What is the alternative of ng-init="myText='Hello World!'"
in Angular 2 to add in the template, not in the component
<div ng-app="" ng-init="myText='Hello World!'">
the alternative in Angular 2
What is the alternative of ng-init="myText='Hello World!'"
in Angular 2 to add in the template, not in the component
<div ng-app="" ng-init="myText='Hello World!'">
the alternative in Angular 2
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 usengInit.values.a
reads the a
value from the created reference.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>
@Directive({
selector: '[ngxInit]',
})
export class NgxInitDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) {
}
@Input() set ngxInit(val: any) {
this.viewContainer.clear();
this.viewContainer.createEmbeddedView(this.templateRef, {ngxInit: val});
}
}
a value expression is set via *ngxInit
and published using as
micro-syntax:
<div *ngxInit="3 * i + j as idx">{{idx}}</div>
published as https://www.npmjs.com/package/ngx-init
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.
It is possible by using OnInit Life Cycle hook as below,
Import OnInit from core library
import {Component, OnInit} from '@angular/core'
Implement it to your component class
export class App implements OnInit {
}
Implement the ngOnInit method
ngOnInit(){
this.myText='Hello World!'
}
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!';
}
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'
})
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.
I found a fairly easy fix for this problem using the data
attribute.
In my example, i just use it to show, but a toggle or whatever is possible using the same method obviously.
<div data-expand="false" #expandWrap>
<span *ngIf="expandWrap.dataset.expand == 'false'">
{{'Test expand without..'}}
<span (click)="expandWrap.dataset.expand = 'true'">more</span>
</span>
<span *ngIf="expandWrap.dataset.expand == 'true'">
{{'Test expand with more text because now we are expanded!'}}
</span>
</div>
I made a small demo on stackblitz on how this works
How about this?:
@Directive({
selector: '[onInit]'
})
export class OnInitDirective implements OnInit {
@Output() onInit = new EventEmitter<void>();
ngOnInit(): void {
this.onInit.emit();
}
}
Use like this:
<div (onInit)="doSomeStuff(someValue)"></div>