【问题标题】:Angular 2, custom control is never marked as dirtyAngular 2,自定义控件永远不会被标记为脏
【发布时间】:2017-08-30 16:26:23
【问题描述】:

我创建了一个自定义控件,我以编程方式为其提供值,因为它是基于cropper.js 的图像编辑器,用户通过普通文件输入“上传”图像,然后我使用文件 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 并将自己弄脏,但它没有用。它保持不脏和未受影响。

任何想法我做错了什么?

编辑

我在writeValue 中删除了对onTouch 和onChange 的调用,因为根据@n00dl3 的回答和评论(见那里)这不是一个好的解决方案。

【问题讨论】:

  • 请添加您的组件模板。

标签: angular angular2-template angular2-forms


【解决方案1】:

您永远不会在您的组件中调用this.onTouch(),因此您的输入不能被标记为已触摸也不脏......

所以澄清一下,当您认为数据已被用户(而不是模型)更改时,您需要手动调用this.onTouch(),因此您应该避免在writeValue方法内调用onTouch。

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

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

【讨论】:

  • 就是这样,我需要在writeValue 中致电onTouch() 和onChange(obj)。我用代码更新了问题
  • 在writeValue中使用这些没有意义,writeValue在模型更新视图时被调用,你应该在裁剪图像时调用这些回调。
  • 感谢您的额外输入,我会看看它
  • @n00dl3 你知道我在哪里可以获得更多关于何时调用writeValue 的详细信息。在一些教程中,我发现它也调用了更改回调,而在其他教程中则没有。有人说writeValue 是在程序更改时调用的,而不是用户更改。只是寻找一些“最终”定义。谢谢
  • @n00dl3 感谢您的更新。我已根据我的要求将其置于输入的模糊事件中,并且它按我的预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
  • 2012-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-14
  • 1970-01-01
相关资源
最近更新 更多