如何根据Angular中一个组件中的click事件更改其他组件中的数据?

时间:2017-12-27 12:45:39

标签: angular data-binding angular-directive angular5

我是Angular的初学者,我开发了一个Angular 4/5应用程序,由5个组件组成:A,B,C,D和E.所有这些组件都显示在单个(相同)页面上。组件A由导航栏中的下拉列表组成。现在,我要做的是,在组件A的下拉列表中选择任何特定选项后,我将同时更改其他组件B,C,D和E的数据。

我对如何实现这种数据绑定感到非常困惑。任何人都可以帮忙解决这个问题吗?

由于发布整个代码在这里将是一项非常困难的任务,因为我有大约2打文件,所以我发布了组件A,组件B和根组件的代码。

组件代码,其中组件A是导航栏

导航bar.component.html:

<div class="container model-family-navigation-bar">
  <nav class="navbar navbar-expand-sm navbar-dark model-family-navigation-bar">
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
      aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav">
        <!-- <div class="col-sm-auto"> -->
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle navigation-bar-content text-white" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
            aria-haspopup="true" aria-expanded="false">
            <span id="selected">Model Family</span>
          </a>
          <div class="dropdown-menu bg-success table-striped" aria-labelledby="navbarDropdown">
            <h1 class="dropdown-header text-white">Select Model Family</h1>
            <div *ngFor="let item of dropdownElements">
              <div class="dropdown-divider"></div>
              <a class="dropdown-item" (click)="showList()">{{item.model_family}}</a>
            </div>
          </div>
        </li>
        <!-- </div> -->
        <!-- <div class="col-sm-auto"> -->
        <li class="nav-item">
          <span class="navigation-bar-content navbar-text text-white ml-4">Proportional Directional Valve</span>
        </li>
        <!-- </div> -->
      </ul>

      <ul class="navbar-nav ml-auto">
        <li class="nav-item navbar-right">
          <a class="nav-link text-white" href="https://www.google.com/">Data Sheet</a>
        </li>
      </ul>

    </div>
  </nav>
</div>

导航bar.component.ts:

import { Component, OnInit } from '@angular/core';
import {NavigationDropdownElements} from './navigation-bar-dropdownElements'

@Component({
  selector: 'navigation-bar',
  templateUrl: './navigation-bar.component.html',
  styleUrls: ['./navigation-bar.component.css']
})
export class NavigationBarComponent implements OnInit {
  dropdownElements = NavigationDropdownElements;

  ngOnInit() {}

}

导航-BAR-dropdownElements.ts

class NavigationDropdown{
    model_family: string;
}
export const NavigationDropdownElements: NavigationDropdown[] = [
    { model_family: 'CP210-1'},
    { model_family: 'CP211-2'},
    { model_family: 'CP212-3'}
];

组件B代码,其中组件B是模型族描述

模型家庭description.component.ts:

import { Component, OnInit } from '@angular/core';
import { descriptionElements1, descriptionElements2 } from './model-family-description-elements';
@Component({
  selector: 'model-family-description',
  templateUrl: './model-family-description.component.html',
  styleUrls: ['./model-family-description.component.css']
})
export class ModelFamilyDescriptionComponent implements OnInit {
  desc1 = descriptionElements1;
  desc2 = descriptionElements2;
  constructor() { }

  ngOnInit() {
  }

}

模型家庭description.component.html

<div class="container border-section">
  <div class="row">
    <p class="ml-2">{{desc2.description}}</p>
  </div>
</div>

模型家庭描述-elements.ts

class ModelFamilyDescription {
    description: string;
}

export const descriptionElements1: ModelFamilyDescription =
    { description: 'This is a proportional, 3 position 4 way, directional control valve.' };

export const descriptionElements2: ModelFamilyDescription =
    { description: 'This is a proportional, 4 position 5 way, non-directional control valve.' };

根组件:

app.component.html:

<navigation-bar></navigation-bar>
<model-family-description></model-family-description>

app.component.ts:

import { Component } from '@angular/core';

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

}

请帮忙。

4 个答案:

答案 0 :(得分:2)

您应该使用@Injectable

创建一个公共Subject

示例:

@Injectable()
export class CommonService {

    private dropdownValue: Subject<string> = new Subject();

    public getDropdownValue() : Observable {
        return this.dropdownValue.asObservable();
    }

    public setDropdownValue(value: string) : void {
        this.dropdownValue.next(value);
    }

然后在组件A中:

constructor(
    private commonService: CommonService
) {
   ...
}

protected onDropdownChange(value: string) : void {
    this.commonService.setDropdownValue(value);
}        

以及其他组成部分:

constructor(
    private commonService: CommonService
) {
    this.commonService.getDropdownValue().subscribe((newValue) => {
        // action on data change
    });
}

答案 1 :(得分:1)

首先创建一个服务:

例如:

<强> message.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MessageService {
    private subject = new Subject<any>();

    sendMessage(message: string) {
        this.subject.next({ text: message });
    }

    clearMessage() {
        this.subject.next();
    }

    getMessage(): Observable<any> {
        return this.subject.asObservable();
    }
}

然后将该服务添加到 app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

import { MessageService } from './message.service';

@NgModule({
  imports:      [
    BrowserModule,
    FormsModule,
    ModalModule.forRoot()
  ],
  declarations: [
    AppComponent 
  ],
  providers:    [
    MessageService
  ],
  bootstrap:    [ 
    AppComponent 
  ]
})
export class AppModule { }

现在您需要在要从中发送数据的组件中导入服务(在您的情况下为组件A)

类似的东西:

import { Component, OnInit } from '@angular/core';
import {NavigationDropdownElements} from './navigation-bar-dropdownElements'

import { MessageService } from './message.service';

@Component({
  selector: 'navigation-bar',
  templateUrl: './navigation-bar.component.html',
  styleUrls: ['./navigation-bar.component.css']
})
export class NavigationBarComponent implements OnInit {
  dropdownElements = NavigationDropdownElements;

  constructor(private messageService: MessageService) {}

  sendMessage(data:string): void {
    // send message to subscribers via observable subject
    this.messageService.sendMessage(data);
  }

  showList() {
    //on a click, you send the message here
    let message:string="data example";
    this.sendMessage(message);
  }

  clearMessage(): void {
    // clear message
    this.messageService.clearMessage();
  }

  ngOnInit() {}

}

最后,您必须在要读取要从第一个组件接收的消息或数据的组件中导入服务(例如,组件B)

类似:

import { Component, OnInit,  OnDestroy} from '@angular/core';
import { descriptionElements1, descriptionElements2 } from './model-family-description-elements';
import { Subscription } from 'rxjs/Subscription';

import { MessageService } from './message.service';
@Component({
  selector: 'model-family-description',
  templateUrl: './model-family-description.component.html',
  styleUrls: ['./model-family-description.component.css']
})
export class ModelFamilyDescriptionComponent implements OnInit {
  //you receive the data in this variable --> message
  message: any;
  subscription: Subscription;

  desc1 = descriptionElements1;
  desc2 = descriptionElements2;

  constructor(private messageService: MessageService) {

  }

  ngOnDestroy() {
    // unsubscribe to ensure no memory leaks
    this.subscription.unsubscribe();
  }

  ngOnInit() {
    // subscribe to component A messages
    this.subscription = this.messageService.getMessage().subscribe(message => { this.message = message; });
  }

}

答案 2 :(得分:0)

使用EventEmitter或使用Subject有两种方法 我更喜欢主题。 您可以从rxjs lib的文档中阅读有关Subject的更多信息 http://reactivex.io/rxjs/file/es6/Subject.js.html#lineNumber19 与EventEmitter不同,它不是角度实现的函数 如果你想了解更多关于EventEmitter的信息 https://angular.io/api/core/EventEmitter

答案 3 :(得分:0)

您需要从组件A

发出下拉选项更改

然后使用 setter 方法从组件B和C接收更改。在值更新期间始终会调用 Setter 方法。

点击此处:https://stackblitz.com/edit/angular-dshm6g

您还可以使用 rxJs 中的可观察模式来解决此类问题。