代码之家  ›  专栏  ›  技术社区  ›  rism

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

  •  1
  • rism  · 技术社区  · 6 年前

    包装材质选择控件并实现ControlValueAccessor的自定义组件无法双向绑定,但成功地绑定了单向。

    组件

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

    组件模板

    <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 值,并将所选选项设置为该值。然而,目标是双向绑定,但是当使用该语法时,绑定既不读取也不写入 分页.pagesize .

    1 回复  |  直到 6 年前
        1
  •  1
  •   G. Tranter    6 年前

    首先,出现语法错误:

    ([pageSize])="pagination.pageSize"
    

    是错的。方括号放在外侧,而不是圆括号:

    [(pageSize)]="pagination.pageSize"
    

    另外,我不确定你 ControlValueAccessor 实现也是正确的。接口的目的是使组件与角形控件一起工作。你正在使用 FormControl 当你使用 ngModel . 所以 writeValue 应该调用已注册的更改函数-即组件的更改如何反映回已注册的 形式控制 必须发生才能写入绑定 NGM模型 . 你不能不止一个 形式控制 ,因此不需要“管理多个订阅”。同样,您需要调用已注册的触摸函数-通常在组件模糊时。我做了一些和你很相似的事情 控制值访问器 实现如下所示(几乎是角度示例的剪切和粘贴):

    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
    }