Angular2通知数据更改组件

时间:2016-09-06 21:31:58

标签: angular angular2-forms angular2-services

所以我一直在研究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);
    }
}

需要做什么才能使列表组件识别数据更新并刷新实际列表?

2 个答案:

答案 0 :(得分:0)

没有任何东西可以将服务器上存在的英雄与客户端上的英雄联系起来,所以当服务器上的内容发生变化时(当你使用表单添加它们时)它会从列表中取消同步客户端。当您重新导航到HeroesComponent时,它们会暂时恢复同步,因为您再次调用getHeroes()。您需要一种方法来通知HeroesComponent数据的变化。

您目前正在使用Promise进行异步通信,但这还不够好,因为Promise在您需要持续更新时是一次性完成,最好是从服务推送。为此你需要Observable。您可以在HeroesComponent ngOnInit()中注册服务的英雄上的Observer,并在ngOnDestroy()中注销。当调用getHeroes()时,服务需要发送英雄列表,但是当添加,删除或编辑英雄时,还需要重新发送。

答案 1 :(得分:0)

问题是你正在解决英雄因此没有反映任何进一步的更新,

<强>服务

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);
}

HeroesComponent

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

在HTML模板中添加async管道,这将有助于解决承诺并更新列表以供将来更新。

希望这会有所帮助!!