我正在使用Angular 2创建一个应用程序,我希望当*ngFor中的最后一个元素被渲染时执行一个函数,类似于以下代码:
<ul>
<li *ngFor="#i of items">{{i.text}}</li> <==== i want when this completed, execute a functuon in my class
</ul>
谢谢。我正在使用Angular 2创建一个应用程序,我希望当*ngFor中的最后一个元素被渲染时执行一个函数,类似于以下代码:
<ul>
<li *ngFor="#i of items">{{i.text}}</li> <==== i want when this completed, execute a functuon in my class
</ul>
谢谢。你可以使用@ViewChildren
来实现这个目的。
有三种情况:
1. 初始化时,由于其上的ngIf
或父级ngIf
而未呈现ngFor
元素
ngIf
变为真,就会通过ViewChildren
订阅得到通知。2. 初始化时,无论是否有ngIf
在其上或其父级上,都会呈现ngFor
元素
ViewChildren
订阅将不会第一时间通知您,但您可以确信它已在ngAfterViewInit
钩子中呈现。3. 向ngFor
数组添加/删除项
ViewChildren
订阅也会通知您。[Plunker演示] (请查看控制台日志)
@Component({
selector: 'my-app',
template: `
<ul *ngIf="!isHidden">
<li #allTheseThings *ngFor="let i of items; let last = last">{{i}}</li>
</ul>
<br>
<button (click)="items.push('another')">Add Another</button>
<button (click)="isHidden = !isHidden">{{isHidden ? 'Show' : 'Hide'}}</button>
`,
})
export class App {
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
@ViewChildren('allTheseThings') things: QueryList < any > ;
ngAfterViewInit() {
this.things.changes.subscribe(t => {
this.ngForRendered();
})
}
ngForRendered() {
console.log('NgFor is Rendered');
}
}
您可以这样做(但请查看自己的副作用)
<ul>
<li *ngFor="let i of items; let last = last">{{i}} {{last ? callFunction(i) : ''}}</li>
</ul>
如果不与changeDetectionStrategy.OnPush一起使用,它就没什么用处了。
然后你可以控制变更检测发生的次数,因此也可以控制函数被调用的次数。
例如:当items
的数据发生改变时,你可以触发下一个changeDetection
,你的函数将正确地指示ngFor
已经呈现出真正的变化。
我使用了一种轻微的方式来解决其他人抱怨过的问题,它很完美地发挥了作用:
<ul>
<li *ngFor="let i of items; let last = last">{{i}} {{last ? callFunction(i) : ''}}</li>
</ul>
然后在你的组件中:
shouldDoIt = true; // initialize it to true for the first run
callFunction(stuff) {
if (this.shouldDoIt) {
// Do all the things with the stuff
this.shouldDoIt = false; // set it to false until you need to trigger again
}
}
这并没有解决这种方法的根本问题,但它是一个极低成本的技巧,让我的应用程序运行顺畅。我希望Angular团队能实现一种更友好的方式,在*ngFor加载其内容后触发一些代码。
您可以通过使用*ngFor
的#last
获取最后一个索引,然后通过获取最后一个索引值调用函数并执行您想要的操作。以下是相同的代码 -
<ul>
<li *ngFor="#item of items; #last = last">
<span *ngIf='last'>{{hello(last)}}</span>
{{item}}
</li>
</ul>
items: Array<number> = [1,2,3,4,5]
constructor() { console.clear();}
hello(a){
if(a==true)
this.callbackFunction();
}
callbackFunction(){
console.log("last element");
}
这是相同问题的示例代码:工作中的 Plunker
@A_singh
回答的评论以获得更多澄清。 - Pardeep Jain我也遇到了这个问题。在我的情况下,我正在调用一个Web服务来检索数据,并需要执行JavaScript来初始化由*ngFor
生成的每个模板。以下是我的解决方案:
updateData() {
this.dataService.getData().subscribe(
function(data) {
this.data = data;
setTimeout(javascriptInitializationFunction, 0);
},
function(err) { /* handle it */ }
);
}
setTimout
会在DOM更新后执行。这不完全是你要求的,但希望能有所帮助。
javascriptInitializationFunction
),则此解决方案将在运行JavaScript函数之前创建产品(数据)的一瞥。我在Angular应用程序中实现Gridify时就有这种经历。 - Peter Højlund Palluth我遇到了同样的问题,并找到一种方法来解决它。不确定它是否适合你。
前提条件是你正在使用ngFor来呈现传入属性。
背景:我需要调用MDL的upgradeAllRegistered,以使复选框在从后端获取网格数据后变得漂亮。
我在'ngOnChanges'中添加了一个setTimeout。
grid.componet.ts:
export class GridComponent {
@Input() public rows: Array<any>;
ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
for (let propName in changes) {
if (propName == 'rows') {
setTimeout(() => componentHandler.upgradeAllRegistered());
}
}
}
}
grid.component.html:
<tr #rowDOM *ngFor="let row of rows;"></tr>
private globalFlag = -1;
这是我的事件,当循环完成时将会被触发
ev(flag){
if(flag != this.globalFlag){
console.log("TRIGGER!")
this.globalFlag = flag;
}
}
这是循环代码
<div *ngFor="let var of list;let i=index;let last=last">
{{last ? ev(i) : ''}}
</div>
<div [innerHTML]="html"></div>
html = '';
ngAfterViewInit(){
let i;
this.html += '<ul>';
for(i = 0 ; i < this.abc.length ; i++){
this.html += '<li>';
this.html += this.abc[i];
if(parseInt(i) === this.abc.length - 1){
this.callMethod(i);
}
this.html += '</li>';
}
this.html += '</ul>';
}
callMethod(text){
alert(text);
}
<div *ngFor="let item of itemList; let i = index;">
{{ ( (!flag) && ( (i+1) === itemList.length) ) ? myFunction() : ''}}
</div>
let flag : boolean = false;
myFunction()
{
// To execute if ngFor has finished
this.flag = true;
}