How do I transfer the array to the routing parameter? - arrays

*I'm making a angular project (version 6+).
I want to transfer array parameter, using routing.
*
const routes: Routes = [
{
path: 'books',
component: BookComponent
}
,
{
path: 'books/:id',
component: BookDetailComponent
},
...

There are two ways you can use,
Method 1:
HTML
<a routerLinkActive="active" [routerLink]="['/home', userIDs.join()]">Home</a>
TS:
userIDs: Array<number> = [1, 3, 4];
Home component typescript:
export class HomeViewComponent implements OnInit {
userIDs: Array<number> = [];
constructor(private router: ActivatedRoute) { }
ngOnInit() {
this.router.params.subscribe(params => {
this.userIDs = params['ids'].split(',');
});
}
}
Router Module:
path: 'home/:ids', component: HomeViewComponent }
Method 2 (Using queryParams):
You don't need to add anything into router module as we are doing in above method.
HTML
<a routerLinkActive="active" [routerLink]="['/home']" [queryParams]="{ids: userIDs}">Home</a>
TS
userIDs: Array<number> = [1, 3, 4];
Home component typescript:
export class HomeViewComponent implements OnInit {
userIDs: Array<number> = [];
constructor(private router: ActivatedRoute) { }
ngOnInit() {
this.router.queryParams.subscribe(p => {
this.userIDs = p.ids;
});
}
}

In html
send data
here first You will import the activated route like following.
import { ActivatedRoute } from '#angular/router';
and also in construction
construction(private _routes:ActivatedRoute) { }
In====== ngOnInit( this._route.params.subscribe(params => {
this.id=param['id'];
)

Related

Angular Jasmine Karma Background Image Component Test

I am new to Angular JS and I would like to test if the background image that I have on my header component is loaded correctly. However, on the console log, it says that the image file is not found.
Here's the whole code for your reference:
HTML:
**<div class="flex-container" [ngStyle]="{'background-image' : 'url('+ bgImage +')'}">**
<div class="text-container">
<h1>{{ title }}</h1>
<p>{{ description }}</p>
<a [href]="buttonLink" target="_blank"><button>{{ buttonText }}</button></a>
</div>
</div>
Component.ts:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
#Input() title: string;
#Input() description: string;
#Input() buttonText: string;
#Input() buttonLink: string;
**#Input() bgImage: string;**
constructor() { }
ngOnInit(): void {
}
}
Component.spec.ts:
import { ComponentFixture, TestBed } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { HeaderComponent } from './header.component';
describe('HeaderComponent', () => {
let component: HeaderComponent;
let fixture: ComponentFixture<HeaderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ HeaderComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(HeaderComponent);
component = fixture.componentInstance;
});
it('should create', () => {
fixture.detectChanges();
expect(component).toBeTruthy();
});
it('should render all inputs', () => {
component.title = 'test'
component.description = 'test-description'
**component.bgImage = 'bgImageIllustrations.jpg'**
fixture.detectChanges();
const title = fixture.debugElement.query(By.css('h1')).nativeElement as HTMLElement
const description = fixture.debugElement.query(By.css('p')).nativeElement as HTMLElement
**const bgImage = fixture.debugElement.query(By.css('.flex-container')).nativeElement as HTMLElement;**
expect(title.textContent).toBe('test');
expect(description.textContent).toBe('test-description');
**console.log(getComputedStyle(bgImage).backgroundImage);**
});
});
Hope you can help me to fix this issue. Thanks!
I would like to see if I am loading the right background image

Access data array in multiple routes angular 4

I have a service which has some data stored like this and functions that push data to it:
service.ts
export class SongsService {
albumsChanged = new Subject();
//Define future album name and songs list
newAlbumName:any;
newSongs:any;
newAlbumID:any;
// New album object
albumData:{name: string, songs:Array<string>};
albums = [
{
name: 'One album',
songs: [
'song1 Album 1',
'song2 Album 1',
'song3 Album 1',
]
}];
albumSongs(albumID){
return this.http.get('http://api.musicgraph.com/api/v2/album/'+
albumID +'/tracks?"+ api_key + "&limit=30").map(
(res:Response) => {
const songData = res.json();
// func to get all tracks
var tracks = songData.data.map(a => a.title);
// Function to filter repeated songs
var uTracks = tracks.filter(function(elem, index, self) {
return index == self.indexOf(elem);
});
return this.allTracks= uTracks;
}
);
}
// .subscribe(album => {console.log(album)}) returns []
newAlbum(name:string){
name = name.replace(/ /g, '+');
var albumID= '';
this.http.
get('http://api.musicgraph.com/api/v2/album/suggest?'
api_key + '&limit=2&prefix=' + name)
.subscribe(
( res:Response) => {
var rawData = res.json();
// console.log(rawData);
var albumName:string = rawData.data[0].title;
albumID = rawData.data[0].id;
this.albumSongs(albumID).subscribe(
songs => {
this.newSongs = songs;
console.log("And this are the songs in newAlbum = " + this.newSongs );
this.albumData = {
name:albumName,
songs:this.newSongs
};
this.albums.push(this.albumData)
this.albumsChanged.next(this.albums.slice())
}
);
}
);
this.albumsChanged.next(this.albums.slice());
}
newAlbum (name:string) {
//function that gets album name from api
this.albums.push(albumObj);
this.albumsChanged.next(this.albums.slice());
}
I have set my app.component to run an init function as a seed:
import { Component, ViewChild, ElementRef, OnInit } from '#angular/core';
import { SongsComponent } from './songs/songs.component';
import { Router } from '#angular/router';
import { SongsService } from './songs.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: []
})
export class AppComponent {
albums:any = [];
constructor(private songsService: SongsService){
};
ngOnInit() {
this.songsService.init()
}
}
App.module
const appRoutes: Routes =[
{path: '', component: AlbumsComponent},
{path: ':album', component: SongsComponent},
];
#NgModule({
declarations: [
SongsComponent,
AppComponent,
AlbumsComponent
],
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(appRoutes),
HttpModule
],
providers: [SongsService],
bootstrap: [AppComponent]
})
export class AppModule {}
When I console.log(this.albums) in the next component it only has the seed I hard coded on service.ts.
Albums.component.ts
#Component({
selector: 'app-albums',
templateUrl: './albums.component.html',
styleUrls: ['./albums.component.css'],
providers: []
})
export class AlbumsComponent {
#ViewChild('albumInput') albumInput: ElementRef;
#ViewChild('deleteIcon') deleteIcon: ElementRef;
private albums:{name: string, songs:Array<string>}[] = [];
private subscription: Subscription;
constructor(private songsService: SongsService,
private router: Router){};
ngOnInit() {
this.albums = this.songsService.albums;
this.subscription = this.songsService.albumsChanged
.subscribe(
(albums:{name: string, songs:Array<string>}[]) => {
this.albums = albums;
});
console.log(this.albums);
}
albumslog(){
console.log(this.albums)
}
// albumSongs(){
// this.router.navigate([])
// }
deleteAlbum(indexOfAlbum){
console.log(this);
console.log(indexOfAlbum);
this.songsService.albums.splice(indexOfAlbum,1);
addAlbum(albumName){
this.songsService.newAlbum(albumName);
console.log(this.songsService.albums);
And songs.components:
#Component({
selector: 'app-songs',
templateUrl: './songs.component.html',
styleUrls: ['./songs.component.css'],
providers: []
})
export class SongsComponent implements OnInit {
private subscription: Subscription;
private albums:any;
private album:any;
private songs:Array<string>;
private albumIndex:string;
constructor(private songsService: SongsService,
private router: Router,
private route: ActivatedRoute){};
ngOnInit() {
var albumIndex = +this.route.snapshot.params['album'];
console.log(albumIndex);
this.albums = this.songsService.albums;
this.subscription = this.songsService.albumsChanged
.subscribe(
(albums:{name: string, songs:Array<string>}[]) => {
this.albums = albums;
this.songs = this.getAlbum(albumIndex);
});
console.log(this.albums);
this.getAlbum(albumIndex);
// console.log(this.songsService.getAlbum("Así en el Cielo Como en la Selva"))
console.log(this.songs);
}
getAlbum(index: number){
return this.album = this.albums.splice(index)
Therefore, when I go to another route my service.albums from my service is empty, how can I keep this data over many routes?

Selecting object from JSON array in Angular 4

working on an angular4 app that has 2 components/pages.
the first component is related to the object id:1 and it is one page and the second component is related to id:2 and it is another page. both of these pages share the same template 'page.component.html'
how do get the first component to only render the object with id:1? and the same for the second component. I understand that right now as it is set up, each component is going to both objects in the array.
is there a way i can do this in the service or each component?
data.json
[
{
"id": 1,
"array":
[
{
"name": "name1.a",
"title": "title1.a",
},
{
"name": "name1.b",
"title": "title1.b",
},
{
"name": "name1.c",
"title": "title1.c",
}
],
}
{
"id": 2,
"array":
[
{
"name": "name2",
"title": "title2",
}
]
}
]
page.component.html
<div *ngFor="let set of sets">
<p>{{set.name}}</p>
<p>{{set.title}}</p>
</div>
page.component.ts
// Imports
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { page } from '../page';
import { Observable } from 'rxjs/Rx';
// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
export class GenreService {
// Resolve HTTP using the constructor
constructor (private http: Http) {}
private pagesUrl = '../assets/json/data.json';
// Fetch all existing comments
getPages() : Observable<Page[]>{
// ...using get request
return this.http.get(this.pagesUrl)
// ...and calling .json() on the response to return data
.map((res:Response) => res.json())
//...errors if any
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
}
page.ts
export class Page {
constructor(
public id: number,
public array: array,
public name: string,
public title: string
){}
}
page.component.ts
import { Component, OnInit } from '#angular/core';
import { Page } from './page';
import { PageService } from '../../services/page.service';
#Component({
selector: 'page1',
templateUrl: './page.component.html',
providers: [ PageService ],
})
export class Page1Component implements OnInit {
pages: Page[];
errorMessage: string;
ngOnInit() {
this.getPages();
}
getPages() {
this.genreService.getPages()
.subscribe(
pages => this.pages = pages,
error => this.errorMessage = <any>error);
}
}
This will work good with you
<div *ngFor="let set of sets.array">
<p>{{set.name}}</p>
<p>{{set.title}}</p>
</div>
Maybe you can change the method getPages() for getPage(id: number) and filter by id. It would be like so:
getPage(id: number) : Observable<Page>{
// ...using get request
return this.http.get(this.pagesUrl)
// ...and calling .json() on the response to return data
.map((res:Response) => res.json())
// ... do antoher map an return the correct object
.map((data: Array<any>) => {
return data.find(x => x.id === id)
})
//...errors if any
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
With that fucntion it will only return the Page that you want,
Hope that helps.

ngOnInit method called twice

I'm a little bit new in Angular:
When I load my Angular application (Angular 4), a specific component's ngOnInit() method called even if it wasn't rendered. After I navigate my app to a route that renders this component, the ngOnInit() called again. Why is that? Is this some kind of error, or is this how it works? There is no error in the console.
(Because of this, in my component's ngOninit() a subscribe method runs twice.)
Update:
offer-info.component.ts:
import { Component, Input, OnInit, NgZone } from '#angular/core';
import { OfferService } from './offer.service';
import { Offer } from '../models';
declare var $: any;
#Component({
moduleId: module.id,
selector: 's2a-offer-info',
templateUrl: './offer-info.component.html',
})
export class OfferInfoComponent implements OnInit {
private zone: NgZone;
offer: Offer = null;
constructor(
private offerService: OfferService,
) { }
ngOnInit() {
//This is where I get two 'test' output on the console:
console.log('test');
this.zone = new NgZone({enableLongStackTrace: true});
this.offerService.getOfferForOfferInfo().subscribe((offer: Offer) => {
if (offer !== null) {
this.zone.run(() => {
this.offer = offer;
$('#s2aOfferInfoModal').modal();
});
}
});
}
}
In page-packages.component.html:
...
<!-- This tag appers only once in the whole application: -->
<s2a-offer-info></s2a-offer-info>
...
In app-routing.module.ts:
...
{ path: 'packages', component: PagePackagesComponent, canActivate: [LoggedInGuard] },
{ path: 'search', component: PageSearchComponent, canActivate: [LoggedInGuard] },
{ path: '', redirectTo: '/search', pathMatch: 'full' },
...

why subscribe function is not called in angular 2?

I am using observable in angular .Actually my issue when I click button my subscribe function not called why ?
as per documentation subscribe function will call when we call next function
https://plnkr.co/edit/83NaHoVaxiXAeUFoaEmb?p=preview
constructor() {
this.data = new Observable(observer => this.dataObserver = observer);
this.data.subscribe(value => {
console.log('+++')
console.log(value)
})
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
here is documentation
http://reactivex.io/rxjs/manual/tutorial.html
On basis of Volodymyr Bilyachat suggestion i have modified your code. its working now plz check. Problem was in your way of using dataObserver
//our root app component
import {Component, NgModule} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
#Component({
selector: 'my-app',
template: `
<div>
<ul>
<li *ngFor ="let n of name">{{n.name}}</li>
</ul>
<button (click)="hndle()">heelo</button>
</div>
`,
})
export class App {
private data:Observable;
private dataObserver:Observer;
name:string;
name[];
constructor() {
this.dataObserver = new Observable(observer => this.dataObserver = observer);
this.dataObserver.subscribe(value => {
console.log('+++')
console.log(value)
});
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
}
#NgModule({
imports: [ BrowserModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
link https://plnkr.co/edit/PO80y2udrOhsVq4QQXc5?p=preview
I believe you are subscribing to the observable 2 times. You should be able to fix it by adding .share()
constructor() {
this.data = new Observable(observer => this.dataObserver = observer).share();
this.data.subscribe(value => {
console.log('+++')
console.log(value)
})
}
hndle(){
this.name.push({name:"navee"});
this.dataObserver.next(this.name);
}
In your case, it's better to use this solution:
constructor() {
this.data = new Subject();
this.data.subscribe(value => {
console.log('+++');
console.log(value);
});
}
hndle() { // TYPO: Probably it was meant to be handle
this.name.push({
name: 'navee'
});
this.data.next(this.name);
}
Don't forget to add:
import { Subject } from 'rxjs/Subject'
Working example:
https://plnkr.co/edit/zB8FHTVEm2QUHiEAYuQB?p=preview

Resources