2016-07-29 73 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

我不确定这会成为可能。 –