2016-07-29 19 views
22

Czy istnieje krótki i prosty sposób przekazania RxJS Subject lub BehaviorSubject do dyrektywy Angular 2 dotyczącej wiązania dwukierunkowego? Długa droga do zrobienia byłoby następująco:Jak dwukierunkowo związać mój własny podmiot RxJS z [(ngModel)]?

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

Chciałbym móc zrobić coś takiego:

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

wierzę rura async jest tylko jedna droga, więc To nie wystarczy. Czy Angular 2 zapewnia krótki i prosty sposób na zrobienie tego? Angular 2 używa również RxJS, więc spodziewałem się, że będzie to nieodłączna kompatybilność.

Czy mógłbym stworzyć nową dyrektywę w stylu ngModel, aby było to możliwe?

+1

Czego oczekujesz, gdy zmieni się wartość sygnału wejściowego? "Przedmiot" jest jednokierunkowy. '[ngModel] =" subject | async "(ngModelChange) =" subject.next ($ event) "' może działać –

+2

@ GünterZöchbauer ['Subject'] (http://reactivex.io/rxjs/class/es6/Subject.js~Subject.html) jest dwukierunkowe. ['Observer'] (http://reactivex.io/rxjs/class/es6/MiscJSDoc.js~ObserverDoc.html) i [' Observable'] (http://reactivex.io/rxjs/class/es6/ Observable.js ~ Observable.html). Nie przeszkadza mi też to, że to zawsze "BehaviorSubject" (http://reactivex.io/rxjs/class/es6/BehaviorSubject.js~BehaviorSubject.html), jeśli pomaga (ponieważ ma to metodę dostępu do bieżącej wartości) – mhelvens

+0

Czy kiedykolwiek to rozgryzłeś? – DarkNeuron

Odpowiedz

1

Najbliżej mogę myśleć jest użycie 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

Zacząłem patrząc na coś takiego zintegrowania kontroli formularzy z mojej biblioteki ng-app-state. Jeśli jesteś typem, który lubi tworzyć bardzo ogólny, podobny do biblioteki kod, czytaj dalej. Ale uwaga, to jest długie! W końcu powinieneś być w stanie wykorzystać to w swoich szablonach:

<input [subjectModel]="subject"> 

Zrobiłem proof-of-concept dla pierwszej połowie tej odpowiedzi, a druga połowa wierzę, jest poprawna, ale ostrzegamy że żaden z rzeczywistych kodów napisanych w tej odpowiedzi nie jest testowany. Przykro mi, ale to najlepsze, co mam teraz do zaoferowania. :)

Możesz napisać własną dyrektywę o nazwie subjectModel, aby połączyć temat ze składnikiem formularza. Poniżej znajdują się podstawowe części, minus rzeczy takie jak czyszczenie. Bazuje on na interfejsie ControlValueAccessor, więc Angular zawiera niezbędne adaptery do podłączenia do wszystkich standardowych elementów formularzy HTML: i będzie działał z dowolnymi niestandardowymi formantami, które znajdziesz w środowisku naturalnym, o ile używają one ControlValueAccessor (która jest zalecaną praktyką).

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

Mogliśmy zatrzymać tutaj, a będziesz w stanie napisać to w szablonach:

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

To dodatkowy [ngDefaultControl] istnieje ręcznie spowodować kątowe, aby zapewnić wymaganą ControlValueAccessor do naszej dyrektywy. Inne rodzaje danych wejściowych (takie jak przyciski i wybory) wymagałyby innej dodatkowej dyrektywy. Wynika to z faktu, że Angular nie dołącza automatycznie wartości dodawanych do każdego komponentu formularza, tylko te, które mają także ngModel, formControl lub formControlName.

Jeśli chcesz zrobić więcej, aby wyeliminować potrzebę stosowania tych dodatkowych dyrektyw, musisz zasadniczo skopiować je do kodu, ale zmodyfikuj selektory, aby aktywować dla nowego subjectModel. Jest to całkowicie niesprawdzone część, ale wierzę, że można to zrobić:

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

kredytowych dla mojego rozumienia tego idzie do ngrx-forms, która zatrudnia tej techniki.

+0

Wygląda interesująco. Czy to rozwiązanie było dostępne, gdy zadałem to pytanie? --- Obawiam się, że nie będę miał czasu na zweryfikowanie tego. Używam Reacta w mojej nowej pracy, a mój umysł naprawdę nie jest teraz w przestrzeni kątowej. --- Jeśli ktoś mógłby zweryfikować, chętnie zaakceptuję odpowiedź. – mhelvens

+0

Nie jestem pewien, kiedy to byłoby możliwe. –

Powiązane problemy