2016-07-29 34 views
22

Gibt es eine kurze und einfache Möglichkeit, ein RxJS Subject oder BehaviorSubject an eine Angular 2-Direktive für Zwei-Wege-Bindung zu übergeben? Der lange Weg, es zu tun wäre, wie folgt:Wie binde ich mein eigenes RxJS mit einem [(ngModel)]?

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

Ich möchte in der Lage sein, so etwas zu tun:

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

ich das async Rohr glauben ist nur ein Weg, so Das ist nicht genug. Bietet Angular 2 einen kurzen und einfachen Weg dies zu tun? Angular 2 verwendet auch RxJS, daher erwartete ich eine gewisse inhärente Kompatibilität.

Könnte ich vielleicht eine neue ngModel ähnliche Anweisung erstellen, um dies zu ermöglichen?

+1

Was erwarten Sie, wenn sich der Wert des Eingangs ändert? "Subject" ist in eine Richtung. '[ngModel] =" subject | async "(ngModelChange) =" subject.next ($ event) "' könnte funktionieren –

+2

@ GünterZöchbauer ['Subject'] (http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html) ist zwei-Wege, obwohl. Es ist sowohl ein ['Observer] (http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObserverDoc.html) und ein [' Observable'] (http://reactivex.io/rxjs/class/es6/ Observable.js ~ Observable.html) Ich bin auch damit einverstanden, dass dies immer ein ['BehaviorSubject'] ist (http://reactivex.io/rxjs/class/es6/BehaviorSubject.js~BehaviorSubject.html), wenn es so ist hilft (weil das eine Methode hat, auf den aktuellen Wert zuzugreifen) – mhelvens

+0

Haben Sie das jemals herausgefunden? – DarkNeuron

Antwort

1

Die nächstgelegene ich denken kann, ist eine Formcontrol zu verwenden:

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

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

ich angefangen habe, einen Blick in so etwas wie diese ng-app-state Formular-Steuerelemente mit meiner Bibliothek zu integrieren. Wenn Sie der Typ sind, der gerne generischen, bibliotheksähnlichen Code erstellt, dann lesen Sie weiter. Aber Vorsicht, das ist lang! Am Ende sollten Sie in der Lage sein, dies in Ihre Templates zu verwenden:

<input [subjectModel]="subject"> 

ich ein Proof-of-Concept für die erste Hälfte dieser Antwort gemacht haben, und die zweite Hälfte glaube ich, ist richtig, aber seien Sie gewarnt, dass keiner der tatsächlichen Codes in dieser Antwort getestet wird. Es tut mir leid, aber das ist das Beste, was ich jetzt zu bieten habe. :)

Sie können Ihre eigene Direktive namens subjectModel schreiben, um einen Betreff mit einer Formularkomponente zu verbinden. Im Folgenden sind die wesentlichen Teile, minus Dinge wie Aufräumen. Es stützt sich auf die ControlValueAccessor Schnittstelle, also schließt Winkel die notwendigen Adapter ein, um dieses bis zu allen StandardHTML Formularelementen, und anzubringen es funktioniert mit allen möglichen Formsteuerungen, die Sie im wilden finden, solange sie ControlValueAccessor benutzen (das ist die empfohlene Praxis).

@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); 
     }); 
    } 
} 

Wir könnten hier aufhören, und Sie werden diese in der Lage sein, in die Vorlagen zu schreiben:

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

Das zusätzliche [ngDefaultControl] die benötigte ControlValueAccessor zu unserer Richtlinie zu schaffen Winkel manuell verursachen vorhanden ist. Andere Arten von Eingängen (wie Radio-Buttons und Selects) würden eine andere Extra-Direktive benötigen. Dies liegt daran, dass Angular nicht automatisch Wert-Accessoren an jede Formularkomponente anfügt, sondern nur an diejenigen, die auch eine ngModel, formControl oder formControlName haben.

Wenn Sie die Extra-Meile nutzen möchten, um die zusätzlichen Anweisungen zu umgehen, müssen Sie sie im Wesentlichen in Ihren Code kopieren, aber ihre Selektoren ändern, um sie für Ihre neue subjectModel zu aktivieren. Dies ist das völlig ungetestet Teil, aber ich glaube, dass Sie dies tun könnte:

// 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 {} 

Kredit für mein Verständnis davon geht zu ngrx-forms, die diese Technik employes.

+0

Sieht interessant aus. War diese Lösung verfügbar, als ich die Frage zum ersten Mal gestellt habe? --- Ich fürchte, ich werde keine Zeit haben, das zu überprüfen. Ich benutze React in meinem neuen Job, und meine Gedanken sind jetzt wirklich nicht im Winkel. --- Wenn jemand anders dies bestätigen könnte, würde ich die Antwort gerne annehmen. – mhelvens

+0

Ich bin mir nicht sicher, wann das möglich gewesen wäre. –