首页 文章

实现ControlValueAccessor的Angular组件无法进行双向绑定

提问于
浏览
1

包装材质选择控件并实现ControlValueAccessor的自定义组件无法双向绑定,但成功绑定了一种方式 .

Component.ts

@Component({
    selector: 'page-size-select',
    templateUrl: 'page-size-select.component.html',
    inputs: ['pageSize'],
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: PageSizeSelectComponent,
        multi: true
    }]
})
export class PageSizeSelectComponent  implements ControlValueAccessor{

    pageSizes = [
        { id: 10, name: '10' },
        { id: 25, name: '25' },
        { id: 50, name: '50' },
        { id: -1, name: 'All' }
    ];

    innerPageSize: number;

    constructor() {}

    private changed = new Array<(value: number) => void>();
    private touched = new Array<() => void>();

    get pageSize(): number {
        return this.innerPageSize;
    }

    set pageSize(pageSize: number) {
        if (this.innerPageSize !== pageSize) {
            this.innerPageSize = pageSize;
            this.changed.forEach(f => f(pageSize));
        }
    }

    touch() {
        this.touched.forEach(f => f());
    }

    writeValue(pageSize: number) {
        this.innerPageSize = pageSize;
    }

    registerOnChange(fn: (value: number) => void) {
        this.changed.push(fn);
    }


    registerOnTouched(fn: () => void) {
        this.touched.push(fn);
    }
}

Component Template

<mat-form-field>
    <mat-select placeholder="Page Size..." [(ngModel)]="pageSize" name="pageSize" role="menu">
        <mat-option *ngFor="let opt of pageSizes" [value]="opt.id" role="menuitem">
            {{opt.name}}
        </mat-option>
    </mat-select>
</mat-form-field>

用法成功:

<page-size-select [pageSize]="pagination.pageSize" ></page-size-select>

使用失败:

<page-size-select ([pageSize])="pagination.pageSize" ></page-size-select>

当单向绑定成功时,它成功将 pagination.pageSize 值读入底层选择控件,并将所选选项设置为该值 . 然而,目标是双向绑定,但是当使用该语法时,绑定既不读取也不写入 pagination.pageSize .

1 回答

  • 1

    首先,您有语法错误:

    ([pageSize])="pagination.pageSize"
    

    是错的 . 方括号在外面,而不是圆括号:

    [(pageSize)]="pagination.pageSize"
    

    另外,我也不确定你的 ControlValueAccessor 实现是否正确 . 界面的目的是使组件与Angular表单控件一起使用 . 当您使用 ngModel 时,您正在使用 FormControl 而未实现它 . 因此 writeValue 应该调用已注册的更改函数 - 即组件的更改将如何反映回已注册的 FormControl ,这必须发生以便与 ngModel 进行写入绑定 . 你不能拥有多个 FormControl ,所以你不必管理多个订阅'. Likewise you need to call your registered touched function - typically when the component is blurred. I'已经完成了与你正在做的非常类似的事情,而我的 ControlValueAccessor 实现看起来像这样(几乎是一个Angular示例的剪切和粘贴) :

    writeValue(value: any) {
        if (value !== this._value) {
            this._value = value; // this is my internal value model
            this._onChange(value);
            this.change.emit(this._value); // I fire change events
        }
    }
    
    _onChange: (value: any) => void = () => {};
    registerOnChange(fn: (value: any) => void) {
        this._onChange = fn;
    }
    
    _onTouched: () => any = () => {};
    registerOnTouched(fn: any) {
        this._onTouched = fn;
    }
    
    // if you implement disabled functionality you need this function
    setDisabledState(value: boolean): void {
        this._disabled = value; // this is my internal disabled model
    }
    
    // and my component's (blur) handler
    onBlur() {
        this._onTouched();
        this.blur.emit(this._value); // I fire blur events
    }
    

相关问题