2016-07-29 71 views
22

是否有簡短的方法將RxJS SubjectBehaviorSubject傳遞給Angular 2指令以進行雙向綁定?長的方式做這將是如下:如何雙向綁定我自己的RxJS受[[ngModel]]約束?

@Component({ 
    template: ` 
     <input type="text" [ngModel]="subject | async" (ngModelChange)="subject.next($event)" /> 
    ` 
}) 

我希望能夠做這樣的事情:

@Component({ 
    template: ` 
     <input type="text" [(ngModel)]="subject" /> 
    ` 
}) 

我相信async管道是單向的,所以這還不夠。 Angular 2是否提供了一種簡單而簡單的方法來實現這一點? Angular 2也使用RxJS,所以我預計它會有一些固有的兼容性。

我可以創建一個新的類似ngModel的指令來實現這一點嗎?

+1

當輸入值發生變化時,您會發生什麼? 「主題」是單向的。 '[ngModel] =「subject | async」(ngModelChange)=「subject。下一個($ event)「'可能工作 –

+2

@GünterZöchbauer['Subject'](http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html)是雙向的,它既是一個['Observer'](http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObserverDoc.html)和['Observable'](http://reactivex.io/rxjs/class/es6/ Observable.js〜Observable.html)。如果它總是[[BehaviorSubject]](http://reactivex.io/rxjs/class/es6/BehaviorSubject.js~BehaviorSubject.html),我也很好。幫助(因爲有一個方法來訪問當前值) – mhelvens

+0

你有沒有想過這個? – DarkNeuron

回答

1

我能想到的最接近的是使用FormControl:

import { FormControl } from '@angular/forms'; 

@Component({ 
    template: '<input [formControl]="control">' 
}) 
class MyComponent { 
    control = new FormControl(''); 
    constructor(){ 
     this.control.valueChanges.subscribe(()=> console.log('tada')) 
    } 
} 
1

我已經開始尋找到這樣的事情表單控件集成與我的圖書館ng-app-state。如果你喜歡製作非常通用的類型庫,然後閱讀。但要小心,這很長!最後,你應該能夠在你的模板使用此:

<input [subjectModel]="subject"> 

我已經做了驗證的概念,這個答案的前半部分,後半部分我認爲是正確的,但被警告沒有寫在這個答案中的實際代碼被測試。我很抱歉,但這是我現在要提供的最好的。 :)

您可以編寫自己的指令,稱爲subjectModel將主題連接到表單組件。以下是關鍵部分,減去清理之類的東西。它依賴於ControlValueAccessor接口,因此Angular包含必要的適配器,以將其與所有標準HTML表單元素掛鉤,只要它們使用ControlValueAccessor(它會與您在野外找到的任何自定義表單控件一起使用)是推薦的做法)。

@Directive({ selector: '[subjectModel]' }) 
export class SubjectModelDirective { 
    private valueAccesor: ControlValueAccessor; 

    constructor(
     @Self() @Inject(NG_VALUE_ACCESSOR) 
     valueAccessors: ControlValueAccessor[], 
    ) { 
     this.valueAccessor = valueAccessors[0]; // <- this can be fancier 
    } 

    @Input() set subjectModel(subject: Subject) { 
     // <-- cleanup here if this was already set before 
     subject.subscribe((newValue) => { 
      // <-- skip if this is already the value 
      this.valueAccessor.writeValue(newValue); 
     }); 
     this.valueAccessor.registerOnChange((newValue) => { 
      subject.next(newValue); 
     }); 
    } 
} 

我們可以停在這裏,你就可以在你的模板來寫:

<input [subjectModel]="subject" [ngDefaultControl]> 

這額外[ngDefaultControl]存在手動引起的角度,以提供所需ControlValueAccessor我們的指令。其他類型的輸入(如單選按鈕和選擇)需要一個不同的額外指令。這是因爲Angular不會自動將值訪問器附加到每個表單組件,只有那些也有ngModel,formControlformControlName的值。

如果您想額外花費一些時間來消除對這些額外指令的需求,您必須將其基本上覆制到您的代碼中,但修改它們的選擇器以激活您的新subjectModel。這是沒有經過測試的一部分,但我相信你可以這樣做:

// This is copy-paste-tweaked from 
// https://angular.io/api/forms/DefaultValueAccessor 
@Directive({ 
    selector: 'input:not([type=checkbox])[subjectModel],textarea[subjectModel]', 
    host: { 
     '(input)': '_handleInput($event.target.value)', 
     '(blur)': 'onTouched()', 
     '(compositionstart)': '_compositionStart()', 
     '(compositionend)': '_compositionEnd($event.target.value)' 
    }, 
    providers: [DEFAULT_VALUE_ACCESSOR] 
}) 
export class DefaultSubjectModelValueAccessor extends DefaultValueAccessor {} 

信貸對我的這種理解去ngrx-forms,其全球員工總數這種技術。

+0

看起來很有趣。當我第一次問這個問題時,這個解決方案是否可用? ---恐怕我沒有時間去驗證這一點。我在新工作中使用了React,現在我的思維真的不在Angular空間中。 ---如果別人可以驗證,我很樂意接受答案。 – mhelvens

+0

我不確定這會成爲可能。 –