我尝试用角度2创建一个应用程序,我想在* ngFor中渲染最后一个元素时,执行一个函数,像这样:
<ul>
<li *ngFor="#i of items">{{i.text}}</li> <==== i want when this completed, execute a functuon in my class
</ul>
感谢。
答案 0 :(得分:46)
您可以将@ViewChildren
用于此目的
有三种情况
初始化ngFor
元素上的 1。由于ngIf
或其父级
ngIf
变得真实时,ViewChildren
订阅ngFor
元素上的 2。是rendred,无论其上是ngIf
还是它的父级
ViewChildren
订阅不会第一次通知您,但您可以确定它是在ngAfterViewInit
挂钩 3。在ngFor
数组
ViewChildren
订阅也会通知您[Plunker Demo] (请参阅控制台日志)
@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.ngForRendred();
})
}
ngForRendred() {
console.log('NgFor is Rendered');
}
}
您可以这样做(但请参阅the side Effects for yourself)
<ul>
<li *ngFor="let i of items; let last = last">{{i}} {{last ? callFunction(i) : ''}}</li>
</ul>
除非与changeDetectionStrategy.OnPush
一起使用,否则无用,然后,您可以控制更改检测的次数,从而控制您的函数被调用的次数。
ie: 当changeDetection
的数据发生变化时,您可以触发下一个items
,并且您的函数会正确指示{{1}为真实更改呈现。
答案 1 :(得分:4)
我使用了其他人抱怨的方法,它就像一个魅力:
SELECT a1.userid,
SUM(path="abc.com") as is_CWS,
a2.Apply_num,
is_CWS/a2.Apply_num FROM
TABLE
JOIN
(select userid,count(userid) as Apply_num
FROM TABLE
where trackid is not NULL
group by userid) a2
on a1.userid=a2.userid
GROUP BY userid
然后在你的组件中:
GROUP BY
这并没有解决这种方法的问题根源,但它是一个极低成本的黑客,使我的应用程序运行顺利。我希望Angular团队能够在* ngFor加载其内容后实现更友好的方式来触发一些代码。
答案 2 :(得分:2)
你可以通过使用#last
的{{1}}来获取最后一个索引,并通过获取最后一个索引值来调用函数,并根据需要执行任何操作。这是相同的代码 -
*ngFor
的工作示例
答案 3 :(得分:2)
我也遇到了这个问题。就我而言,我正在调用一个Web服务来检索数据,并且需要执行javascript来初始化*ngFor
生成的每个模板。这就是我想出的:
updateData() {
this.dataService.getData().subscribe(
function(data) {
this.data = data;
setTimeout(javascriptInitializationFunction, 0);
},
function(err) { /* handle it */ }
);
}
setTimout
将等待DOM在执行之前进行更新。这不完全是你提出的要求,但希望它有所帮助。
答案 4 :(得分:1)
我面临同样的问题,找到一种方法来解决这个问题。不确定它是否适合你。
前提条件是您使用ngFor来呈现入站属性。
context:我需要调用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>
答案 5 :(得分:1)
我设法执行一些黑客攻击以防止事件被触发(我发现滚动总是触发那些事件)
添加:[在您的组件中添加]
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>
主要思想是如果标志相同则防止触发事件。因此只有当globalFlag值与从ngFor传递的当前标志不同时才会触发。抱歉我的英语不好,希望你能理解我的想法。
答案 6 :(得分:0)
可能的解决方案:答案显示在https://stackblitz.com/edit/angular-phpauq?file=src%2Fapp%2Fapp.component.ts
<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);
}