Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular @input value reaching late in constructor

I am writing a directive which has 2 @Input() variables and takes value from who ever using that directive like components.

Everything is fine. The only problem is that when there is a Observable.subscribe in the constructor, then @Input values are available in constructor and without Observable.subscribe the @Input() variable values are undefined

I know the better way to get @Input() variable of a directive is to access them inside a life cycle hook like ngOnInit or ngOnChange but my question is: why is this available in some cases and not available in other cases in a directive.

<div authorizedme
     [permission]="'manager'"
     [auth]="department"
     class="col-2 data-object-link">your salary is $90,000,0000

directive

If inside the directive's constructor below the subscribe code is there, then permission and auth is available, and if it's commented out then both of the @Input() variables are undefined.

this.userService.getUser().subscribe((user) => {
  this.user = user;
  if (this.authorized()) {
    this.elementRef.nativeElement.style.display = 'block';
  }
});

Below is the entire directive code

@Directive({
  selector: '[authorizedme]'
})
export class AuthorizedDirective implements OnInit {

  @Input() permission: string;
  @Input() auth: string;
  private user: any;

  constructor(private elementRef: ElementRef, private currentUserService: userService) {
    this.elementRef.nativeElement.style.display = 'none';
    this.currentUser = this.userService.userAuthorizations;

    /*this.currentUserService.getUser().subscribe((user) => {
      this.user = user;
      if (this.authorized()) {
        this.elementRef.nativeElement.style.display = 'block';
      }
    });*/

  }

  public authorized() {
   return this.user || authorize;
  }
}
like image 672
Aniruddha Das Avatar asked Jun 18 '26 20:06

Aniruddha Das


2 Answers

Don't try to access @Input()s in the constructor, do it in the ngOnInit life-cycle hook. The constructor has almost nothing to do with the Angular application life-cycle.

From another question:

Implement this interface to execute custom initialization logic after your directive's data-bound properties have been initialized. ngOnInit is called right after the directive's data-bound properties have been checked for the first time, and before any of its children have been checked. It is invoked only once when the directive is instantiated.

Furthermore, the constructor is not an Angular feature, it's a TypeScript feature. To quote directly from Günter in his comment to the above-linked answer:

Contstructors are not related to Angular2, they are a TypeScript feature. Lifecycle hooks are called by Angular after some initialization took place or when some event happend to allow the component act on certain situations and to give it the chance to do some tasks at proper times.

It's to be expected, then, that your data-bound properties are not yet available in the constructor.

like image 192
msanford Avatar answered Jun 20 '26 09:06

msanford


This is a classic case of lifecycle hooks and asynchronous processing!

Taking it step by step:

  1. Angular instantiates the directive
  2. Angular processing things
  3. While processing it calls LifeCycle hooks to let you know what is happening.

Putting it all together what this means is Angular instantiates your directive AuthorizedDirective with its constructor function. In the context of that function permission, auth, and currentUser are all undefined because you have not set values to them yet. You then subscribe to changes that will happen in the service which is basically registering a function to occur AFTER we process observables.

As it happens observables, are not processed until a tick of the zone they are in for Angular.

The reason permission / auth are set in ngOnInit is because after Angular has instantiated your object, it parses it to see if you have any input or output values to use. If you do, it looks for the corresponding things that were set on the element and sets them before calling ngOnInit which is all before a zone tick happens.

So this is why you have the value in the subscribe and in ngOnInit but you don't have the value in the constructor itself.

like image 28
KeniSteward Avatar answered Jun 20 '26 08:06

KeniSteward



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!