2017-04-12 78 views
1

我制作了一个组件 - 我们称之为CUSTOMSELECT,它需要一些输入,例如下拉列表的选项列表,默认选择的选项,标签等等。我想在某些页面上多次使用此组件。例如,我需要CUSTOMSELECT的员工,并且在页面上的嵌套组件中,我需要一个CUSTOMSELECT部门和另一个角色。Angular 2 Observable for custom component

好吧,一切都很好。每个实例都可以正确显示所需的数据。

现在我要发布一个CUSTOMSELECT的实例中选择的任何改变,这样我可以让我可以订阅。例如,当选择员工时,我想刷新页面的其余部分。

我为此创建了一个服务。我将CUSTOMSELECT中的click事件链接到一个将所选值发布到服务的函数。在父组件中,我订阅了“主题”,以便我可以对员工进行更改。

这是有效的。

但是,如果我再与嵌套组件的部门CUSTOMSELECT改变选择,这个值被公布,父组件的员工用户拿起变化并处理它。不是我想要发生的事情。一点也不!

所以,我怎么能告诉观察员只注意他们感兴趣的消息?即我如何发布给适当的观察者:员工实例不需要知道部门实例已更改值,等等。

感谢您的任何帮助 - 一整天试图找出迄今为止这一个。

它可能有助于查看组件树是这样的:

employee-roles.component 
    select-dropdown.component (employees) 
    employee-roles-form.component 
    select-dropdown.component (departments) 
    select-dropdown.component (roles) 

下面的代码。

选择-dropdown.component.html

<div style="margin-top: 12px" class="input-group"> 
<span class="input-group-addon" style="height:30px">{{label}}</span> 
<input type="text" class="form-control" style="height:30px" 
(change)="filterTextChanged($event.target.value)" placeholder="Enter a 
value to search for ..." /> 
</div> 
<div style="margin-top: -6px" class="input-group"> 
<select class="form-control" (click)="publishChange($event)" size="5"> 
<option>Please select an option ...</option> 
<option *ngFor="let item of list" 
    [selected]="item.dropdownValue==selected" 
    [value]="item.dropdownValue" 
    >{{item.dropdownText}}</option> 
</select> 
</div> 

选择-dropdown.component.ts

import { Component, EventEmitter, forwardRef } from '@angular/core'; 
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 
import { SelectDropdownService } from 'common/services/select-dropdown.service'; 
import { SelectModule } from 'ng2-select'; 
import * as _ from 'lodash'; 

@Component({ 
    inputs: ['enablefilter', 'label', 'list', 'selected'], 
    outputs: ['filterTextChanged'], 
    providers: [ 
    { 
     provide: NG_VALUE_ACCESSOR, 
     useExisting: forwardRef(() => SelectDropdownComponent), 
     multi: true 
    } 
    ], 
    selector: 'app-select-dropdown', 
    templateUrl: './select-dropdown.component.html', 
    styleUrls: ['./select-dropdown.component.scss'] 
}) 
export class SelectDropdownComponent implements ControlValueAccessor { 

    propagateChange = (_: any) => { }; 
    private enablefilter: boolean; 
    private label  : string; 
    private list  : string[]; 
    private originalList: string[]; 
    private value  : any = {}; 

    /** 
    * TODO: Need to review the methods in this class which have been copied from the web 
    */ 
    constructor(
    public selectDropdownService: SelectDropdownService 
) { 
    this.enablefilter = false; // please do not change as would affect many forms! 
    } 

    /** 
    * Let the parent component know that an option has been selected 
    * @param event 
    */ 
    public publishChange(event) { 
    // let target = event.target; 
    let selectedValue = event.target.value; 
    this.propagateChange(selectedValue); 
    this.selectDropdownService.sendSelectedValue(selectedValue); 
    } 

选择-dropdown.service.ts

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

@Injectable() 
export class SelectDropdownService { 

    className: string = this.constructor['name']; 
    private dropdownValueSubject: Subject<number> = new Subject<number>(); 

    constructor() { } 

    sendSelectedValue(id: number) { 
    this.dropdownValueSubject.next(id); 
    } 

    getServiceObservable(): Observable<number> { 
    return this.dropdownValueSubject.asObservable(); 
    } 
} 

雇员-roles.component.ts - 提取物(这是父组件)

import { SelectDropdownService } from 'common/services/select-dropdown.service'; 

constructor(
    private activatedRoute  : ActivatedRoute, 
    private sabreAPIService  : SabreAPIService, 
    private selectDropdownService: SelectDropdownService 
) { } 

ngOnInit() { 
    this.enableEmployeeFilter = true; 
    this.apiEmployeeProfile = new EmployeeProfile(this.sabreAPIService, null); 
    this.readParameters(); 
    this.listEmployees(); 
    this.observeEmployeeDropdown(); 
} 

/** 
* Read URL parameters 
*/ 
private readParameters() { 
    this.activatedRoute.params 
    .subscribe((params: Params) => { 
     this.selectedEmployeeID = params['id']; 
    }); 
} 

/** 
* subscribe to change of emplyee dropdown 
*/ 
observeEmployeeDropdown() { 
    this.selectDropdownService.getServiceObservable() 
    .subscribe(selectedEmployeeID => { 
     this.selectedEmployeeID = selectedEmployeeID; 
     this.refreshRequired(); 
    }) 
} 

雇员-roles.component.html - 提取

<app-select-dropdown [enablefilter]="enableEmployeeFilter" label="Employees" [selected]="selectedEmployeeID" [list]="employeeList"> 
</app-select-dropdown> 

员工角色的形式。零件。HTML - 提取(自定义组件的2个实例)

<app-select-dropdown label="Department" [list]="payrollDepartmentsList" [selected]="selectedDeptID"></app-select-dropdown> 
<app-select-dropdown label="Role" [list]="businessRolesList" [selected]="selectedBroleID"></app-select-dropdown> 

员工角色的form.component.ts(提取物)

import { SelectDropdownService } from 'common/services/select-dropdown.service'; 


constructor(
    private formBuilder: FormBuilder, 
    private sabreAPI: SabreAPIService, 
    private selectDropdownService: SelectDropdownService 
) { } 

ngOnInit() { 
    this.apiEmployeeRole = new EmployeeRole(this.sabreAPI, null); 
    this.generateFormControls(); 
    this.listBusinessRoles(); 
    this.listPayrollDepartments(); 
    this.observeDepartmentDropdown(); 
} 

observeDepartmentDropdown() { 
    this.selectDropdownService.getServiceObservable() 
    .subscribe(selectedDeptID => { 
     this.selectedDeptID = selectedDeptID; 
    }) 
} 
+1

你可能希望得到一点帮助,除非你分享你的代码我的朋友:) – Alex

+1

啊,够公平的,谢谢 –

+0

怎么那@ AJT_82? –

回答

1

有取决于你的前提条件的几个选项:

如果您可以通过它的ID区分所选下拉值的类型 那么只需将.filter放在前面每.subscribe。例如如果员工ID始终小于100:

this.selectDropdownService.getServiceObservable() 
    .filter((selectedId: number) => selectedId <= 100) 
    .subscribe(selectedEmployeeID => { 
     this.selectedEmployeeID = selectedEmployeeID; 
     this.refreshRequired(); 
    }); 

如果你无法确定类型由只的ID。然后你需要发出的不仅仅是ID。创建服务,这也持有一种类型的接口:

interface SelectedItem { 
    id: number; 
    itemType: "employee" | "department"; 
} 

然后改变你Subject<number>Subject<SelectedItem>和您的服务的方法:

sendSelectedValue(id: number, type: string) { 
    this.dropdownValueSubject.next({id: id, itemType: type}); 
} 

getServiceObservable(type: string): Observable<number> { 
    return this.dropdownValueSubject.asObservable() 
      .filter((item: SelectedItem) => item.itemType === type) //filter by type 
      .map((item: SelectedItem) => item.id); // only return the id 
} 

现在,当您运行this.selectDropdownService.getServiceObservable()只是把相应的itemType参数:this.selectDropdownService.getServiceObservable("employee")this.selectDropdownService.getServiceObservable("department")

当然,你必须知道选择组件内的类型,你可以通过只是通过类型作为输入...

+0

谢谢,我认为这(与接口)整齐地解释了我的一个很好的解决方案。 非常感谢。 :) –

+0

所有工作 - 欢呼! –

0

我不知道你的潜力值是什么的不同选择是,但是你有可能有某种逻辑检查的价值来区分你的方案吗?

例如

subscribe(selectedDeptID => { 
    if (regex.test(selectedDeptID)) { 
     this.selectedDeptID = selectedDeptID; 
    } 
}) 

其中regex可能是你的匹配条件,或带有某种价值地图替换逻辑等

+0

非常感谢您对此的意见,谢谢。 :) –