I'm trying to use the surveyService in the voteOptionRepository, but when I use the route, the console return this: TypeError: this.surveyService.getSurveyById is not a function
This is my SurveyModule
#Module({
imports: [
TypeOrmModule.forFeature([SurveyRepository]),
AuthModule
],
controllers: [SurveyController],
providers: [SurveyService],
exports: [SurveyService]
})
export class SurveyModule{}
This is my voteOptionModule
#Module({
imports: [
TypeOrmModule.forFeature([VoteOptionRepository]),
AuthModule,
SurveyModule
],
controllers: [VoteOptionController],
providers: [VoteOptionService]
})
export class VoteOptionModule{}
And this is how I'm trying to use the service
#EntityRepository(VoteOption)
export class VoteOptionRepository extends Repository<VoteOption>{
constructor(private surveyService: SurveyService){
super();
}
async createVoteOption(createVoteOptionDTO: CreateVoteOptionDTO, surveyId: number, user: User){
const survey = await this.surveyService.getSurveyById(surveyId, user)
const { voteOptionName, image } = createVoteOptionDTO;
const voteOption = new VoteOption();
voteOption.voteOptionName = voteOptionName;
voteOption.image = image;
voteOption.survey = survey;
try{
await voteOption.save()
this.surveyService.updateSurveyVoteOptions(voteOption, surveyId, user)
} catch(error){
throw new InternalServerErrorException();
}
delete voteOption.survey;
return voteOption;
}
}
TypeORM repository classes do not adhere to Nest's Dependency Injection System, due to being tied TypeORM. Repository classes are actually supposed to have connections and entity managers passed to them in the constructor to allow for communication with the database. If you need logic from other services, you should generally be calling those other services from inside the service call, not the repository.
I'm new to NestJS, but I believe this is what you want to do. You need to inject the reference to your table in your service.
export class VoteOptionRepository extends Repository<VoteOption>{
constructor(
private surveyService: SurveyService
#InjectRepository
surveyServiceRepo(SurveyRepository)
){
super();
}
async getSurveyById () {
const survey = await this.surveyServiceRepo.find({id: 'survey-id'})
return survey
}
}
Without seeing your SurveyService though, it may be that getSurveyById has not been defined properly, which is why your getting an error that it's not a function.
Related
This is a Node app with OIDC login. I want to store the JWT in the cookie.
I'm using version 12 of the library 'angular-auth-oidc-client'. I can't use a later version of this library.
The documentation says to set up your app.module.ts like this:
imports: [
/*...*/,
AuthModule.forRoot({
config: {
authority: ...,
redirectUrl: ...,
/*...*/,
storage: new MyCustomStorage()
}
})
So it uses that 'storage' parameter.
This works correctly if I use, for instance, localStorage in my new MyCustomStorage. But I want to use the cookie.
So, if I for instance make my MyCustomStorage like this:
import { CookieService } from 'ngx-cookie-service';
#Injectable({
providedIn: 'root',
})
export class MyCustomStorage implements AbstractSecurityStorage {
constructor(private cookieService: CookieService) {
}
remove(key: string): void {
throw new Error('Method not implemented.');
}
clear(): void {
throw new Error('Method not implemented.');
}
read(key: string) {
let item = this.cookieService.get(key);
if (!!item) {
return JSON.parse(item);
}
else {
return null;
}
}
write(key: string, value: any) {
value = value || null;
//Expiration time can be set in the third parameter of below function.
this.cookieService.set(`${key}`, JSON.stringify(value), undefined, undefined, undefined, true, 'Strict');
return true;
}
}
I believe this would work... however I now get an error in my app.module.ts, because now creating a new MyCustomStorage() requires a CookieService parameter to be injected.
But that CookieService is automatically injected into the MyCustomStorage usually...
Do I need to manually instantiate a new CookieService in the "storage: new MyCustomStorage()" line? If so, it asks for parameters for DOCUMENT and PLATFORM_ID and REQUEST. Do I have to instantiate those as well? If yes... how do I create a new document and platform id for this new CookieService()?
When you know the list of queues to be registered, you can add them using registerQueue() in nestjs module instantiation but how to dynamically register a queue, for eg. if I have a multi tenant architecture, when a new tenant is created I want to register a new queue dynamically, is it possible to do with nest js bull queue ?
I don't know if you can do that with the Nest package. Check this GitHub issue response from the Nestjs's creator.
You can, however, use the vanilla Bull package.
For example, imagine that you have a Controller like this:
#Controller()
export class AppController {
constructor(
private queuesManager: QueuesManagerService
) {}
#Post(['generate-queue'])
generateQueue(
#Body() generateQueueDto: GenerateQueueDto
): Promise<GenerateQueueResponse> {
return this.queuesManager.generateQueue(generateQueueDto.name);
}
#Get(['get-all-jobs'])
getAllJobsFromQueue(
#Query() queryParameters: GetAllJobsEndpointQueryParameters
): Promise<Bull.Job[]> {
return this.queuesManager.getAllJobsFromQueue(queryParameters.name);
}
}
And the QueuesManagerService looks like this:
#Injectable()
export class QueuesManagerService {
async generateQueue(name: string): Promise<GenerateQueueResponse> {
const queue: Bull.Queue = new Bull(name);
await queue.add({ test: 'test' });
return {
status: 200,
message: `Queue with name ${name} generated successfully!`,
};
}
async getAllJobsFromQueue(name: string): Promise<Bull.Job[]> {
const jobStatuses: Bull.JobStatus[] = [
'waiting',
'delayed',
'active',
'completed',
'failed',
];
const queue: Bull.Queue = new Bull(name);
const jobs: Bull.Job[] = await queue.getJobs(jobStatuses);
return jobs;
}
}
You could interact with the server using curl:
$ curl -X POST -d 'name=myFirstQueue' localhost:3333/api/generate-queue
# response
{"status":200,"message":"Queue with name myFirstQueue generated successfully!"}
###
$ curl localhost:3333/api/get-all-jobs?name=myFirstQueue
# response
[{"id":"1","name":"__default__","data":{"test":"test"},"opts":{"attempts":1,"delay":0,"timestamp":1639085434398},"progress":0,"delay":0,"timestamp":1639085434398,"attemptsMade":0,"stacktrace":[],"returnvalue":null,"finishedOn":null,"processedOn":null}]
PS1:
Bull's Github
queue.getJobs() reference
PS2:
My Classes and Interfaces:
export class GetAllJobsEndpointQueryParameters {
#IsNotEmpty()
name!: string;
}
export class GenerateQueueDto {
#IsNotEmpty()
name!: string;
}
export interface GenerateQueueResponse {
status: number;
message: string;
}
As per the single-spa official doc, we can share the application's UI state by using RxJs.
Observables / Subjects (RxJs) - one microfrontend emits new values to
a stream that can be consumed by any other microfrontend. It exports
the observable to all microfrontends from its in-browser module, so
that others may import it.
Link: https://single-spa.js.org/docs/recommended-setup/#ui-state
Link: https://single-spa.js.org/docs/faq/#how-can-i-share-application-state-between-applications
I was trying to create an example in React, where I am using single-spa parcel to include my micro-apps in root application. I was trying to share the UI state using RxJs.
When I googled it for single-spa RxJs, I didn't find anything. Can anyone provide me a basic example where I will be able to share UI state for below use cases:
Sharing the UI state from root app to my micro-apps.
Sharing the UI state from micro-apps to root apps.
Sharing the UI state between micro-apps.
Here is a high level overview on how to approach this:
add rxjs as a shared dependency in your import map
"rxjs": 'https://unpkg.com/#esm-bundle/rxjs/system/rxjs.min.js,
"rxjs/operators": 'https://unpkg.com/#esm-bundle/rxjs/system/rxjs-operators.min.js,
consider pinning these to a specific version!
create a utility module (create-single-spa makes this easy!) that sets up and exports the observable with data that you need
include this utility module in importmap too
import and subscribe to observable from the utility module in the apps that need it
don't forget to unsubscribe when your apps unmount.
celebrate 🎉
I have created single-spa-example-rxjs-shared-state as an example repo that shows how to use an Rxjs utility module with cross-frontend imports.
This does the trick
In root html js file add the following
Import { Subject, Subscription } from 'https://dev.jspm.io/rxjs#6/_esm2015';
import { filter, map } from 'https://dev.jspm.io/rxjs#6/_esm2015/operators';
export class EventBusService {
constructor() {this.subject$ = new Subject(); }
emit(event) {
this.subject$.next(event);
}
on(eventName, action) {
return this.subject$.pipe(
filter( (e) => e.name === eventName),
map( (e) => e["data"])).subscribe(action);
}
}
var EventBus= new EventBusService()`enter code here`;
System.import('single-spa').then(function (singleSpa) {
singleSpa.registerApplication(
'app1',
function () {
return System.import('app1');
},
function (location) {
return true;
// return location.pathname.startsWith('/app1');
},
{ EventBus: EventBus }
);
singleSpa.registerApplication(
'app2',
function () {
return System.import('app2');
},
function (location) {
return true
// return location.pathname.startsWith('/app2');
},
{ EventBus: EventBus }
)
singleSpa.start();
})
In component
import { Component,OnInit ,ChangeDetectorRef} from '#angular/core';
import { assetUrl } from 'src/single-spa/asset-url';
import { singleSpaPropsSubject, SingleSpaProps } from 'src/single-spa/single-spa-props';
import { Subscription } from 'rxjs';
#Component({
selector: 'app1-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
singleSpaProps: SingleSpaProps;
subscription: Subscription;
title = 'app1';
yoshiUrl = assetUrl("yoshi.png");
msgFromMicro="";
titleToPass="";
constructor(private ChangeDetectorRef:ChangeDetectorRef){
}
ngOnInit(): void {
this.subscription = singleSpaPropsSubject.subscribe(
props => {
this.singleSpaProps = props;
console.log(props);
this.lookForEvents();
}
);
}
lookForEvents(){
this.singleSpaProps['EventBus'].on('msgFrmMicro2',(data)=>{
this.msgFromMicro=data;
this.ChangeDetectorRef.detectChanges();
});
}
sendMsg(){
// alert(this.titleToPass);
debugger;
this.singleSpaProps['EventBus'].emit({name:'msgFrmMicro1',data:this.titleToPass});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
Take look at the following repo, handled the same scenario by passing observable ref to micro apps through customprops of single spa
https://github.com/SENTHILnew/micro_spa_intercom
I am trying to use events in my nestjs app.
However when I attempt to trigger command, I get CommandHandlerNotFoundException.
I have message-bus.module:
#Module({
imports: [CqrsModule],
providers: [
MessageBusLocalService,
StartWorkflowHandler
],
exports: [MessageBusLocalService]
})
export class MessageBusModule {
}
message-bus-local.service
#Injectable()
export class MessageBusLocalService {
constructor(private readonly commandBus: CommandBus, private eb: EventBus) {
}
startWorkflow(workflowId: string, payload: any) {
return this.commandBus.execute(
new StartWorkflowCommand(workflowId, payload)
);
}
}
and start-workflow.handler
#CommandHandler(StartWorkflowCommand)
export class StartWorkflowHandler implements ICommandHandler<StartWorkflowCommand> {
constructor() {}
async execute(command: StartWorkflowCommand) {
console.log('Workflow started', command.jobId);
return true;
}
}
I am trying to trigger command when app is bootstrapped:
const app = await NestFactory.create(ApplicationModule);
const service = app.get(MessageBusLocalService);
try {
const c = await service.startWorkflow('abcde', {just: "test"});
console.log('And returned', c);
} catch (e) {
console.error(e)
}
and... I get the CommandHandlerNotFoundException there although I believe it is declared... What did I do wrong?
Thanks in advance.
Since you want to use the handler in another module (e.g. appModule ) you need to add the #Injectable() decorator to the StartWorkflowHandler class.
And call app.init() in the main.ts. Before starting the application.
Your MessageBusModule does not re-export handlers, thus they are not "visible" on app.module level (at least this is what I understand on my own)
I got similar scenario like that:
const commands = [NewOrder, ChargeForOrder]
const events = [ChargeOrder, OrderProcessed]
const sagas = [AdjustWalletFunds]
#Module({
imports: [
CqrsModule,
WalletsModule,
TypeOrmModule.forFeature([...]),
],
providers: [...commands, ...events, ...sagas],
exports: [CqrsModule, ...commands, ...events, ...sagas],
})
export class RxModule {}
so, assuming you import your MessageBusModule in the main app.module, try the following:
#Module({
imports: [CqrsModule],
providers: [
MessageBusLocalService,
StartWorkflowHandler
],
exports: [MessageBusLocalService, StartWorkflowHandler]
})
export class MessageBusModule {
}
As it turns out, the method I used in the question does not work.
However it does work as expected if I inject the MessageBusLocalService in controller.
It seems odd to answer my own question but it might help someone eventually.
Ensure you imported have CqrsModule imported. Also import the MessageBusModule into any other module where it is called from.
I just want to show the name of the current logged in user, but I cant make it works.
I wrote this on the app.component:
import { Component } from '#angular/core';
import template from './app.component.html';
import {ROUTER_DIRECTIVES} from '#angular/router';
import {LoginButtons} from 'angular2-meteor-accounts-ui';
//import our Carousel Component
import {CSSCarouselComponent} from './imports/componenets/carousel/carousel.component';
import { InjectUser } from 'angular2-meteor-accounts-ui';
#Component({
selector: 'app',
template,
directives: [ROUTER_DIRECTIVES, LoginButtons,CSSCarouselComponent]
})
#InjectUser('user')
export class AppComponent {
user: Meteor.User;
constructor() {
console.log(this.user);
}
loginFacebook(event) {
Meteor.loginWithFacebook({}, function(err){
if (err) {
throw new Meteor.Error("Facebook login failed");
}
console.log(Meteor.user().profile.name;);
});
}
}
console.log(this.user); returns undefined.
console.log(Meteor.user().profile.name;); works and gives me the name, but I have no success to export it to the html and show that.
You have to reference Meteor in your Component, for example as let M = Meteor;. Then you can use {{M.user().profile.name}} in your html.
Also this.user is never set in your code, you just define its class. Anyway, you should always use Meteor.user() or M.user(), because it's always up-to-date.