Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 Data in Service, passing to component(s)

Tags:

Have some data in a service, and was working perfectly when I had data in an object sitting on the service, but now that I've hooked up a database connection, the data never makes it to the component.

I want the service to subscribe to the data coming back from the database and have defined the call like this:

  public setPerson(ac: string): void{
    console.log(ac);
    this.generatePerson(ac).subscribe((data) => {
        // this.mapPersonFromInput(data[0]);
        console.dir(data);
    });

  }

The mapPersonFrominput() function is a holdover from mocked data. it is essentially the same as extractData further below, but from a static object in the code.

generatePerson looks like this:

public generatePerson(id: string):Observable<Person>{
    var datRetUrl: string = '/api/'
    var fullUrl: string = datRetUrl + id;
    return this.http.get(fullUrl)
                .map(this.extractData)
                .catch(this.handleError);
  }

extractData simply assigns values from the input object to the service's object structure, and handleerror simply logs the error to the console.

I call the service to initialize the data object from the component before the component loads by calling this function from a navigation component:

  passCodeToService():void{
    this.psn.setPerson(this.accessCode);
    this.route.navigate(['/name']);
  }

and in the actual component that should get the data, I'm using ngOnInit, but I think I should be using ngOnChanges to initialize the component. Here's the code that I'm currently using, but haven't had luck fixing just yet.

ngOnInit() {
  this.name =this.psn.getName();
  console.log(this.name);
}

getName() simply returns the object that I'm storing in the service.

  public getName(): Name{
    return this.servicePerson.name;
  }
like image 924
Chris Rutherford Avatar asked Aug 02 '17 14:08

Chris Rutherford


People also ask

How do you pass data from one component to another through service?

If you want to pass data from the child component to the parent component use @Output() and EventEmitter. To pass data from the child to the parent, you have to emit it from the child. The parent will be listening for the event will grab the data.

Is it a good practice to pass data using services in Angular?

This is used to get direct access to the element in the DOM and it is not a good practice. However, it is the easiest way to get input data from users and focus on the service itself. Alternatively, use ngModel or consider Angular forms.


1 Answers

You should not use ngOnChanges here, it is not meant for what you are trying to do.

According to your question, this is what you are trying to achieve:

  • Fetch data from DB
  • Your component should be able to get a piece of that data asynchronously

You can achieve this with the code you have. All you need to do is add a little more code and leverage RxJS. More specifically:

  • Create a person subject in your person service
  • When data comes back from your DB, do personSubject.next(dataFromDB) to add to the person stream.
  • Create a function that will return the person subject as an observable, and then you can subscribe to that observable from your component

With this approach, every time data comes from your DB, that data will be added to a person stream, and anything subscribing to that stream (your component) will get the data.

Quick example (since I don't have your full code):

import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class PersonService {
    // The person subject
    personStream: ReplaySubject<Person> = new ReplaySubject();

    // The person observable
    person$(): Observable<Person> {
        return this.personStream.asObservable();
    }

    // Get person from DB and add to stream
    getDataFromDB() {
        this.http.get(url).subscribe(response => {
            this.personStream.next(response.person);
        });
    }
}

@Component({...})
export class MyComponent implements OnInit {
    person: Person;

    constructor(private personService: PersonService) {}

    ngOnInit() {
        // Subscribe to person observable. Any time person data changes, this will be called.
        this.personService.person$().subscribe(person => this.person = person);

        // If you return the `this.http.get(url)` from `getDataFromDB`, you can just do this instead...
        this.personService.getDataFromDB().subscribe(person => this.person = person);
    }
}

But this is all overkill, because in reality all you need to do is subscribe to the getDataFromDB function in your component, since that itself can return an observable of Person type.

like image 188
Lansana Camara Avatar answered Sep 30 '22 15:09

Lansana Camara