I have a Parent Component with an HTML click event that passes the clicked element to a method on the component.ts file, I would like this click event to be routed to Services, made into a new Subject
, then using the next()
method, pass the Subject to a different Sibling Component and bind the data to the Sibling Component's HTML.
So the routing of this data will look like this:
Parent Component(via click event) --> Service(via method on Parent Component) --> Sibling Component(via Service)*
Here is where my data passing starts:
app.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ApiService } from '../api.service';
@Component({
selector: 'app-contacts-list',
templateUrl: './contacts-list.component.html',
styleUrls: ['./contacts-list.component.scss']
})
export class ContactsListComponent implements OnInit {
sortedFavorites: any[] = [];
sortedContacts: any[] = [];
constructor (private _apiService: ApiService, private router: Router) {}
ngOnInit(){ this.getContacts()}
getContacts() {
this._apiService.getContacts()
.subscribe(
(contacts) => {
//Sort JSON Object Alphabetically
contacts.sort( (a, b) => {
if (a.name > b.name) return 1;
if (a.name < b.name) return -1;
return 0;
});
//Build new Sorted Arrays
contacts.forEach( (item) => {
if (item.isFavorite) {
this.sortedFavorites.push(item);
} else {
this.sortedContacts.push(item);
}
});
});
}
openFavorite($event, i) {<--HTML click event passing 'i' in as object clicked
let selectedFavorite = this.sortedFavorites[i];
this._apiService.openSelectedContact(selectedFavorite); <--passing said object into method connected to my services.ts file
this.router.navigate(['/details']);
};
}
The data that I am passing with the openFavorite()
method I created is working because doing a console.log(selectedFavorite)
logs the desired result to be passed.
Then it comes over to services
app.service.ts:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
@Injectable()
export class ApiService {
//API URL
private url: string = 'assets/api/contacts.json';
//Create new Subject and assign to local variable
public newContactSubject = new Subject<any>();
//Initialize HttpClient for request
constructor(private _http: Http) { }
//Pull JSON data from REST API
getContacts(): Observable<any> {
return this._http.get(this.url)
.map((response: Response) => response.json());
}
openSelectedContact(data) {
this.newContactSubject.next(data); <---Where data should be passing in!
}
}
**Now I would like my other component to receive the data from app.service.
import { Component, OnInit } from '@angular/core';
import { ContactsListComponent } from './app/contacts-list/contacts-list.component';
import { ApiService } from '../api.service';
@Component({
selector: 'app-contact-details',
templateUrl: './contact-details.component.html',
styleUrls: ['./contact-details.component.scss']
})
export class ContactDetailsComponent implements OnInit {
selectedContact: any[] = [];
error: string;
constructor(private _apiService: ApiService) { }
ngOnInit() { this.showContact() }
showContact() {
this._apiService.newContactSubject.subscribe(
data => this.selectedContact = data) <--Where the data should be showing up from services.ts file
console.log(this.selectedContact.name); <-- This is logging Undefined
}
}
What would I be missing here? Thanks so much in advance!
Try this:
showContact() {
this._apiService.newContactSubject.subscribe(
data => {
this.selectedContact = data;
console.log(this.selectedContact.name);
}
}
Both lines of code (including your logging) are within the function passed into the subscribe. Each time an item is emitted, it only runs the code within the callback function.
And as a side note ... it is normally recommended that you make your subject private and only expose it's read-only observable using code something like this:
private selectedMovieSource = new Subject<IMovie | null>();
selectedMovieChanges$ = this.selectedMovieSource.asObservable();
Notice that the subject is private and it's observable is exposed using a separate property. The components then subscribe to the public observable of the subject.