angular's ng-init alternative in Angular 2

后端 未结 8 835
遇见更好的自我
遇见更好的自我 2020-12-01 12:14

What is the alternative of ng-init=\"myText=\'Hello World!\'\" in Angular 2 to add in the template, not in the component

 
相关标签:
8条回答
  • 2020-12-01 12:37

    You can use a directive

    @Directive({
      selector: 'ngInit',
      exportAs: 'ngInit'
    }) 
    export class NgInit {
      @Input() values: any = {};
    
      @Input() ngInit;
      ngOnInit() {
        if(this.ngInit) { this.ngInit(); }
      }  
    }
    

    you can use it to pass a function to be called like

    <div [ngInit]="doSomething"
    

    or to make values available

    <div ngInit [values]="{a: 'a', b: 'b'}" #ngInit="ngInit">
      <button (click)="clickHandler(ngInit.values.a)">click me</button>
    </div>
    
    • ngInit addes the directive
    • [values]="{a: 'a', b: 'b'}" sets some initial values
    • #ngInit="ngInit" creates a reference for later use
    • ngInit.values.a reads the a value from the created reference.

    See also Converting Angular 1 to Angular 2 ngInit function

    0 讨论(0)
  • 2020-12-01 12:48

    Another approach is by using the @Output decorator and EventEmitter:

    import {Directive, OnInit, Output, EventEmitter} from '@angular/core';
    
    @Directive({
        selector: '[ngInit]'
    })
    export class NgInitDirective implements OnInit {
    
        @Output()
        ngInit: EventEmitter<any> = new EventEmitter();
    
        ngOnInit() {
            this.ngInit.emit();
        }
    }
    

    And then use it like:

    <div *ngIf="condition" (ngInit)="initialize()">  ... </div>
    

    Demo

    0 讨论(0)
  • 2020-12-01 12:48

    While I agree that initialization should go into the ngOnInit life-cycle hook, it should also be noted that you can use the constructor of the component to initialize class members. In your simple example, you could even use the member declaration to set the variable, e.g.:

    @Component({ template: '<div>{{myText}}</div>' })
    export class MyComponent {
        myText = 'Hello World!';
    }
    
    0 讨论(0)
  • 2020-12-01 12:56

    Little Update! In the latest versions of Angular this will not work:

    @Directive({
     selector: 'ngInit',
     exportAs: 'ngInit'
    })
    

    you should use '[]':

    @Directive({
       selector: '[ngInit]',
       exportAs: 'ngInit'
    })
    
    0 讨论(0)
  • 2020-12-01 12:58

    A possible improvement over Günter's answer:

    @Directive({
      selector: 'ngInit',
      exportAs: 'ngInit'
    }) 
    export class NgInit {
      @Input() ngInit: () => any;
      ngOnInit() {
        if(typeof this.ngInit === 'function') { 
            this.ngInit(); 
        } else {
            // preventing re-evaluation (described below)
            throw 'something';
        }
      }  
    }
    

    And then use higher-order functions for passing in data, like so:

    // component.ts
    myInitFunction(info) {
      // returns another function
      return () => console.log(info);
    }
    

    If you use a higher-order function like this, you also don't need to worry about what this is inside of myInitFunction since an arrow function is really what is passed.

    Use the directive like so:

    // component.html
    <another-component #ref></another-component>
    <div [ngInit]="myInitFunction(ref)"></div>
    

    If you were to try and create a directive that doesn't pass in a function as the input in the manner described here, you run the risk of infinite loops. For example, you'd get that if you whole directive was simply evaluating the expression you gave it.

    This is what would happen if your myInitFunction method didn't return another function (and your HTML was the same as above). You'd console out, return undefined, and then change detection would re-evaluate it, consoling out over and over.

    0 讨论(0)
  • 2020-12-01 12:59

    You do not always need a custom directive for this. If you're okay with your function being called more than once, you can simple do:

    <input #input [attr.init]="resizeInput(input)"/>

    The word "init" there is completely arbitrary. The downside is yourInitFunction will get called on every digest cycle.

    Note, if you return anything from your function this will add an attribute called "init" to your element with the returned value. If you return undefined, it will not add the attribute.

    This is normally a non-issue, just keep it in mind.

    0 讨论(0)
提交回复
热议问题