Angular 6 - Get current route and its data - angular6

How to get the current route you're in and its data, children and parent?
If this is the route structure:
const routes: Routes = [
{path: 'home', component: HomeComponent, data: {title: 'Home'}},
{
path: 'about',
component: AboutComponent,
data: {title: 'About'},
children: [
{
path: 'company',
component: 'CompanyComponent',
data: {title: 'Company'}
},
{
path: 'mission',
component: 'MissionComponent',
data: {title: 'Mission'}
},
...
]
},
...
]
If I am currently in CompanyComponent, how do I get my current route w/c is Company, get its parent w/c is about, its data and its siblings such as mission, etc.?

#Component({...})
export class CompanyComponent implements OnInit {
constructor(
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
// Parent: about
this.route.parent.url.subscribe(url => console.log(url[0].path));
// Current Path: company
this.route.url.subscribe(url => console.log(url[0].path));
// Data: { title: 'Company' }
this.route.data.subscribe(data => console.log(data));
// Siblings
console.log(this.router.config);
}
}

constructor(
private router: Router,
private route: ActivatedRoute,
) {
}
ngOnInit() {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
return this.getHeaderClasses();
}),
)
.subscribe((headerClasses: string | null) => {
this.headerClasses = headerClasses;
});
this.headerClasses = this.getHeaderClasses();
}
getHeaderClasses(): string | null {
let child = this.route.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['headerClasses']) {
return child.snapshot.data['headerClasses'];
} else {
return null;
}
}
return null;
}
routing
{
path: 'list',
component: DialogListComponent,
data: {
headerClasses: 'col-lg-8',
},
},

You can access the route's data property from the snapshot like this:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
templateUrl: './app/home/welcome.component.html'
})
export class WelcomeComponent implements OnInit {
public pageTitle: string;
constructor( private route: ActivatedRoute) {
}
ngOnInit(): void {
this.pageTitle = this.route.snapshot.data['title'];
}
}

#Component({...})
#UntilDestroy()
export class CompanyComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
this.router.events
.pipe(
untilDestroyed(this),
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
map((event: NavigationEnd) => event.url)
)
.subscribe(url=> {
console.log(url);
});
}
}

Related

Problem on casting objects to array of a model in Angular

Here is my service code:
export class ProductListService {
constructor(private httpClient: HttpClient) {
}
getProducts(): Observable<IResponse> {
return this.httpClient.get<IResponse>('https://localhost:7127/Product/GetProductList');
}
}
and here is my component:
getProducts(): void {
this.productsService.getProducts()
.subscribe((response: IResponse) => {
this.products = <Product[]>response.data;
})
}
Which Product and IResponse are models:
export interface Product {
Id: string;
Title: string;
Description: string;
ImageUri: string;
CategoryId: string;
}
export interface IResponse {
data: object;
status: number;
}
When I get data from the api, it returns data as follow:
{
"data": [
{
"id": "e15",
"title": "LED TV 42 inch ",
"description": "-",
"imageUri": "C:\\wwwroot/cdn\\e15.jpg",
"categoryId": "tv"
},
{
"id": "e16",
"title": "LED TV 52 inch ",
"description": "-",
"imageUri": "C:\\wwwroot/cdn\\e16.jpg",
"categoryId": "tv"
}
],
"status": 200
}
I want to put the data into my products variable. How could I do this?
I agree with Sean Chase. Change the casing on your model. You also might want to cast the data property on the IResponse interface to Product[] (as a side note, interfaces don't start with I. That's a C# convention).
Are you using the products property in the template HTML? If so, you can use the pipe async syntax and replace the products property with an Observable<Product[]>. Here's an example
// models.ts
export interface Product {
id: string;
title: string;
description: string;
imageUri: string;
categoryId: string;
}
export interface IResponse {
data: Product[];
status: number;
}
// product-list.component.ts
import { Component, OnInit } from '#angular/core';
import { map, Observable, of, Subscription } from 'rxjs';
import { IResponse, Product } from './models';
import { ProductListService } from './products-list.service';
#Component({
selector: 'product-list',
template: `
<div *ngFor="let product of products$ | async">
<div>Id: {{ product.id }}</div>
<div>Title: {{ product.title }}</div>
<div>Description: {{ product.imageUri }}</div>
<div>CategoryId: {{ product.categoryId }}</div>
</div>
`
})
export class ProductListComponent implements OnInit {
products$: Observable<Product[]> = of([]);
constructor(private productsListService: ProductListService) {}
ngOnInit() {
this.products$ = this.productsListService.getProducts().pipe(map((res: IResponse) => res.data));
}
}
// product-list.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, of } from 'rxjs';
import { IResponse, Product } from './models';
#Injectable({
providedIn: 'root',
})
export class ProductListService {
// constructor(private httpClient: HttpClient) {}
getProducts(): Observable<IResponse> {
// return this.httpClient.get<IResponse>('https://localhost:7127/Product/GetProductList');
return of({
data: [
{
id: '1',
title: 'title-1',
description: 'description-1',
imageUri: '/images/image-1.jpg',
categoryId: '1'
} as Product,
{
id: '2',
title: 'title-2',
description: 'description-2',
imageUri: '/images/image-2.jpg',
categoryId: '2'
} as Product,
],
status: 200
});
}
}

Unit Testing Angular component with service : Cannot read property 'diagonisticData' of undefi

I am new to angular testing. I have a component, nested json and a service. The app works fine but during testing values are not being populated into the component. Please help.I have attached the service, json object,component and spec file.
I am not sure if I am following the right approach in spec file.
App component -Hub-Details-component.ts
export class HubDetailsComponent implements OnInit {
ngOnInit(): void {}
public jsonData:any = []
public diagnosticsData:any = [];
public dummy:any = [];
public hubData:any;
constructor(private dataService: DataService) {}
handleData()
{
this.dataService.getData()
.subscribe(response =>{
if(response!=null)
{
this.jsonData=response;
console.log(this.jsonData);
this.dummy=this.jsonData.result;
console.log(this.dummy);
this.diagnosticsData=this.dummy.diagnosticData;
const DataArray = [];
for(const element in this.diagnosticsData)
{
DataArray.push({
id:element,
name:this.diagnosticsData[element]
});
}
console.log(DataArray);
this.hubData=DataArray;
}
});
}
}
DataService
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'})
export class DataService {
public url = '/assets/Data/Data.json'
constructor(private http: HttpClient ) { }
getData = () => {
const url = 'assets/Data/Data.json';
return this.http.get(url);
}}
json file
{
"result"
{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}
spec.ts
it('should get data from dataservice',fakeAsync(()=>{
const fixture =
TestBed.createComponent(HubDetailsComponent);
const component =
fixture.debugElement.componentInstance;
const service =
fixture.debugElement.injector.get(DataService);
let spy_getPosts =
spyOn(service,'getData').and.callFake(() => {
return of([{"result"{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}]).pipe(delay(2000));});
fixture.detectChanges();
component.handleData();
tick(2000);
expect(component.jsonData).toEqual([{
{"result"{
"abc"
{
"name" :"abc",
"tag" : "xyz",
"status": "qwe"
}
}
}
}]);
}));
Thanks in advance.
Try this:
// In your spec file, mock the service;
#Injectable()
class MockDataService extends DataService {
getData() {
const mockData = {
result: {
diagnosticData: [
{ mock1: 'value1' },
{ mock2: 'value2' }
]
}
}
return of(mockData);
}
}
describe('Your Component Name you are testing', () => {
let dataService;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [],
imports: [...yourImports],
schemas: [NO_ERRORS_SCHEMA],
providers: [
{
provide: DataService,
useClass: MockDataService
}
]
}).compileComponents();
dataService = TestBed.get(DataService);
}));
// Now your test case:
it('should call #handleData() method', () => {
spyOn(component, 'handleData').and.callThrough();
component.handleData();
expect(component.handleData).toHaveBeenCalled();
});
// Thats it. You do not need to do anything else;
})

After guard implementation, the unauthorized url return to main screen not showing data

When I run the angular app, it redirects to localhost:4200/events page where I have data to be displayed. Now I have implemented guard service as beforelogin & afterlogin to let allow user to access the certain page before and after login.
Example: if the user is not logged-in and if the user hits url "localhost:4200/special" directly I want it redirect to localhost:4200/events page but instead it redirect to localhost:4200 page. I have tried to display data to this localhost:4200 page as well but data is not being displayed.
Instead of
path:'', redirectTo: 'events',
I have also tried:
path:'', component: EventComponent
app-routing.module.ts
import { BeforeLoginGuard } from './guards/before-login.guard';
import { AfterLoginGuard } from './guards/after-login.guard';
const routes: Routes = [
{
path:'',
redirectTo: 'events',
pathMatch: 'full'
},
{
path: 'login',
component: LoginComponent,
canActivate: [BeforeLoginGuard]
},
{
path: 'signup',
component: SignupComponent,
canActivate: [BeforeLoginGuard]
}
{
path: 'events',
component: EventsComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
after-login.guard
export class AfterLoginGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this._tokenService.loggedIn();
}
constructor(private _tokenService: TokenService) { }
}
events.component
export class EventsComponent implements OnInit {
events = [];
constructor(private _eventService: EventService) { }
ngOnInit() {
this._eventService.getEvents()
.subscribe(
res => this.events = res,
err => console.log(err)
);
}
}

angular observables reading json into smart table

I am trying to read json data from a restFul server and populate a smart table with the results. I am stuck and cant seem to find out how to get it to work. It seems I am able to read the Json data from the restFul server but I am not real sure how to load it into the smart-table.
Any help is greatly appreciated!
Here are the parts of the application that are used:
the service (smart-table.service):
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { HttpErrorResponse, HttpResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
export interface LCQIWK {
date: Date;
rank: number;
zone: string;
enodeb: string;
market: string;
usid: number;
impact: number;
tnol: number;
ret: number;
acc: number;
irat: number;
tput: number;
rtt: number;
}
const REST_SERVER = 'http://nonprod-hywrca02-zltv3747-0001- ingress.idns.cci.att.com:31840/thor';
// import { LCQIWK } from './models/lcqiwk';
#Injectable()
export class SmartTableService {
constructor(private http: HttpClient) { }
getData() {
return this.http.get<LCQIWK>(REST_SERVER + '/cqi/lte/wk')
.pipe(
retry(3), // retry a failed request up to 3 times
catchError(this.handleError) // then handle the error
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
}
}
cqi-table.component
import { Component } from '#angular/core';
import { LocalDataSource } from 'ng2-smart-table';
import { LCQIWK, SmartTableService } from '../../../#core/data/smart-table.service';
// import { LCQIWK } from '../../../#core/data/models/lcqiwk';
#Component({
selector: 'app-cqi-table',
templateUrl: './cqi-table.component.html',
providers: [ SmartTableService ],
styleUrls: ['./cqi-table.component.scss']
})
export class CqiTableComponent {
settings = {
actions: false,
columns: {
date: {
title: 'Date',
type: 'number',
},
rank: {
title: 'Rank',
type: 'string',
},
zone: {
title: 'ZONE',
type: 'string',
},
enodeb: {
title: 'eNodeB',
type: 'string',
},
market: {
title: 'Market',
type: 'string',
},
usid: {
title: 'USID',
type: 'number',
},
impact: {
title: 'Impact',
type: 'number',
},
tnol: {
title: 'TNoL',
type: 'string',
},
ret: {
title: 'RET',
type: 'string',
},
acc: {
title: 'ACC',
type: 'string',
},
irat: {
title: 'IRAT',
type: 'string',
},
tput: {
title: 'TPUT',
type: 'number',
},
rtt: {
title: 'RTT',
type: 'number',
},
},
};
error: any;
headers: string[];
lcqiwk: LCQIWK;
source: LocalDataSource = new LocalDataSource();
constructor(private smartTableService: SmartTableService) {
this.smartTableService.getData()
.subscribe(
(data: LCQIWK) => this.lcqiwk = { ...data }, // success path
// this.source.load(this.lcqiwk),,
error => this.error = error, // error path
);
}
clear() {
this.lcqiwk = undefined;
this.error = undefined;
this.headers = undefined;
}
/* showConfig() {
this.smartTableService.getData()
.subscribe(
(data: LCQIWK) => this.lcqiwk = { ...data }, // success path
// this.source.load(this.lcqiwk),
error => this.error = error // error path
);
} */
}
// this.source.load(data);
Try this way...
this.smartTableService.getData()
.subscribe((data) => {
for (let i = 0; i < data.length; i++) {
data = {
id: (i + 1),
date : data[i].date,
rank : data[i].rank,
zone : data[i].zone,
enodeb : data[i].enodeb,
market : data[i].market,
usid : data[i].usid
// ... Add all data
}
this.source.add(data)
}
this.source.refresh();
});
}

How to pass data received from service to angular datatable

I have just started working on Angular 4 and I am trying to render some data which I receive from angular service in json format, into angular-datatable, but whichever option i try its not working for me.
The table is coming, the columns are coming, however the data inside the columns are not displaying.
Any help would be great,
Thanks in advance..!!!!
Please find my code below:
component.html
<table datatable [dtOptions]="dtOptions" class="row-border hover"></table>
component.ts
import { Component, OnInit } from '#angular/core';
import { FleetDataService } from '../../services/fleet-data.service';
import { Subject } from 'rxjs/Subject';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
private fleetData: any;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
this.fleetData = fleetData;
console.log(this.fleetData);
this.dtTrigger.next();
},
err => {
console.log(err);
}
);
this.dtOptions = {
pagingType: 'full_numbers',
columns: [{
title: 'First Name',
data: this.fleetData
}, {
title: 'Last Name',
data: this.fleetData
}, {
title: 'Score',
data: this.fleetData
}]
};
}
}
component.service
import { Injectable } from '#angular/core';
import { HttpModule, Http, Response, Headers, RequestOptions } from
'#angular/http';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class FleetDataService {
constructor(private http: Http) { }
getFleetData() {
return this.http.get("../../assets/data/test.json")
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server
Error'));
}
}
test.json
[{
"FirstName": "Jill",
"LastName": "Smith",
"Score": "disqualified"
}, {
"FirstName": "Eve",
"LastName": "Jackson",
"Score": "94"
}, {
"FirstName": "John",
"LastName": "Doe",
"Score": "80"
}, {
"FirstName": "Adam",
"LastName": "Johnson",
"Score": "67"
}]
You set your dtOptions outside the subscribe.
If you do this the fleetData stays empty so dtOptions is never set correctly, because an Observable is asynchronous. I propose this code:
export class DashboardComponent implements OnInit {
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private getFleetData:FleetDataService) { }
ngOnInit() {
this.getFleetData.getFleetData().subscribe(
fleetData => {
console.log(fleetData);
this.buildDtOptions(fleetData)
this.dtTrigger.next();
},
err => {
console.log(err);
});
}
private buildDtOptions(fleetData: any): void {
this.dtOptions = {
pagingType: 'full_numbers',
columns: [
{title: 'First Name', data: fleetData},
{title: 'Last Name', data: fleetData},
{title: 'Score', data: fleetData}
]
};
}
}
For this error: ERROR TypeError: Cannot read property 'aDataSort' of undefined. You can do a spinner (ngIf / else) in the view and when data are loaded you display the datatable