Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doesn't work when an input has [readonly]="condition" data-binding #15

Open
KingMario opened this issue Apr 18, 2018 · 5 comments
Open

Comments

@KingMario
Copy link

Even if readonly is removed by angular data-binding, the accessor doesn't work.

@stenzengel
Copy link

I have the same problem.

@KingMario Did you find a workaround?

@stenzengel
Copy link

stenzengel commented Jul 11, 2018

If others are interested in a workaround, I respond to my own question:
Currently, the directive TrimValueAccessor provided in this project does not work correctly for input elements with a type or readonly attribute which is set dynamically via property binding. For these rare cases I implemented a trimming directive (based on this project) and use it in those input elements via trim and suppress TrimValueAccessor with the CSS class ng-trim-ignore.

My current implementation of this directive:

@Directive({
    providers: [{
        multi: true,
        provide: NG_VALUE_ACCESSOR,
        useExisting: TrimDirective,
    }],
    selector: "[trim]",
})
export class TrimDirective extends DefaultValueAccessor implements AfterViewInit {
    private afterViewInit = false;

    constructor(
        renderer: Renderer2,
        private elementRef: ElementRef,
        @Optional() @Inject(COMPOSITION_BUFFER_MODE) compositionMode: boolean,
    ) {
        super(renderer, elementRef, compositionMode);
    }

    ngAfterViewInit(): void {
        this.afterViewInit = true;
    }

    @HostListener("input", ["$event.target.value"])
    onInput(value: string): void {
        this.onChange(this.trimIfNeeded(value));
    }

    @HostListener("blur", ["$event.target.value"])
    onBlur(value: string): void {
        this.writeValue(value);
    }

    // tslint:disable-next-line:no-any
    writeValue(value: any): void {
        super.writeValue(this.trimIfNeeded(value));
    }

    private trimIfNeeded(value: string): string {
        return this.needsTrim() ? value.trim() : value;
    }

    private needsTrim(): boolean {
        // wait for property binding
        if (!this.afterViewInit) {
            return false;
        }

        const inputElement: HTMLInputElement = this.elementRef.nativeElement;
        return !inputElement.readOnly && ["checkbox", "radio", "password"].indexOf(inputElement.type) < 0;
    }

}

@KingMario
Copy link
Author

@stenzengel just my two cents: https://www.npmjs.com/package/ngx-trim-directive
It lies on a simple fact that Angular listens to input event to bring the view-to-model binding into being.

@stenzengel
Copy link

@KingMario Thanks. ngx-trim-directive looks like a similar implementation to my TrimDirective.

@KingMario
Copy link
Author

KingMario commented Jul 13, 2018

@stenzengel well, it's in a different way actually. The directive just sends an input event after trimming the value of the element so that the model will be updated by the ValueAccessor behind, whichever it is.

The disadvantage of the directive is that, if the user binds a callback to the input event, the callback will be called twice on each of user's keystrokes.
Since Angular is a data-driven framework, I don't see any necessity to bind to the input event during my daily development. And a debounced binding of the input event, which is usually applied in event binding, is helpful to overcome the disadvantage.

Why is another directive?
I tried the ng-trim-value-accessor of this repo (thanks @khashayar for your great job) and angular2-trim-directive, but they both have some issues regarding with FormControl states.
I fixed two of the issues of angular2-trim-directive, but figured out that it's too complex underlying the forms implementation of Angular to be touched as much as it should be.
Then I ran into the idea that sending an input event to let Angular itself maitain the model and states.

@stenzengel Thanks for you comment on my issue and if it's possible, you may fix it by submitting your codes and raising a pull request to this repo, so that this issue and discussion can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants