2017-04-12 96 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

非常感謝您對此的意見,謝謝。 :) –