好吧,我想我明白了。或者至少,在我目前的理解水平上,我有一个可行的解决方案。如果你看到优化的方法,请告诉我。
部分问题是让controlValueAccessor在不破坏其本机功能的情况下使用ng select。具体地说,当您使用ng select作为一个预输入控件并选择一个值时,它应该添加一个标记,显示到目前为止您选择的值。尝试实现ControlValueAccessor接口会破坏这一点,可能是因为它重写了与ng select一起提供的接口onchange处理程序。
所以我所采取的方法结合了我在问题中所看到和提到的两种方法。我的ng select实现现在位于一个嵌套组件中,该组件被封装在一个包装组件中,该组件上有controlValueAccessor。
这使得以下结构变得粗糙:
app.component (test harness)
people-search.component (ControlValueAccessor)
namelookup.component (@Outputs an EventEmitter)
将namelookup从原始项目中迁移出来,然后只需要进行一些小的更改。我从其HTML中编辑了[FormGroup]=“父”部分,因为这不再是控件上下文的一部分。
在namelookup.component.html中,我添加了:
<ng-select
...
(change)="handleSelection($event)"
...>
在namelookup.component.ts中
@Component({
selector: 'ps-namelookup',
templateUrl: './namelookup.component.html',
styleUrls: ['./namelookup.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush, // new code
})
export class NameLookupComponent implements OnInit {
...
@Output() selectedValue = new EventEmitter<string>();
handleSelection(event) {
console.log('handleSelection in NameLookupComponent fired');
this.selectedValue.emit(event);
}
...
}
然后创建了一个新的包装器people-search.component,它实现了一个基本的controlValueAccessor
as outlined
in many
examples
.
其要点是:
在模板中为CVA包装器中的子组件发出的事件(selectedValue)提供一个输出挂钩。
@Component({
selector: 'ps-people-search',
template: `
<ps-namelookup (selectedValue)="handleselectedvalue($event)"></ps-namelookup>
`,
...
向类定义中添加方法并实现CVA。
export class PeopleSearchComponent implements ControlValueAccessor {
....
private propagateChange = (_: any) => { };
handleselectedvalue($event) {
console.log('handleselectedvalue fired');
console.log($event);
this.data = $event[0].id;
this.propagateChange(this.data);
console.log('handling change event and propagating ' + this.data);
}
至少不执行Registeronchange和RegisterOntouched。编译器可能会坚持使用其他一些。
最后,在test harness app.component.html中,为了在表单上显示值,以便我知道所选值已被传递回,我添加了:
{{form.value | json}}
在app.component.ts中提供了一个stand-in-formgroup对象。
public form: FormGroup;
constructor(private fb: FormBuilder){
console.log('constructing test harness appComponent');
this.form = this.fb.group({});
}
这是一个回答我根本问题的答案,可能还有其他的好方法来回答这个问题。当然欢迎反馈、优化和更正。