是否有一种简短的方法可以将RxJS Subject
或BehaviorSubject
传递给Angular 2指令以进行双向绑定?要做的很长的路要点如下:
@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
- 类指令来实现这一目标?
答案 0 :(得分:2)
我能想到的最接近的是使用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 :(得分:2)
我开始研究这样的事情,将表单控件与我的库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]
以手动导致angular为我们的指令提供所需的ControlValueAccessor
。其他类型的输入(如单选按钮和选择)需要不同的额外指令。这是因为Angular不会自动将值访问器附加到每个表单组件,只有那些也具有ngModel
,formControl
或formControlName
的组件。
如果您想加倍努力以消除对这些额外指令的需求,您必须将它们复制到您的代码中,但修改其选择器以激活您的新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,它采用了这种技术。
答案 2 :(得分:2)
我尝试了这个,它奏效了
$this->db->select('a.tgl_kejadian,b.nama_bencana,a.alamat,c.nama_kelurahan,d.nama_kecamatan,a.kerugian,a.keterangan')
->from('data_kejadian a , data_bencana b, kelurahan c, kecamatan d')
->where('a.id_bencana = b.id_bencana')
->where('a.id_daerah = c.id_kelurahan')
->where('c.id_kecamatan = d.id_kecamatan')
->where_between('a.tgl_kejadian', ['$tanggal_awal', '$tanggal_akhir']);
我不确定这是否违反任何规则,是否有错误,但似乎对我有用。我希望Angular像构建表单一样拥有一个内置的主题指令。
希望这会有所帮助
答案 3 :(得分:2)
正如您在问题中所说,这是一个简单的解决方案。 (没有比您已经提供的更简单的了)
<input type="text" [ngModel]="subject | async" (ngModelChange)="subject.next($event)" />
答案 4 :(得分:2)
可能的解决方案是BehaviorSubject的子类:
class ModelSubject<T> extends BehaviorSubject<T> {
constructor(initialValue: T) {
super(initialValue);
}
set model(value: T) {
this.next(value);
}
get model(): T {
return this.value;
}
}
用法:
组件类:
name = new ModelSubject<string>('');
组件模板:
<input [(ngModel)]="firstName.model">
答案 5 :(得分:0)
'如果山不来穆罕默德,那么穆罕默德必须去山上'
让我们从RxJS端而不是NgModule端进行处理。
此解决方案将我们限制为仅使用users
813-123-4567 | 1
users2
813-123-4567 | 1
813-123-4567 | 0
,但我认为采用这种简单解决方案是一项公平的交易。
将这段代码拍入您的polyfills.ts中。这使您可以将BehaviorSubject
的{{1}}绑定到.value
BehaviorSubject
然后像这样使用它。
ngModule
ps:我正准备在RxJS的github存储库中打开一个与此有关的请求,但结果发现有人刚刚提出了the exact same request just 3 hours ago.如果您希望实现此功能,请认可该请求。