Skip to content

Directive that extends from DefaultValueAccessor applies to all controls instead of respecting the selector. Host's events not being trigerred #9146

@daniel-a-melo

Description

@daniel-a-melo
  • I'm submitting a ...
  • bug report
  • feature request
  • support request => Please do not submit support request here, see note at the top of this template.

Current behavior

I am implementing masked input for text boxes. With ng1 I used to implement using ngModelController's $parsers and $formatters. An example implementation can be found at https://plnkr.co/HQSyZkr4VgezzcSNWnuJ (ng1) . On this example the input displays uppercase text and stores (via ngModel) lowercase text.

I managed to replicate the same behavior using DefaultValueAccessor as in in the following snippet (based on code posted on example posted on other issue). This code works on beta 17 but doesn't work on RC1. Obviously the beta 17 version differs on the import statements.

The code samples for beta 17 and RC 1 may be found here:

https://plnkr.co/yDvm2x3YiKY6LKhRSzQ3 (Beta 17 - It works)
http://plnkr.co/eAEML8VTnvNo78IFGgSB (RC1 - It doesn't work)

With RC1 the directive applies to all input controls in the form instead of respecting the selector input[type=uppercase]. Futhermore the input event is never triggered and nor the method writeValue

import {Directive, Provider, forwardRef, Renderer, ElementRef} from '@angular/core';
import {DefaultValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, Validator, Control} from '@angular/common';

const FORMAT_CPF_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, {
    useExisting: forwardRef(() => UpperCaseValueAccessor),
    multi: true
});

@Directive({
    selector: 'input[type=uppercase]',
    host: {
        "maxlength": "14",
        "minlength": "14",
        "min": "0",
        "type": "text",
        "(input)": "input($event.target.value)",
        "(blur)": "blur()"
    },
    bindings: [FORMAT_CPF_VALUE_ACCESSOR]
})
export class UpperCaseValueAccessor  extends DefaultValueAccessor  {

    constructor(renderer: Renderer, elementRef: ElementRef) {
        elementRef.nativeElement.style.backgroundColor = 'yellow';
        super(renderer, elementRef);
    }

    ngAfterViewInit() { }

    blur() {
        this.onTouched();
    }

    input(value : string) {
        // Write back to model
        if (value) {
            value = value.toLowerCase();
            //write formatted to to control view
            (<any>this)._elementRef.nativeElement.value = value.toUpperCase();
        }
        this.onChange(value);
    }

    writeValue(value: any): void {
        // Write to view
        if (value) {
            value = value.toUpperCase();
        }
        super.writeValue(value);
    }
}

The code for component using the directive :

import {Component} from '@angular/core';
import {ControlGroup, Control, FormBuilder, Validators} from '@angular/common';
import {UpperCaseValueAccessor} from './uppercase-directive';

interface FormData {
    name : string;
    uppercaseText: string;
}

@Component({
  selector: 'my-app',
  providers: [],
  template: `
        <form [ngFormModel]="dataForm">
            <label for="inputName">Name</label>
            <input type="text" [(ngModel)]="data.name" [ngFormControl]="dataForm.controls.name" id="inputName" placeholder="Name">
            <div [hidden]="dataForm.controls.name.valid || dataForm.controls.name.pristine" class="alert alert-danger">Name is required</div>

            <p></p>

            <label for="upperText">Uppercase text</label>
            <input type="uppercase" [(ngModel)]="data.uppercaseText" [ngFormControl]="dataForm.controls.uppercaseText" id="upperText" placeholder="Something">

            <p></p>

             <button [disabled]="!dataForm.valid" (click)="submitForm()">Submit</button>
             <button (click)="resetForm()">Reset</button>

             <p></p>

             <pre>{{data | json}}</pre>
        </form>
  `,
  directives : [UpperCaseValueAccessor],
})
export class App {
    dataForm : ControlGroup; 
    data : FormData = <FormData> {};

    constructor(private fb : FormBuilder) {
        this.buildForm();
    }

    buildForm() {
        this.dataForm = this.fb.group({
            name : ['', Validators.required],
            uppercaseText : ['']
        });
    }

    submitForm() {
        console.log(this.dataForm.value);
    }

    resetForm() {
        this.buildForm();
    }
}

Expected/desired behavior

https://plnkr.co/yDvm2x3YiKY6LKhRSzQ3 (Beta 17 - It works)
http://plnkr.co/eAEML8VTnvNo78IFGgSB (RC1 - It doesn't work)

  • What is the expected behavior?

The directive would apply only to componenet specified in the selector input[type=uppercase], the event input would be triggered and the method writeValue would be invoked.

  • Please tell us about your environment:
  • Angular version: 2.0.0-RC.1
  • Browser: [Chrome 51]
  • Language: [all | TypeScript 1.8.10]

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions