Angular 2,自定义控件永远不会标记为脏

时间:2017-04-05 07:33:41

标签: angular angular2-template angular2-forms

我创建了一个自定义控件,我以编程方式为其提供值,因为它是基于cropper.js的图像编辑器,用户通过普通文件输入“上传”图像然后我使用File API将图像分配给我的自定义控件。

这是代码(为了便于阅读,我删除了一些cropper.js特定代码)

import {
   Component,
   OnInit,
   ViewChild,
   ElementRef,
   ViewEncapsulation,
   forwardRef
} from '@angular/core';

import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import * as Cropper from 'cropperjs';
import { Photo } from '../entities/photo';

@Component({
   selector: 'image-edit',
   templateUrl: 'image-edit.component.html',
   styleUrls: [
       'image-edit.component.scss',
       '../../../node_modules/cropperjs/dist/cropper.min.css'
],
encapsulation: ViewEncapsulation.None,
providers: [
    {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => ImageEditComponent),
        multi: true
    }
   ]
})

export class ImageEditComponent implements OnInit, ControlValueAccessor {

    get value() {
        return this.cropperImage.nativeElement.src;
    }

    set value(v: string) {
        this.cropperImage.nativeElement.src = v;
    }

    public onTouch: () => void;
    public onChange: (_: any) => void;

    @ViewChild('cropperImage')
    private cropperImage: ElementRef;

    private isDisabled: boolean;

    // cropper.js
    private cropper: Cropper;
    private cropperOptions: Cropper.CropperOptions = {};

    public ngOnInit(): void {

        // init cropper.js
    }

    public writeValue(obj: any): void {

        if (obj) {
            this.value = obj;
            this.initializeCropperOrReplaceImage();
        }
    }

    public registerOnChange(fn: any): void {
        this.onChange = fn;
    }

    public registerOnTouched(fn: any): void {
        this.onTouch = fn;
    }

    public setDisabledState(isDisabled: boolean): void {
       this.isDisabled = isDisabled;
    }

    private initializeCropperOrReplaceImage(): void {

        if (!this.isCropperInitialized) {
            this.cropper = new Cropper(this.cropperImage.nativeElement, this.cropperOptions);
            this.isCropperInitialized = true;
        }
        else {
            this.cropper.replace(this.cropperImage.nativeElement.src);
        }

        URL.revokeObjectURL(this.cropperImage.nativeElement.src);
    }
}

这是模板

<image-edit [hidden]="!photo.data" #photoData="ngModel" name="photoData" [(ngModel)]="photo.data" validateMinImageDimensions minWidth="300" minHeight="400">
 </image-edit>

不幸的是,我的控制从不肮脏或感动。 我试图扩展AbstractForm并自己设置脏,但它没有用。它仍然是不动的,没有动过。

任何想法我做错了什么?

修改

我已移除了对onTouchonChangewriteValue的调用,因为根据@ n00dl3回答和评论(请参阅此处),这不是一个好的解决方案。

1 个答案:

答案 0 :(得分:3)

你永远不会在你的组件中调用this.onTouch(),所以你的输入不能被标记为既不会被标记为触摸....

因此,为了澄清,当您考虑用户(而不是模型)更改了数据时,您需要手动调用this.onTouch(),因此您应该避免在{{1}内调用onTouch方法。

相反,您应该倾听用户在处理(不必更改)您正在处理的值时触发的最终事件(可能只是在关注常规writeValue元素之后)。

我想有一种方法可以知道用户在input库中裁剪了图像,就像在初始化选项中传递Cropper回调一样。您需要从此回调中调用complete方法,或者只要您认为输入应标记为已触摸(可能单击图像,甚至只是将其悬停)。