简体   繁体   中英

Angular 4/5 issue with routing Subject between Angular components via Angular Services

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.

first of all, your component's sort method will never sort, because you're ignoring the return value. If you wanna deal with sorting you should use like this concatcts = contacts.sort(...)

and i suggest you an another pattern:

import { Component, OnInit } from '@angular/core';
import { ContactsListComponent } from './app/contacts-list/contacts-list.component';
import { ApiService } from '../api.service';
import { OnDestroy } from "@angular/core";
import { ISubscription } from "rxjs/Subscription";

@Component({
    selector: 'app-contact-details',
    templateUrl: './contact-details.component.html',
    styleUrls: ['./contact-details.component.scss']
})
export class ContactDetailsComponent implements OnInit, OnDestroy {

    selectedContact: any[] = [];

    error: string;
    private subscription: ISubscription;

    constructor(private _apiService: ApiService) { }

    ngOnInit() { 
      this.subscription = this._apiService.newContactSubject().subscribe(data => {
        this.selectedContact = data;
        console.log(this.selectedContact.name);
      });
    }

    showContact() {
      this._apiService.newContactSubject.subscribe();
    }

    ngOnDestroy() {
      this.subscription.unsubscribe();
    }
}

But I've found have an another issue: you have defined your selectedContact as an any object array then you wanna reach the value as an object: this.selectedContact.name I hope you can solve this problem :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM