1

Consider the following code :

 <button cdtSaving type="submit" class="btn btn-default" [disabled]="!canSave()">Save</button>

with cdtSaving an attribute directive :

@Directive({
  selector: '[cdtSaving]'
})
export class SavingDirective implements OnInit, OnDestroy {

  private subscription: Subscription;

  constructor(private _loaderService: LoaderService, private _elRef: ElementRef, private _renderer: Renderer2) { }

  ngOnInit() {
    // subscribe to the service state to hide/show the loader
    this.subscription = this._loaderService.loaderState
      .subscribe((state: LoaderState) => {
        this._renderer.setAttribute(this._elRef.nativeElement, 'disabled', state.show ? 'true' : null);
        console.log(`state changed:${state.show} for element ${this._elRef.nativeElement.textContent}`);
      });
  }

  ngOnDestroy() {
    // unsubscribe
    this.subscription.unsubscribe();
  }
}

Basically whenever the observable next() is called, we enable or disable the button (nativeElement).

The problem is that when setting the disabled attribute to null, the canSave method is no longer taken into account.

So instead I would like to set a flag to true/false in the directive instead of setting the disabled attribute and then I would read that flag like this :

 <button cdtSaving type="submit" class="btn btn-default" [disabled]=" cdtSaving.myFlag || !canSave()">Save</button>

Currently cdtSaving.myFlag wouldn't work but maybe there's a way to achieve that with Angular ?

1 Answer 1

1

If you want to access the directive internal state, you need to set the exportAs metadata in the @Directive() decorator.

Also there is no need for imperative managment of the disabled attribute with ElementRef and Renderer. Just use the @HostBinding decorator.

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

@Directive({
  selector: '[cdtSaving]',
  exportAs: 'cdtSaving'
})
export class SavingDirective {
  myFlag = false
}

Usage:

<button cdtSaving  #dir="cdtSaving" [disabled]="dir.myFlag">Save</button>
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the syntax tip, it looks neater like this. However it does not solve my problem. First, if you do this.disabled = state === 'show' the button will always be disabled. Instead it should be this.disabled = state === 'show' ? 'true' : null where disabledis a string instead of boolean. But again, I'm back to my issue, which is the canSave method is no longer taken into account once disabledwas overwritten by the directive.
check out my edit, also please upvote my answer since we're having a nice conversation :) @HostBinding() now takes into account the [disabled] input and the value emitted by the loaderService.
Maybe I need to be more explicit with what I'm trying to achieve. When the loaderState returns true, the button should be disabled by the cdtSaving directive. However when the loaderState returns false, the button should be disabled by the canSave method (directly bound in the HTML). I don't see how your edited code solves that problem. Am I missing something ? Thanks for helping !
As long as the disabled attribute is modified by the directive, this will never work. The canSave() method (which code should not be in the directive) will always get removed and replaced by null or true. Instead I'm looking for a way to access the directive's disabled property from the disabled attribute of the button (as explained in the OP). I'm not sure if this is possible to do but it seems the only way to achieve what I want.
That's exactly what I wanted ! I didn't know about the exportAs metadata. I've implemented the changes and it works as expected. Many thanks for helping !
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.