anguar2 nativescript error "TypeError: undefined is not an object (evaluating 'this.router')" - angular2-routing

I am new to Angular2 Native script Programming... i need to navigate one page to another. i am stuck with the typeError:"undefined is not an object (evaluating 'this.router')" plz help me out..
my code is given..
//page1.ts
public constructor(private router: Router) { }
getMyDrawing(args) {
let pad = this.DrawingPad.nativeElement;
let img: Image = this.signImage.nativeElement;
let drawingImage;
pad.getDrawing().then
(
(data) => {
console.log(data);
drawingImage = data;
img.src=data;
this.router.navigate(['page2']);
}
);
}
//routing.ts
import { DrawingPadExample } from "./app.component";
import { Page2Component } from "./app.page2";
export const routes = [
{ path: "drawing-pad-example", component: DrawingPadExample},
{ path: "page2", component: Page2Component }
];
export const navigatableComponents = [
DrawingPadExample,
Page2Component
];
//module.ts
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { NativeScriptModule } from "nativescript-
angular/nativescript.module";
import { DrawingPadExample } from "./app.component";
import { routes, navigatableComponents } from "./app.routing";
import { NativeScriptRouterModule } from "nativescript-
angular/router";
#NgModule({
bootstrap: [
DrawingPadExample
],
imports: [
NativeScriptModule,
NativeScriptRouterModule,
NativeScriptRouterModule.forRoot(routes)
],
declarations: [
DrawingPadExample,
...navigatableComponents
],
schemas: [
NO_ERRORS_SCHEMA
]
})
export class AppModule { }

When you say navigation is not working, do you nothing at all happens and no errors are generated?
I would advice you try putting the callback within a zoneCallback.
public constructor(private ngZone: NgZone, private router: Router){
}
public getMyDrawing(args) {
let pad = this.DrawingPad.nativeElement;
let img: Image = this.signImage.nativeElement;
let drawingImage;
pad.getDrawing().then((data) => {
this.ngZone.run(() => {
console.log(data);
drawingImage = data;
img.src=data;
this.router.navigate(['page2']);
});
});
}

Add instance in constructor for router.
constructor(private router : Router){}
because as error stated typeError:"undefined is not an object (evaluating 'this.router')" you are trying to access
this.router which is not initilized yet

#JBR, No, I mean dependency injection using constructor, for example,
constructor(private router: Router) {}
add that line to you page1 component.
Update
replace this
function(data) {
console.log(data);
drawingImage = data;
img.src=data;
this.router.navigate(['page2']);
}
with arrow function
(data) => {
console.log(data);
drawingImage = data;
img.src=data;
this.router.navigate(['page2']);
}

I got this bug when I was passing a function between two components.
In the first component, I imported Router, but in the second I didn't. Make sure that you import all necessary libraries when you are using callback functions.

Related

Angular Component Expects 2 Arguments

I'm attempting to create a Wordpress theme compatible with 4.8.x that will render single posts and list of posts as per [this tutorial]:1
When I run the test script, I receive the following errors:
ERROR in C:/MyTheme/src/app/posts/post-list/post-list.component.spec.ts
(9,25): Expected 2 arguments, but got 0.
ERROR in C:/MyTheme/src/app/posts/post-single/post-single.component.spec.ts
(8,25): Expected 2 arguments, but got 0.
The code for both components is very similar and calls into the PostsService which is defined as:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Post } from './post';
import { environment} from '../../environments/environment';
import {Observable} from 'rxjs/Observable';
#Injectable()
export class PostsService {
private _wpBase = environment.wpBase;
constructor(private http: HttpClient) { }
getPosts():Observable<Post[]> {
return this.http.get<Post[]>(this._wpBase + 'posts');
}
getPost(slug: string): Observable<Post[]> {
return this.http.get<Post[]>(this._wpBase + 'posts?slug=${slug}');
}
}
My post-list-component includes the following:
import { Component, OnInit } from '#angular/core';
import { Post } from '../post';
import { PostsService} from '../posts.service';
import { HttpErrorResponse } from '#angular/common/http';
import {Router} from '#angular/router';
#Component({
selector: 'app-post-list',
templateUrl: './post-list.component.html',
styleUrls: ['./post-list.component.css'],
providers: [PostsService]
})
export class PostListComponent implements OnInit {
posts: Post[];
constructor( private postsService: PostsService, private router: Router ){}
ngOnInit() {
this.postsService.getPosts().subscribe(
(posts: Post[]) => this.posts = posts,
(err: HttpErrorResponse) => err.error instanceof Error ?
console.log('An error has occurred:',
err.error.message):console.log('Backend returned code $(err.status),
body was: ${err.error}'));
}
selectPost(slug) {
this.router.navigate([slug]);
}
}
The error is thrown in the following post.list.component.spec.ts:
/* tslint:disable:no-unused-variable */
import { TestBed, async } from '#angular/core/testing';
import { PostListComponent } from './post-list.component';
import {Router} from "#angular/router";
describe('Component: PostList', () => {
it('should create an instance', () => {
let component = new PostListComponent();
expect(component).toBeTruthy();
});
});
I am not sure how to resolve the errors. It seems to me that PostLisComponent() needs to be passed 2 arguments as per the error, but it's not clear what arguments should be passed. Can anyone assist me in better understanding how to resolve the errors?
its because the constructor use TestBed
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { PostListComponent } from './post-list.component';
describe('PostListComponent ', () => {
let component: PostListComponent ;
let fixture: ComponentFixture<PostListComponent >;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ PostListComponent ]
})
.compileComponents();}));
beforeEach(() => {
fixture = TestBed.createComponent(PostListComponent );
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create an instance', () => {
expect(component).toBeTruthy();
});
});
From Angular's Testing Guide in regards to the TestBed, and why it would fit such a scenario:
TestBed is the first and most important of the Angular testing
utilities ... In effect, you detach the tested component from its own
application module and re-attach it to a dynamically-constructed
Angular test module tailored specifically for this battery of tests.
Right now, you're statically constructing instead of dynamically constructing using the TestBed, which is causing the error since the constructor of the PostListComponent contains two parameters which would be required to be filled in case of static constructing.

subscribe to HTTP-service to pass an object to a form in a child component with Angular 4 Router with Observable

I apologize if this question seems to be a double, but I have searched the resource up and down and upon reading many threads and the Angular.io tutorial, I still cannot figure out how exactly to achieve my goal, although I have a pretty good understanding of the possibilities now.
My parent component (which is nothing more but a header + ) an object with an HTTP-service, which I would like to subscribe to from a child-component, in order the form in the child component gets pre-filled with object data.
Here is my code:
(ProjectsService)
#Injectable()
export class ProjectsService {
private projectsUrl = environment.apiurl + 'projects';
constructor(private http: Http) { }
private extractData(res:Response) {
let body = res.json();
return body || [];
}
getProjects(): Observable<Project[]> {
return this.http.get(this.projectsUrl)
.map(response => response.json() as Project[])
.catch(this.handleError);
}
getProject(id: String): Observable<Project> {
const url = `${this.projectsUrl}/${id}`;
return this.http.get(url)
.map(response => response.json() as Project)
.catch(this.handleError);
}
parent (ProjectComponent)
export class ProjectComponent implements OnInit {
project: Project;
constructor(
private projectsService: ProjectsService,
private route: ActivatedRoute,
) {}
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => {
return this.projectsService.getProject(params.id);
}).
subscribe(project => this.project = project);
}
}
(routing module)
{ path: '', redirectTo: 'projects', pathMatch: 'full' },
{
path: 'project/:id',
component: ProjectComponent,
children: [
{
path: '',
redirectTo: 'settings', pathMatch: 'full'
},
{
path: 'settings',
component: SettingsComponent
},
child (SettingsComponent):
export class SettingsComponent {
#Input() project: Project;
constructor(
private route: ActivatedRoute,
private projectsService: ProjectsService
) { }
ngOnInit(): void {
***I think it's here that I need a subscription to the HTTP-service but I cannot figure out how to ****
this.project = {
(...some porject properties to fill the data in the form)
}
}
}
Many thanks in advance for a reply.
I have solved my issue by subscribing to the HTTP-service from within the child component but using this.route.parent.params instead of this.route.params

Angular2 - unable to retrieve data from API

I am currently building an Angular2 application accessing an MVC web API i have built. However, it does not seem to retrieve any data. I am obviously missing something but i am not sure what.
I know that the URL i am using works along with the headers as i am able to retrieve the data correctly through fiddler.
My repack.service.ts is as follows:
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { RepackIndex } from './RepackIndex';
#Injectable()
export class RepackService{
private baseUrl = 'https://localhost:44321/api/Repack/All';
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) { }
getAllRepacks(): Promise<RepackIndex[]>{
var data = this.http.get(this.baseUrl)
.toPromise()
.then(response => response.json().data as RepackIndex[])
.catch(this.handleError);
return data;
}
private handleError(error: any): Promise<any>{
console.error("An error occured in repack.service", error);
return Promise.reject(error.message || error);
}
}
And this is my component:
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { RepackIndex } from './repackIndex';
import { RepackService } from './repack.service';
#Component({
selector: 'index',
templateUrl: 'app/index.component.html',
providers: [RepackService]
})
export class IndexComponent implements OnInit{
repacks: RepackIndex[];
selectedRepack: RepackIndex;
constructor(private router: Router, private repackService: RepackService) { }
onSelect(repack: RepackIndex): void{
this.selectedRepack = repack;
}
getRepacks(): void{
this.repackService.getAllRepacks().then(repacks => this.repacks = repacks);
}
ngOnInit(): void{
this.getRepacks();
}
}
I have tried putting in a breakpoint and adding a console.log line but no data is returned to the component.
I am fairly new to Angular2 so any help would be greatly appreciated.
Thanks,
Right I have managed to get it to work by using an observable rather than a promise.
My service method now looks like this:
public GetAll = (): Observable<RepackIndex[]> => {
return this.http.get(this.baseUrl)
.map((response: Response) => <RepackIndex[]>response.json())
.catch(this.handleError);
}
And my Component call now looks like this:
getRepacks(): void{
this.repackService.GetAll()
.subscribe((data:RepackIndex[]) => this.repacks = data,
error => console.log(error),
() => console.log('Get All repacks complete'));
}
I found the answer here
Hope this helps someone else

Cache data but check in the background for new data

I want to cache my data, but at the same time I need my data to be up-to-date. I found this: Angular2 easiest way to cache HTTP responses but this will not check for new data.
I have this now in my service:
public publishedSessions: Session[] = null;
getPublishedSessions(): Observable<any> {
let headers = new Headers();
headers.append('authorization', this.userService.getToken());
if (this.publishedSessions) {
this.http.get(this.apiUrl + 'api/sessions/published', {
headers: headers
})
.map(res => res.json().sessions)
.subscribe(sessions => this.publishedSessions = sessions);
return Observable.of(this.publishedSessions);
} else {
return this.http.get(this.apiUrl + 'api/sessions/published', {
headers: headers
})
.do(res => this.publishedSessions = res.json().sessions)
.map(res => res.json().sessions)
.catch((error) => Observable.of(error));
}
}
And some standard code in my component:
handlePublishedSessions(): void {
this.subscriptionArr.push(this.sessionService.getPublishedSessions().subscribe(sessions => {
this.session = sessions
}));
}
This causes the effect that when I first navigate (visit 1) to the page, a call (call 1) will be made (wanted). Then if I navigate away and return back to the page (visit 2), the data from call 1 will be returned (not wanted), in the meantime, call 2 is in the works. So if I then navigate away again and navigate back (visit 3), the data from call 2 is being returned.
I want that the call 1 data is displayed on visit 2 for the first few milliseconds (untill call 2 is done). When call 2 is done I want the data to be replaced (without user interaction).
I would use a BehaviorSubject to cache data.
Take a look at this plunker to get an idea: https://plnkr.co/edit/jNNQJToYia2MhIE488YX?p=preview
import {Component, NgModule, Injectable} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import {HttpModule, Http} from '#angular/http';
import {BehaviorSubject} from 'rxjs/Rx';
#Injectable()
export class AnyService {
public data = new BehaviorSubject<string>();
constructor(private _http: Http) { }
public getData(): string {
this._http.get('https://httpbin.org/bytes/12')
.subscribe(
resp => this.data.next(resp._body)
);
return this.data.value;
}
}
#Component({
selector: 'my-app',
template: `
<div>
<h2 (click)="getData()">Hello {{name}} -- CLICK ME !! --</h2>
</div>
`,
})
export class App {
name:string;
firstSubscribeCallback = false;
constructor(private _srvc: AnyService) {
this.name = 'Angular2'
this._srvc.data.subscribe(
newData => {
// FIRST CALL WILL BE THE CACHED DATA..
if (!this.firstSubscribeCallback) { // JUST FOR DEMO ..
console.log('got cached data # startup..');
this.firstSubscribeCallback = true;
}
else console.log('got new data:');
console.log(newData);
}
);
this.getData(); // get FRESH data ..
}
getData() {
console.log('getting cached data:');
console.log(this._srvc.getData());
}
}
#NgModule({
imports: [ BrowserModule, HttpModule ],
declarations: [ App ],
providers: [ AnyService ],
bootstrap: [ App ]
})
export class AppModule {}

Test Angular2 service with mock backend

First: I'm aware that Angular2 is in alpha and changing frequently.
I'm working with Angular2. There is an injectable service with http dependency that I'd like to test using a mock backend. The service works when the app starts but I'm having no luck writing the test and getting the mock backend to respond. Any insight, is there something obvious in the test setup or implementation that I'm missing?
service/core.ts:
import { Injectable } from 'angular2/angular2';
import { Http } from 'angular2/http';
#Injectable()
export class CoreService {
constructor(public http:Http) {}
getStatus() {
return this.http.get('/api/status')
.toRx()
.map(res => res.json());
}
}
service/core_spec.ts:
import {
AsyncTestCompleter,
TestComponentBuilder,
By,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit
} from 'angular2/test';
import { MockBackend, MockConnection, BaseRequestOptions, Http, Response } from 'angular2/http';
import { Injector, bind } from 'angular2/angular2';
import { ObservableWrapper } from 'angular2/src/core/facade/async'
import { CoreService } from 'public/services/core'
export function main() {
describe('public/services/core', () => {
let backend: MockBackend;
let response: Response;
let coreService: CoreService;
let injector: Injector;
afterEach(() => backend.verifyNoPendingRequests());
it('should get status', inject([AsyncTestCompleter], (async) => {
injector = Injector.resolveAndCreate([
BaseRequestOptions,
MockBackend,
bind(Http).toFactory((backend, options) => {
return new Http(backend, options)
}, [MockBackend, BaseRequestOptions]),
bind(CoreService).toFactory((http) => {
return new CoreService(http);
}, [Http])
]);
backend = injector.get(MockBackend);
coreService = injector.get(CoreService);
response = new Response('foo');
ObservableWrapper.subscribe<MockConnection>(backend.connections, c => {
expect(c.request.url).toBe('/api/status');
c.mockRespond(response);
});
// attempt #1: fails because res argument is undefined
coreService.getStatus().subscribe(res => {
expect(res).toBe('');
async.done();
});
// attempt #2: fails because emitter.observer is not a function
ObservableWrapper.subscribe(coreService.getStatus(), res => {
expect(res).toBe('');
async.done();
});
}));
});
}
Related:
https://github.com/angular/angular/issues/3502
https://github.com/angular/angular/issues/3530
I just found this topic while looking for testing tips but I can't see a direct answer to that so...
This one is based on Angular RC.1
Testing service with Mock Backend
Let's say your service is:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
#Injectable()
export class CoreService {
constructor(private http: Http) {}
getStatus() {
return this.http.get('/api/status');
}
}
Test to the service above will look like this:
import {
beforeEach,
beforeEachProviders,
describe,
expect,
inject,
it,
} from '#angular/core/testing';
import { provide } from '#angular/core';
import { BaseRequestOptions, Response, ResponseOptions } from '#angular/http';
import { MockBackend, MockConnection } from '#angular/http/testing';
describe('Http', () => {
beforeEachProviders(() => [
CoreService,
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
})
]);
beforeEach(inject([MockBackend], (backend: MockBackend) => {
const baseResponse = new Response(new ResponseOptions({ body: 'status' }));
backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse));
}));
it('should return response when subscribed to getStatus',
inject([CoreService], (coreService: CoreService) => {
coreService.getStatus().subscribe((res: Response) => {
expect(res.text()).toBe('status');
});
})
);
})
What you really have to look at there is to have proper mocking in beforeEachProviders. Test itself is quite simple and ends up with subscribing to the service method.
Note: Don't forget to set base providers first:
import { setBaseTestProviders } from '#angular/core/testing';
import {
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS,
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
} from '#angular/platform-browser-dynamic/testing';
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
Since asking this question we did upgrade to Angular2 RC 1. Our imports look like Wojciech Kwiatek's (thank you for your answer!) but our testing strategy is slightly different. We wanted to assert on the request as well as the response. Instead of using beforeEachProviders(), we used beforeEach() where we create our own injector and save a reference to the service-under-test and mock backend. This allows us to assert on the request and manage the response inside the test, and it lets us use the verifyNoPendingRequests() method after each test.
describe('core-service', () => {
let service: CoreService;
let backend: MockBackend;
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate(<any> [
CoreService,
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: (mockBackend, defaultOptions) => new Http(mockBackend, defaultOptions),
deps: [MockBackend, BaseRequestOptions]
})
]);
service = <CoreService> injector.get(CoreService);
backend = <MockBackend> injector.get(MockBackend);
});
afterEach(() => backend.verifyNoPendingRequests());
it('should get status', () => {
backend.connections.subscribe((c: MockConnection) => {
expect(c.request.url).toEqual('api/status');
c.mockRespond(new Response(new ResponseOptions({ body: 'all is well' })));
});
service.getStatus().subscribe((status) => {
expect(status).toEqual('all is well');
});
}));
});
Edit: Plunker updated to RC2.
https://plnkr.co/edit/nlvUZVhKEr8d2mz8KQah?p=preview

Resources