父/子组件通信角度2

时间:2017-11-17 14:25:22

标签: html angular

我无法在child_1组件中实现操作按钮,但事件处理程序位于子子组件child_2中,如以下代码所示:

app.component.html(Parent Html)

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
  <app-navigation></app-navigation> <!-- Child1-->
</div>

app.component.html(父组件)

import { Component } from '@angular/core';
import { ProductService } from './productservice';
import {Product} from './product';

@Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css'],
    })
    export class AppComponent {
      title = 'MobileShirtShoeApp';
    }

app.module.ts(主要模块)

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { Product } from './product';
import { ProductService } from './productservice';
import { AppComponent } from './app.component';
import { NavigationComponent } from './navigation/navigation.component';
import { DataTemplateComponent } from './data-template/data-template.component';

@NgModule({
  declarations: [AppComponent,NavigationComponent,DataTemplateComponent],
  imports: [BrowserModule,HttpModule],
  providers: [ProductService],
  bootstrap: [AppComponent]
})

export class AppModule { }

navigation.component.html(儿童1 HTML)

<fieldset>
  <legend>Navigate</legend>
  <div>
     <button  (click)="loadMobiles()">Mobiles</button> <!--Child_1 Action-->
  </div>
  <app-data-template></app-data-template>
</fieldset>

navigation.component.ts(Child 1 Component.ts)

import { Component, OnInit } from '@angular/core';
import { ProductService } from '../productservice';
import {Product} from '../product';
import {DataTemplateComponent} from '../data-template/data-template.component';


@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
  error: string;
  productArray: Product[];

  constructor(private myService: ProductService){
    this.myService = myService;
  }

  dataTemplateComponent: DataTemplateComponent = new DataTemplateComponent(this.myService);

  ngOnInit() {
  }

  loadMobiles() {
   return this.dataTemplateComponent.loadMobiles();
  }
}

data-template.component.html(子级2 HTML)(不显示数据)

<fieldset>
    <legend>Requested Data</legend>
    Welcome
    <div>
      <ul>
            <li *ngFor="let product of productArray">
                {{product.id}} {{product.name}} {{product.price}}
                <img src="{{product.url}}">
            </li>
        </ul>
    </div>
</fieldset>

data-template.component.ts(子级2组件)(包含产品服务调用代码)

import { Component} from '@angular/core';
import {Product} from '../product';
import {ProductService} from '../productservice';

@Component({
  selector: 'app-data-template',
  templateUrl: './data-template.component.html',
  styleUrls: ['./data-template.component.css']
})

export class DataTemplateComponent  {
  error: string;
  productArray: Product[];
  constructor(private productService: ProductService) {
    this.productService = productService;
  }

  loadMobiles(){
    let promise  = this.productService.fetchMobiles();
    promise.then(productArr => {
        return this.productArray = productArr;
      }).catch((err) => {
       this.error = err;
      });
  }
}

ProductService.ts

import 'rxjs/add/operator/toPromise';
import {Http, HttpModule} from '@angular/http';
import {Injectable} from '@angular/core';
import {Product} from './product';


@Injectable()
export class ProductService{
  http: Http;
  constructor(http: Http){
  this.http = http;
  console.log(http);
 }

fetchMobiles(): Promise<Product[]>{
  let url = "https://raw.githubusercontent.com/xxxxx/Other/master/JsonData/MobileData.json";
  return this.http.get(url).toPromise().then((response) => {
        return response.json().mobiles as Product[];
    }).catch(this.handleError);
}

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

很抱歉,如果代码困扰你。因此,当在child_1.html中进行操作时,我无法在child_2.html中显示服务数据。服务正常且名称是ProductService,它使用Product.ts作为对象来获取JSON格式的数据。任何形式的帮助都表示赞赏。

1 个答案:

答案 0 :(得分:2)

这不起作用,因为您在app-navigation中实例化的DataTemplateComponent与DataTemplateComponent的实例不同于页面上的DataTemplateComponent。这是一个全新的实例化,并且根本不受页面约束。您要实现的是组件通信。具体而言,父/子组件通信。有很多方法可以做到这一点,最干净,最灵活/可扩展的方法是使用共享服务模式。基本上,你声明一个带有observable的服务,你注入两个服务,一个更新observable而另一个订阅它,如下所示:

@Inject()
export class MyComponentCommunicationService {
    private commSubject: Subject<any> = new Subject();
    comm$: Observable<any> = this.commSubject.asObservable();
    notify() {
        this.commSubject.next();
    }
}

然后在应用程序模块中提供此服务,或者根据需要在应用程序导航中提供父组件:

constructor(private commService: MyComponentCommunicationService) {}
loadMobiles() {
   this.commservice.notify();
}

并在数据模板中:

constructor(private commService: MyComponentCommunicationService, private productService: ProductService) {}
ngOnInit() {
    this.commSub = this.commService.comm$.subscribe(e => this.loadMobiles());
}
ngOnDestroy() { this.commSub.unsubscribe(); } // always clean subscriptions

这可能有点不必要,因为您已经在那里拥有产品服务。您可能只是将加载移动设备逻辑移动到产品服务中,并触发数据模板服务订阅的可观察对象,并让导航组件在产品服务上调用load mobile方法,但这只是为了说明这个概念。

我可能会这样做:

@Inject()
export class ProductService {
    private productSubject: Subject<Product[]> = new Subject<Product[]>();
    products$: Observable<Product[]> = this.productSubject.asObservable();
    loadMobiles() {
        this.fetchMobiles().then(productArr => {
            this.productSubject.next(productArr);
          }).catch((err) => {
            this.productSubject.error(err);
          });
    }
}

然后导航组件:

loadMobiles() {
   this.myService.loadMobiles();
}

然后是数据模板:

ngOnInit() {
    this.productSub = this.productService.products$.subscribe(
        products => this.productArray = products,
        err => this.error = err
    );
}
ngOnDestroy() { this.productSub.unsubscribe(); } // always clean subscriptions