1

I'm trying to create a custom directive for disabling a form field but it's not working.

import { Directive, Input, ElementRef, Renderer2 } from '@angular/core';

@Directive({
  selector: '[appCustomDisable]',
  })
 export class CustomDisableDirective {
@Input() appCustomDisable: boolean;
constructor(private el: ElementRef, private renderer: Renderer2) {}

ngOnChanges() {
if (this.appCustomDisable) {
  this.renderer.setProperty(this.el.nativeElement, 'disabled', 
this.appCustomDisable);
} else {
  this.renderer.setProperty(this.el.nativeElement, 'disabled', 
this.appCustomDisable);
 }
}
}

I also tried the above using Render from '@angular/core'

 this.renderer.setElementAttribute(this.el.nativeElement, 'disabled', 
'true');

in app.component.html I'm using like [appCustomDisable]="myVar"

Stackblitz link https://stackblitz.com/edit/angular-lxb661

Anil Kumar Reddy A
  • 665
  • 11
  • 29
  • 1
    What kind of element are you placing the directive on? Have you added styles to the element which apply when it's disabled? How do you know it's not working? – Christian Mar 25 '19 at 14:21
  • And what's wrong with just `[disabled]="someBoolean"` which doesn't need any custom directive? – JB Nizet Mar 25 '19 at 14:22
  • Nvm, I can see you're trying to disable a material form control that way. What you're doing is incorrect, as the Material team have already implemented the logic of being able to disable their controls. Look into FormsModule or ReactiveFormsModule and how to disable controls respectively. – Christian Mar 25 '19 at 14:23
  • I provided u the stackbliz link. U can get everything from that. I know its not working bcoz the form is not getting disabled. – Anil Kumar Reddy A Mar 25 '19 at 14:23
  • I know how to use [disabled]="someBoolean", but i want a custom directive for that where i want to implement some complex functions inside it – Anil Kumar Reddy A Mar 25 '19 at 14:25
  • @AnilKumarReddyA implement the function on your component and send the result in the disabled attribute. –  Mar 25 '19 at 14:26
  • @trichetriche i know that one, but i have to use it in many other places. i want a custom directive for that purpose – Anil Kumar Reddy A Mar 25 '19 at 14:28
  • Well seems like you can't have it. As said before, look into Angular form types to see how to handle the disabling of the inputs, and create a service or an utils function that does the heavy lifting. –  Mar 25 '19 at 14:30
  • @trichetriche see i already went through this. Even this isn't working https://angular.io/api/forms/ControlValueAccessor – Anil Kumar Reddy A Mar 25 '19 at 14:32
  • The control value accessor allows you to **create Angular controls**, not disable them. That's in fact what you are facing : Material has made a control value accessor on their inputs, lockinf it for you. Check template driven and reactive forms, not the control value accessor. –  Mar 25 '19 at 14:35

2 Answers2

1

Since your are using MatInput your Code wont work for that. But you can adapt it simply like:

import { Directive, ElementRef, Input, Renderer2, Optional, S } from '@angular/core';
import { MatInput } from '@angular/material'

@Directive({
  selector: '[appCustomDisable]'
})
export class CustomDisableDirective {
  @Input() appCustomDisable: string;
  constructor(@Optional() private matInput: MatInput, private el: ElementRef, private renderer: Renderer2) { }

  ngOnChanges() {
    // Find Input
    let input: any;
    if (this.matInput) {
      // It's a Material Input
      input = this.matInput;
    }
    else {
      // Its a native Input
      if (this.el.nativeElement && this.el.nativeElement.tagName && this.el.nativeElement.tagName === "INPUT") {
        input = this.el.nativeElement;
      } else {
      // No Input found
      // return or throw error
      return;
      }
    }

    if (this.appCustomDisable === 'hide') {
      this.renderer.setStyle(this.el.nativeElement, 'display', 'none')
    } else if (this.appCustomDisable === 'view') {
     console.log(input);
     input.disabled = true;
    }
    else {
      this.renderer.setStyle(this.el.nativeElement, 'display', 'block')
    }
  }

}

MullisS
  • 238
  • 2
  • 11
1

Apparently, what you want to disable is the MatInput directive that is present on the same element. So, just inject it into your component, and disable it:

import { Directive, Input } from '@angular/core';
import { MatInput } from '@angular/material';

@Directive({
  selector: '[appCustomDisable]'
})
export class CustomDisableDirective {

    @Input() appCustomDisable : boolean;
    constructor(private matInput: MatInput) {}

    ngOnChanges() {
        this.matInput.disabled = this.appCustomDisable;
    }

}

Demo

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255