簡體   English   中英

Angular2通知組件數據更改

[英]Angular2 Notify Component Of Data Change

因此,我一直在研究Angular 2教程和文檔。 在試用它時,我想看看是否可以將表單分成其自己的組件,但仍以相同的方式工作。 當您添加英雄時,它會自動將其添加到列表中。 我將列表作為父組件,並將表單作為子組件。 目前,當您添加英雄時,它會添加到數據中,但列表不會自動更新。 但是,如果您導航到儀表板然后返回列表,則英雄現在就在那里。

這是我的清單組件:

import { Component, OnInit }    from '@angular/core';
import { Router }               from '@angular/router';

import { Hero }                 from './hero';
import { HeroFormComponent }    from './hero-form.component';
import { HeroService }          from './hero.service';

@Component({
    selector: 'my-heroes',
    templateUrl:'app/heroes.component.html',
    styleUrls: ['app/heroes.component.css'],
    providers: [HeroService],
    directives: [HeroFormComponent]
})

export class HeroesComponent implements OnInit {
    heroes: Hero[];
    selectedHero: Hero;

    constructor(private router: Router, private heroService: HeroService) {}

    delete(hero: Hero): void {
        this.heroService
            .delete(hero.id)
            .then(() => {
                this.heroes = this.heroes.filter(h => h !== hero);
                if(this.selectedHero === hero) { this.selectedHero = null; }
            });
    }

    getHeroes(): void {
        this.heroService.getHeroes().then(heroes => this.heroes = heroes);
    }

    ngOnInit(): void {
        this.getHeroes();
    }

    onSelect(hero: Hero): void {
        if(this.selectedHero === hero) {
            this.selectedHero = null;
        } else {
            this.selectedHero = hero;
        }
    }

    gotoDetail(): void {
        this.router.navigate(['/detail', this.selectedHero.id]);
    }
}

這是我的表單組件:

import { Component, Injectable }    from '@angular/core';
import { Hero }                     from './hero';
import { HeroService }              from './hero.service';
import { HeroesComponent }          from './heroes.component';

@Component({
    selector: 'hero-form',
    templateUrl: 'app/hero-form.component.html',
    providers: [HeroService]
})

@Injectable()
export class HeroFormComponent {

    heroes: Hero[] = [];

    constructor(private heroService: HeroService) {}

    add(name: string, heroName: HTMLInputElement): void {

        name = name.trim();
        if (!name) { return; }

        this.heroService.create(name)
            .then(hero => {
                this.heroes.push(hero);
                this.selectedHero = null;
            });

        heroName.value = null;

    }
}

這是我的服務:

import { Injectable }       from '@angular/core';
import { Headers, Http }    from '@angular/http';

import 'rxjs/add/operator/toPromise';

import { Hero } from './hero';

@Injectable()
export class HeroService {

    private heroesUrl = 'app/heroes';
    private headers = new Headers({'Content-Type': 'application/json'});

    constructor(private http: Http) { }

    create(name: string): Promise<Hero> {
        return this.http
                   .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers})
                   .toPromise()
                   .then(res => res.json().data)
                   .catch(this.handleError);
    }

    delete(id: number): Promise<void> {
        let url = `${this.heroesUrl}/${id}`;
        return this.http.delete(url, {headers: this.headers})
                   .toPromise()
                   .then(() => null)
                   .catch(this.handleError);
    }

    getHero(id: number): Promise<Hero> {
        return this.getHeroes()
                   .then(heroes => heroes.find(hero => hero.id === id));
    }

    getHeroes(): Promise<Hero[]> {
        return this.http.get(this.heroesUrl)
                   .toPromise()
                   .then(response => response.json().data as Hero[])
                   .catch(this.handleError);
    }

    update(hero: Hero): Promise<Hero> {
        const url = `${this.heroesUrl}/${hero.id}`;
        return this.http
                   .put(url, JSON.stringify(hero), {headers: this.headers})
                   .toPromise()
                   .then(() => hero)
                   .catch(this.handleError);
    }

    private handleError(error: any): Promise<any> {
        console.error('An error occurred', error);
        return Promise.reject(error.message || error);
    }
}

為了使列表組件識別數據更新並刷新實際列表,需要做什么?

沒有將服務器上存在的Heros與客戶端上存在的Heros綁定的關系,因此,當服務器上的內容發生更改時(使用表單添加它們時),它將與客戶端上的列表不同步。 當您重新導航至HeroesComponent時,它們會暫時恢復同步,因為您再次調用了getHeroes()。 您需要一種方法來通知HeroesComponent有關數據的更改。

您當前正在使用Promises進行異步通信,但這還不夠好,因為Promises是一勞永逸的,而您需要連續更新,最好從服務中推送。 為此,您需要“可觀察”。 您可以在HeroesComponent ngOnInit()中注冊為該服務的英雄的觀察者,並在ngOnDestroy()中注銷。 調用getHeroes()時,該服務將需要發送英雄列表,但是當添加,刪除或編輯英雄時,該服務也需要重新發送。

問題是您正在解決英雄,因此不會反映任何進一步的更新,

服務

heroes: Subject<Hero[]> = new Subject<Hero[]>();

getHeroes(){
    this.http.get(this.heroesUrl)
               .toPromise()
               .then(response => {
                    this.heroes.next(response.json().data as Hero[]);
               })
               .catch(this.handleError);
}

create(name: string): Promise<Hero> {
    return this.http
               .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers})
               .toPromise()
               .then(res => {
                 // update heroes observable
                 this.getHeroes();
                 return res.json().data
              })
               .catch(this.handleError);
}

英雄組成

getHeroes(): void {
        this.heroes = this.heroService.heroes;
        this.heroService.getHeroes();
    }

在HTML模板中添加一個async管道,這將有助於解決Promise,並將更新列表以供將來更新。

希望這可以幫助!!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM