Angular2 Service Unit Test Fails with TypeError: undefined is not an object - testing

I am testing my authService. This is the full Test, yet Karma tells me, authService is undefined. I have plenty of Service which AuthService depends upon, but I provided and injected them all properly.
Error: Cannot resolve all parameters for 'AuthService'(BackendService, Store, LoggerService, undefined, ErrorService). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'AuthService' is decorated with Injectable. in /var/folders/zb/tpysrhsx7hbg1dnsn4gwtqq00000gn/T/8715f9a6c29e748f52c8f59e3e1daae3.browserify (line 34976)
authservice.spec.ts
import { provide } from "#angular/core";
import { AuthHttp } from "angular2-jwt";
import { HTTP_PROVIDERS, XHRBackend } from "#angular/http";
import { MockBackend } from "#angular/http/testing";
import {
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
} from "#angular/platform-browser-dynamic/testing";
import {
beforeEachProviders,
inject,
beforeEach,
it,
describe,
setBaseTestProviders
} from "#angular/core/testing";
import { Subject } from "rxjs/Subject";
import { AuthService } from "./auth.service";
import { BackendService } from "../../backend/backend.service";
import { ErrorService } from "../../error/error.service";
import { LoggerService } from "../../logger/logger.service";
import { NavService } from "../../nav/nav-service/nav.service";
import { Store } from "#ngrx/store";
import { TestComponentBuilder } from "#angular/compiler/testing";
import { ToastController, AlertController } from "ionic-angular";
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
describe("AuthService", () => {
let response = new Subject();
let tcb;
let authService;
let navService;
let backendService;
let errorService;
let store;
let loggerService;
class StubErrorService extends ErrorService {
constructor() {
super(null, null);
}
toast(title) {
console.error(title);
}
modal(title, subtitle) {
console.error(title, subtitle);
}
}
class StubBackendService extends BackendService {
}
class StubStore extends Store<any> {
}
class StubLoggerService extends LoggerService {
}
class StubNavService extends NavService {
}
// PROVIDE
beforeEachProviders(() => [
HTTP_PROVIDERS,
provide(AuthHttp, {
useValue: {
get: (url: string) => {
return response;
}
}
}),
AuthService,
TestComponentBuilder,
provide(ToastController, {useClass: null}),
provide(AlertController, {useClass: null}),
provide(ErrorService, {useClass: StubErrorService}),
provide(XHRBackend, {useClass: MockBackend}),
provide(BackendService, {useClass: StubBackendService}),
provide(Store, {useClass: StubStore}),
provide(LoggerService, {useClass: StubLoggerService}),
provide(NavService, {useClass: StubNavService})
]);
// INJECTS
beforeEach(inject([TestComponentBuilder, AuthService, ErrorService, BackendService, Store, LoggerService, NavService], (_tcb, as, es, bs, s, ls, ns) => {
tcb = _tcb;
authService = as;
navService = ns;
errorService = es;
store = s;
backendService = bs;
loggerService = ls;
}));
it("should test authservice", () => {
authService.logout();
});
});

I don't know if its relevant anymore, just to say I had an almost identical issue and I resolved it following the official docs on how to test services. Hope it helps!

Related

NestJS Authentication - Passport strategy, JWT creation problem

I'm following the official NestJS documentation. Currently, I'm trying to implement the authentication step with Passport strategy. I did every step, as the documentation says, but I got stuck where I need to generate the JWT with the jwtService.sign() method.
The error, that I'm getting is:
ERROR [ExceptionsHandler] secretOrPrivateKey must have a value`.
Here are the code snippets:
AuthModule:
#Module({
imports: [
UserModule,
PassportModule,
User,
TypeOrmModule.forFeature([User]),
JwtModule.register({
secret: 'somerandomsecret',
signOptions: { expiresIn: '60s' }
})
],
providers: [AuthService, LocalStrategy, UserService],
exports: [AuthService]
})
export class AuthModule {}
AuthService
#Injectable()
export class AuthService {
constructor(
private userService: UserService,
private jwtService: JwtService
){}
async validateUser(email: string, pass: string): Promise<any> {
const user = await this.userService.findByEmail(email);
const isMatch = await comparePasswords(pass, user.password);
if( user && isMatch) {
const { password, ...result } = user;
return result;
}
return null;
}
async signIn(user: any) {
const payload = { username: user.email, sub: user.id };
return this.jwtService.sign(payload)
}
}
And inside the User controller, I'm calling the method signIn from the AuthService.
UserController
import {
Body,
Controller,
Post,
HttpException,
HttpStatus,
Request,
UseGuards,
Bind,
} from "#nestjs/common";
import { UserService } from "./user.service";
import { SignUpDataValidation } from "./user.validation";
import { hashPassword } from "../../utils/hash-password";
import { AuthGuard } from '#nestjs/passport';
import { AuthService } from '../auth/auth.servers';
import { LocalAuthGuard } from '../auth/local-auth.guard';
#Controller("user")
export class UserController {
constructor(
private userService: UserService,
private authService: AuthService
) {}
#UseGuards(LocalAuthGuard)
#Post("/signin")
#Bind(Request())
async signIn(req) {
return this.authService.signIn(req.user)
}
}
UserModule
import { Module } from "#nestjs/common";
import { UserController } from "./user.controller";
import { UserService } from "./user.service";
import { TypeOrmModule } from "#nestjs/typeorm";
import { User } from "src/modules/user/user.entity";
import { AuthService } from '../auth/auth.servers';
import { JwtService } from '#nestjs/jwt';
#Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService, AuthService, JwtService],
})
export class UserModule {}
LocalStrategy
import { Injectable, UnauthorizedException } from '#nestjs/common';
import { PassportStrategy } from '#nestjs/passport';
import { Strategy } from 'passport-local';
import { AuthService } from './auth.servers';
#Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({usernameField: 'email'});
}
async validate(email: string, password: string): Promise<any> {
const user = await this.authService.validateUser(email,
password);
if(!user) {
throw new UnauthorizedException()
}
return user;
}
}
As you can see, I'm also using Guards, but I'm not going to send you that code to avoid confusion.
So, can anybody tell me, why I'm getting this ERROR? Am I missing something?
Here is the link to the particular NestJS documentation page with a feature that I'm trying to implement: https://docs.nestjs.com/security/authentication

How to call a http post method from a service in a parent director

My http method returns results when it is contained in my component, but does not return any results when called from a service located one directory up.
I've checked the console and there are no errors. I have tried printing to the console, which works from within the service (returns the desired data), but does not when run from within the child component.
This is the service that I'm trying to build:
import { Injectable } from '#angular/core';
import { Resturant } from '../../models/resturant.model'
import { HttpClient } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class GetResturantsService {
fullListresturants: Resturant[];
constructor(private http:HttpClient) { }
fetchList(){
this.http.get('https://lunchlads.firebaseio.com/posts.json')
.pipe(map(responseData =>{
const postsArray: Resturant[] = [];
for (const key in responseData) {
if (responseData.hasOwnProperty(key)){
postsArray.push({ ...responseData[key], id:key })
}
}
return postsArray;
}))
.subscribe(posts => {
// this.fullListresturants = posts;
});
}
}
This is the component which is one file down in the directory:
import { Component, OnInit } from '#angular/core';
import { Resturant } from '../../../models/resturant.model'
import { GetResturantsService } from '../get-resturants.service'
import { HttpClient } from '#angular/common/http';
//import { map } from 'rxjs/operators';
#Component({
selector: 'app-list-all',
templateUrl: './list-all.component.html',
styleUrls: ['./list-all.component.css']
})
export class ListAllComponent implements OnInit {
fullListresturants: Resturant;
constructor(private http:HttpClient, private listAllResturants:GetResturantsService) { }
ngOnInit() {
this.onfullList();
}
onfullList(){
this.fullList();
}
private fullList(){
// this.http.get('https://lunchlads.firebaseio.com/posts.json')
// .pipe(map(responseData =>{
// const postsArray: Resturant[] = [];
// for (const key in responseData) {
// if (responseData.hasOwnProperty(key)){
// postsArray.push({ ...responseData[key], id:key })
// }
// }
// return postsArray;
// }))
// .subscribe(posts => {
// // this.fullListresturants = posts;
// });
this.listAllResturants.fetchList();
}
}
The firebase backend contains roughly 10 records with a name:string, votes:number, and selected:number fields. When run from the component, the html file simply returns the name values with an *ngFor loop.
When run from the service, nothing is returned and no errors are reported in the console.
I suspect the problem lies somewhere in how I am calling the fetchList method from the component, but google and me have not been able to suss out what I'm doing wrong.
Your service should return an observable to make it work. As per your current code, you are not returning anything from GetResturantsService.fetchList(). To make it work let change the service like this:
export class GetResturantsService {
fullListresturants: Resturant[];
constructor(private http:HttpClient) { }
fetchList(){
return this.http.get('https://lunchlads.firebaseio.com/posts.json')
.pipe(map(responseData =>{
const postsArray: Resturant[] = [];
for (const key in responseData) {
if (responseData.hasOwnProperty(key)){
postsArray.push({ ...responseData[key], id:key })
}
}
return postsArray;
}));
}
}
Now in component subscribe to the observable returned from fetchList method like this:
export class ListAllComponent implements OnInit {
fullListresturants: Resturant;
constructor(private http:HttpClient, private listAllResturants:GetResturantsService) { }
ngOnInit() {
this.onfullList();
}
onfullList(){
this.fullList();
}
private fullList(){
this.listAllResturants.fetchList()
.subscribe(posts => {
//DO whatever you want to do with posts
this.fullListresturants = posts;
});
}
}
Hope it helps.

Dependencies not being injected on NestJS with Serverless and AWS

Everyone,
I'm trying to setup my first NestJS application. It is backed by Serverless on AWS.
I created a simple Controller that has a Service as a dependency. When I hit the endpoint with my HTTP Client, the object that should contain the Service instance is undefined. I'm not able to make it work. Could you help?
handler.ts
import { Context, Handler } from 'aws-lambda';
import { NestFactory } from '#nestjs/core';
import { AppModule } from './src/module';
import { Server } from 'http';
import { ExpressAdapter } from '#nestjs/platform-express';
import * as serverless from 'aws-serverless-express';
import * as express from 'express';
import {DB} from './src/libs/db';
let cachedServer: Server;
function bootstrapServer(): Promise<Server> {
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
return NestFactory.create(AppModule, adapter)
.then(app => app.enableCors())
.then(app => app.init())
.then(() => DB.connect())
.then(() => serverless.createServer(expressApp));
}
export const handle: Handler = (event: any, context: Context) => {
if (!cachedServer) {
bootstrapServer().then(server => {
cachedServer = server;
return serverless.proxy(server, event, context);
});
} else {
return serverless.proxy(cachedServer, event, context);
}
};
module.ts
import { Module } from '#nestjs/common';
import { EventController } from './event.controller';
import { EventService } from './event.service';
#Module({
controllers: [EventController],
providers: [EventService],
})
export class AppModule {}
event.service.ts
import { Injectable } from '#nestjs/common';
interface Event{}
#Injectable()
export class EventService {
create(event: Event) {
return {
id: Date.now()
}
}
}
event.controller.ts
import { Controller, Post, Body } from '#nestjs/common';
import { EventService } from './event.service';
interface Event { }
#Controller('event')
export class EventController {
constructor(private readonly eventService: EventService) { }
#Post()
async create(#Body() req)
{
this.eventService.create(req);
}
}
So this.eventService is always undefined. What is wrong with this implementation?
Maybe you are missing a line from tsconfig add this below:
"emitDecoratorMetadata": true
Credits to the God of Nestjs Mr. Kamil's reply:
https://stackoverflow.com/a/50121886/6301493

Angular 5: Solving unresolved dependency in constructor

I'm trying to create a generic HttpService for my Angular 5 project.
The error I am getting:
Uncaught Error: Can't resolve all parameters for HttpService: ([object Object], [object Object], [object Object], ?)
app/util/constants.ts
import { Injectable } from "#angular/core";
#Injectable()
export class SERVER {
readonly ROOT:string = 'http://localhost:8888/';
readonly API_PATH:string = 'api/v1/';
}
#Injectable()
export class API_URLS {
readonly USER:string = 'user/';
}
app/serializers/serializer.ts
import { Resource } from 'app/models/resource';
export interface Serializer {
fromJson(json: any): Resource;
toJson(resource: Resource): any;
}
app/models/resource.ts
export class Resource {
id: number;
}
app/models/user.model.ts
import { Resource } from 'app/models/resource';
export class User extends Resource{
id: number;
name: string;
email: string;
gender: string;
address: string;
landmark: string;
client_id: number;
dealer_id: number;
phone_number: string;
alternate_phone_number: string;
status: string;
is_active: boolean;
date_created: string;
date_updated: string;
}
app/serializers/user.serializer.ts
import { User } from 'app/models/user.model';
import { Serializer } from 'app/serializers/serializer';
export class UserSerializer implements Serializer {
fromJson(json: any): User {
const user = new User();
user.id = json.id;
user.client_id = json.client_id;
user.dealer_id = json.dealer_id;
user.status = json.status;
user.is_active = json.is_active;
user.date_created = json.date_created;
user.date_updated = json.date_updated;
return user;
}
toJson(user: User): any {
return {
id: user.id,
client_id: user.client_id,
dealer_id: user.dealer_id,
status: user.status,
is_active: user.is_active,
date_created: user.date_created,
date_updated: user.date_updated,
};
}
}
app/services/user.service.ts
import { Injectable } from '#angular/core';
import { SERVER } from 'app/util/constants';
import { API_URLS } from 'app/util/constants';
import { User } from 'app/models/user.model';
import { HttpClient } from '#angular/common/http';
import { HttpService } from 'app/services/http.service';
import { UserSerializer } from 'app/serializers/user.serializer';
#Injectable()
export class UserService extends HttpService<User> {
constructor(
server: SERVER,
API_URLS: API_URLS,
httpClient: HttpClient
) {
super(
server,
httpClient,
API_URLS.USER,
new UserSerializer());
}
}
app/app.module.ts
import { Observable } from 'rxjs/Rx';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { CommonModule } from '#angular/common';
import { RouterModule } from '#angular/router';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '#angular/common/http';
import { BrowserModule } from '#angular/platform-browser';
/************** Services *****************/
import { UserService } from './services/user.service';
/************** Components *****************/
import { UserComponent } from './components/user/user.component';
/************** Constant *****************/
import { SERVER } from './util/constants';
import { API_URLS } from './util/constants';
import { OPERATION_TYPES } from './util/constants';
import { REQUEST_METHODS } from './util/constants';
import { Resource } from './models/resource';
#NgModule({
declarations: [
AppComponent,
UserComponent,
],
imports: [
CommonModule,
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [
SERVER,
API_URLS,
OPERATION_TYPES,
REQUEST_METHODS,
Resource,
UserService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Edit: Added missing code
app/services/http.service.ts
import { Observable } from 'rxjs/Rx';
import { Resource } from 'app/models/resource';
import { Serializer } from 'app/serializers/serializer';
import { SERVER } from 'app/util/constants';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class HttpService<T extends Resource> {
constructor(
private SERVER: SERVER,
private httpClient: HttpClient,
private API_URL: string,
private serializer: Serializer) { }
/*
* Get single record by id
*/
read(id: number): Observable<T> {
return this.httpClient.get<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${id}`).map(data => this.serializer.fromJson(data) as T);
}
/*
* Get all records by page
*/
readRecords(): Observable<T[]>{
return this.httpClient.get<T[]>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}`).map((data: any) => this.convertData(data.items) as T[]);
}
/*
* Create new record
*/
create(record: T): Observable<T>{
return this.httpClient.post<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}`, record).map(data => this.serializer.fromJson(data) as T);
}
/*
* Update record
*/
update(record: T): Observable<T>{
return this.httpClient.put<T>(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${record.id}`, record).map(data => this.serializer.fromJson(data) as T);
}
/*
* Remove record
*/
remove(id: number) {
return this.httpClient.delete(`${this.SERVER.ROOT}/${this.SERVER.API_PATH}/${this.API_URL}/${id}`);
}
private convertData(data: any): T[] {
return data.map(item => this.serializer.fromJson(item));
}
}
What am I missing?
I solved this by making the Serializer abstract class and making serializers injectable.
import { Injectable } from '#angular/core';
import { Resource } from 'app/models/resource';
#Injectable()
export abstract class Serializer {
abstract fromJson(json: any): Resource;
abstract toJson(resource: Resource): any;
}
And
import { Injectable } from '#angular/core';
import { User } from 'app/models/user.model';
import { Serializer } from 'app/serializers/serializer';
#Injectable()
export class UserSerializer implements Serializer {
fromJson(json: any): User {
const user = new User();
user.id = json.id;
user.client_id = json.client_id;
user.dealer_id = json.dealer_id;
user.status = json.status;
user.is_active = json.is_active;
user.date_created = json.date_created;
user.date_updated = json.date_updated;
return user;
}
toJson(user: User): any {
return {
id: user.id,
client_id: user.client_id,
dealer_id: user.dealer_id,
status: user.status,
is_active: user.is_active,
date_created: user.date_created,
date_updated: user.date_updated,
};
}
}

Pass data to not-yet-loaded view in Aurelia

I am navigating from one view (call it bestSellersView) to another (BookDetailsView). There are multiple different 'parent' views that can navigate to 'Book Details' and they all need to pass the book that is to be viewed to the next view. I don't want to inject the source view to the details view as some threads suggest since my constructor would grow with each new view that uses the details sub-view.
I am trying to use the event aggregator, however due to the life cycle of things I am always getting a blank details screen on the first time I navigate. When I first navigate to the 'book details' view the ViewDetailsMessage has not yet been subscribed to before the publisher (best sellers) sends the message. Since I have my viewmodel set to singleton, the subsequent clicks work fine (since the details view is already constructed and subscribed to the event).
How can I get around this chicken-egg problem in Aurelia?
Edit 01
Here is what I was doing when I was having a problem:
Master.ts:
import { JsonServiceClient } from "servicestack-client";
import {
ListPendingHoldingsFiles,
ListPendingHoldingsFilesResponse,
SendHoldings,
PositionFileInfo
} from "../holdingsManager.dtos";
import { inject, singleton } from "aurelia-framework";
import { Router } from "aurelia-router";
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
#singleton()
#inject(Router, EventAggregator)
export class Pending {
router: Router;
positions: PositionFileInfo[];
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.client = new JsonServiceClient('/');
var req = new ListPendingHoldingsFiles();
this.client.get(req).then((getHoldingsResponse) => {
this.positions = getHoldingsResponse.PositionFiles;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
openHoldings(positionInfo) {
this.eventAgg.publish(new GetPendingPositionMessage(positionInfo));
this.router.navigate('#/holdings');
}
}
Child.ts:
import { JsonServiceClient } from "servicestack-client";
import { inject, singleton } from "aurelia-framework";
import { Router } from 'aurelia-router';
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
import {
GetPendingHoldingsFile,
GetPendingHoldingsFileResponse,
Position,
PositionFileInfo
} from "../holdingsManager.dtos";
#singleton()
#inject(Router, EventAggregator)
export class Holdings {
router: Router;
pendingPositionFileInfo: PositionFileInfo;
position: Position;
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.eventAgg.subscribe(GetPendingPositionMessage,
message => {
this.pendingPositionFileInfo = message.fileInfo;
});
}
activate(params, routeData) {
this.client = new JsonServiceClient('/');
var req = new GetPendingHoldingsFile();
req.PositionToRetrieve = this.pendingPositionFileInfo;
this.client.get(req).then((getHoldingsResponse) => {
this.position = getHoldingsResponse.PendingPosition;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
}
Here is what I am doing now:
master.ts
import { JsonServiceClient } from "servicestack-client";
import {
ListPendingHoldingsFiles,
ListPendingHoldingsFilesResponse,
PositionFileInfo
} from "../holdingsManager.dtos";
import { inject, singleton } from "aurelia-framework";
import { Router } from "aurelia-router";
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
import { SetPendingPositionMessage } from "../common/SetPendingPositionMessage";
#singleton()
#inject(Router, EventAggregator)
export class Pending {
router: Router;
eventAgg: EventAggregator;
positions: PositionFileInfo[];
client: JsonServiceClient;
fileInfo: PositionFileInfo;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.eventAgg.subscribe(GetPendingPositionMessage, () => {
this.eventAgg.publish(new SetPendingPositionMessage(this.fileInfo));
});
}
activate(params, routeData) {
this.client = new JsonServiceClient('/');
var req = new ListPendingHoldingsFiles();
this.client.post(req).then((getHoldingsResponse) => {
this.positions = getHoldingsResponse.PositionFiles;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
openHoldings(positionInfo) {
this.fileInfo = positionInfo;
this.router.navigate('#/holdings');
}
}
child.ts
import { JsonServiceClient } from "servicestack-client";
import { inject, singleton } from "aurelia-framework";
import { Router } from 'aurelia-router';
import {
GetPendingHoldingsFile,
GetPendingHoldingsFileResponse,
Position,
SendHoldings,
PositionFileInfo
} from "../holdingsManager.dtos";
import { EventAggregator } from "aurelia-event-aggregator";
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage";
import { SetPendingPositionMessage } from "../common/SetPendingPositionMessage";
import { GetDeliveredPositionMessage } from "../common/GetDeliveredPositionMessage";
import { SetDeliveredPositionMessage } from "../common/SetDeliveredPositionMessage";
#singleton()
#inject(Router, EventAggregator)
export class Holdings {
router: Router;
pendingPositionFileInfo: PositionFileInfo;
position: Position;
client: JsonServiceClient;
eventAgg: EventAggregator;
constructor(router, eventAggregator) {
this.router = router;
this.eventAgg = eventAggregator;
this.eventAgg.subscribe(SetPendingPositionMessage, message => this.getPositionData(message.fileInfo));
this.eventAgg.subscribe(SetDeliveredPositionMessage, message => this.getPositionData(message.fileInfo));
}
getPositionData(fileInfo) {
this.position = null;
this.client = new JsonServiceClient('/');
var req = new GetPendingHoldingsFile();
req.PositionToRetrieve = fileInfo;
this.client.post(req).then((getHoldingsResponse) => {
this.position = getHoldingsResponse.PendingPosition;
}).catch(e => {
console.log(e); // "oh, no!"
});
}
activate(params) {
this.eventAgg.publish(new GetPendingPositionMessage());
this.eventAgg.publish(new GetDeliveredPositionMessage());
}
sendHoldings() {
var req = new SendHoldings();
this.client.get(req).then((sendHoldingsRepsonse) => {
console.log("SUCCESS!"); // "oh, no!"
}).catch(e => {
console.log(e); // "oh, no!"
});
}
}
I need to add a bit of logic to the activate method of the child to ensure I ask for the right parents holdings file.
Sounds like you need to share state between views. I use a StateStore class that is injected into any views that wish to share state. By default all objects injected are Singletons making it easy to share state. A very simple example could be (in TypeScript):
statestore.ts
export class StateStore {
state: any;
}
masterview.ts
autoinject()
export class MasterView {
constructor(private store: StateStore){
}
doSomething(): void {
this.store.state = "some value";
// navigate to detail view
}
}
detailview.ts
autoinject()
export class DetailView {
sharedValue: any;
constructor(store: StateStore) {
this.sharedValue = store.state;
}
}
This will share a single instance of StateStore between views allowing state to easily be shared.
My current solution, though not as pretty as I'd like it to be is as follows:
Source view (bestSellersView) is a singleton and subscribes to "GetCurrentBookMessage". When a user selects a book, the Source saves it locally and navigates to the "BookDetailsView". The BookDetailsView is constructed, subscribes to a "SetCurrentBookMessage" and, when activated, it sends a GetCurrentBookMessage. The source view answers with a "SetCurrentBookMessage".
This will get messy with multiple sources and I will have to have some way to resolve where the navigation came from to pick the 'right' source, but for today this works.
Edit 01
I have also tried getting rid of all the event aggregator stuff and putting this in the master's OpenHoldings method:
let routeConfig = this.router.routes.find(x => x.name === 'holdings');
this.fileInfo = positionInfo;
routeConfig.settings = {
fileInfo: positionInfo
};
this.router.navigateToRoute('holdings');
And then putting this in the child's activate method:
activate(urlParams, routeMap, navInstr) {
this.getPositionData(routeMap.settings.fileInfo);
}
But the settings did not persist after the navigation was executed.