Угловой 2, пользовательский контроль никогда не помечается как грязный


Я создал пользовательский элемент управления, которому я предоставляю значение программно, потому что это редактор изображений, основанный на cropper.js и пользователь "загружает" изображение через обычный файловый вход, а затем я использую файловый API для назначения изображения моему пользовательскому элементу управления.

Вот код (я удалил некоторые обрезки.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 и установить dirty я сам, но это не сработало. Она остается незагрязненной и нетронутой. Есть идеи, что я делаю не так?

EDIT

Я удалил вызов onTouch и onChange в writeValue, потому что в соответствии с ответом и комментарием @n00dl3 (см. Там) это не очень хорошее решение.

1 2

1 ответ:

Вы никогда не вызываете this.onTouch() в вашем компоненте, поэтому ваш вход не может быть помечен как тронутый или грязный....

Итак, чтобы уточнить, вам нужно вручную вызвать this.onTouch(), когда вы считаете, что данные были изменены пользователем (а не моделью), поэтому вы должны избегать вызова onTouch внутри метода writeValue.

Вместо этого вы должны слушать возможные события, которые ваш пользователь может вызвать при работе с (без необходимости изменения) значением, которое вы обрабатываете (возможно, сразу после фокусировки на регулярный элемент input).

Я предполагаю, что есть способ узнать, что пользователь обрезал изображение внутри вашей библиотеки Cropper, как передача обратного вызова complete, в параметрах инициализации. Вам нужно вызвать метод onTouch из этого обратного вызова или всякий раз, когда вы думаете, что ваш ввод должен быть отмечен как сенсорный (возможно, нажав на изображение или даже просто наведя на него курсор мыши).