Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2: get data from http in parent-component and subscribe on it nested

I plan to do such architecture:

  • component store
  • -- nested-component book

in store - i have an service call, which get data from service, and i do a subscription on result. Like it was described in angular2 docs (http).

And i want to use this data in nested components: in forms (formBuilder), in material-design elements etc.

Which way is the best, to do this? I'm new to angular2.

Store:

book: IBook;

constructor(private bookService: BookService) { }

ngOnInit() {
    this.bookService.getBook('1')
        .subscribe((book) => {
            this.book = book;
        });
}

BookService:

...

getBook (id): Observable<IBook> {
    return this.http.get(this.url + '/' + id)
        .map(this.extractData)
        .catch(this.handleError);
}

private extractData(res: Response) {
    let body = res.json();
    return body || { };
}

...

Book:

@Input() book:IBook;

constructor() {}

ngOnInit() {
    /*How here can i subscribe on book http data get?, so that i can use async value in forms etc?*/
});

Because, if i use async book everywhere (not formBuilder) - all is ok, but formBuilder is in need to update values, after data is loaded in parent component. How can i do this?

like image 928
byCoder Avatar asked Jan 05 '17 20:01

byCoder


People also ask

How do you pass data to parent component from nested child component?

To accept the data that is passed from the child component, we need to define a function in the parent-output. component and call it in the app-child-output selector, as you can see in the above snippet. $event is mandatory to use as it gets the data from the child and passes it to the parent function.

How do you pass data between two child components?

By adding the state isOpen to the parent, we can facilitate communication between the two sibling components. When the Button component is clicked it emits an event that updates the isOpen variable. That variable is then passed down to the Toggle component as a prop.

How do you pass data from one component to another in Angular on button click?

This can be done via input binding, which passes data from one component to another, generally from parent to child. This custom input binding is created by using the @Input() decorator.


1 Answers

What about passing the bookID to the BookComponent and letting the BookComponent handle the async http get in ngInit?

export class Book implements OnInit {
  @Input() bookID: number;
  private book: IBook;

  constructor(private bookService: BookService) {}

  ngOnInit() {
    this.bookService.getBook(this.bookID)
      .subscribe((book) => {
        this.book = book;
      });
  }
}

Otherwise you have a few options which are explained in https://angular.io/docs/ts/latest/cookbook/component-communication.html

I'll briefly highlight two ways which I think you could use.

Intercept input property changes with ngOnChanges

export class Book implements OnChanges {
  @Input() book: IBook;
  ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
    for (let propName in changes) {
       // handle updates to book
    }
  }
}

more info https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html

Parent and children communicate via a service

@Injectable()
export class BookService {
  books = new Subject<IBook>();

  getBook(id): Observable<IBook> {
    return this.http.get(this.url + '/' + id)
    .map(d => {
      let book = this.extractData(d);
      this.books.next(book);
      return book;
    })
    .catch(this.handleError);
  }
  ...
}

@Component({
  selector: 'book',
  providers: []
})
export class Book implements OnDestroy {
  book: IBook
  subscription: Subscription;

  constructor(private bookService: BookService) {
    this.subscription = bookService.books.subscribe(
      book => {
        this.book = book;
    });
  }

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

@Component({
  selector: 'store',
  providers: [BookService]
})
export class Store {
  book: IBook;

  constructor(private bookService: BookService) { }

  ngOnInit() {
    this.bookService.getBook('1')
        .subscribe((book) => {
            this.book = book;
        });
  }
}
like image 182
shusson Avatar answered Oct 26 '22 11:10

shusson