Javascript 当 *ngFor 在 angular 2 中完成时执行一个函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37087864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
execute a function when *ngFor finished in angular 2
提问by Ankit Singh
I trying to create a application with angular 2,i want when last element rendered in *ngFor,execute a function, somthing like this :
我试图创建一个带有 angular 2 的应用程序,我希望在 *ngFor 中呈现最后一个元素时,执行一个函数,如下所示:
<ul>
<li *ngFor="#i of items">{{i.text}}</li> <==== i want when this completed, execute a functuon in my class
</ul>
Thanks.
谢谢。
回答by Ankit Singh
Update
更新
You can use @ViewChildren
for that purpose
您可以@ViewChildren
为此目的使用
There are three cases
有三种情况
1.on initialization ngFor
element is not rendred due to ngIf
on it or it's parent
1.on 初始化ngFor
元素没有被渲染,因为ngIf
它或者它的父元素
- in which case, whenver
ngIf
becomes truthy, you will be notified by theViewChildren
subscription
- 在这种情况下,当
ngIf
变得真实时,您将收到ViewChildren
订阅通知
2.on initialization ngFor
element is rendred regardless of ngIf
on it or it's parent
2.初始化ngFor
元素被渲染,不管ngIf
它是在它还是它的父元素上
- in which case
ViewChildren
subscription will not notify you for the first time, but you can be sure it's rendered in thengAfterViewInit
hook
- 在这种情况下,
ViewChildren
订阅不会第一次通知您,但您可以确定它是在ngAfterViewInit
钩子中呈现的
3.items are added/removed to/from the ngFor
Array
3.向/从ngFor
数组中添加/删除项目
- in which case also
ViewChildren
subscription will notify you
- 在这种情况下,
ViewChildren
订阅也会通知您
[Plunker Demo](see console log there)
[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');
}
}
.
.
Original
原来的
You can do it like this ( but see the side Effects for yourself)
<ul>
<li *ngFor="let i of items; let last = last">{{i}} {{last ? callFunction(i) : ''}}</li>
</ul>
Which is Useless,unless used with changeDetectionStrategy.OnPush
这是无用的,除非与changeDetectionStrategy.OnPush 一起使用
Then you can have control over how many times change detection occurs, hence how many times your function is called.
然后您可以控制发生变化检测的次数,从而控制您的函数被调用的次数。
i.e:You can trigger next changeDetection
when the data of items
changes, and your function will give proper indication that ngFor
is rendered for real change.
即:您可以changeDetection
在数据items
更改时触发 next,您的函数将给出正确的指示,ngFor
为真正的更改呈现。
回答by Methodician
I used a slight hack of the approach others have complained about and it worked like a charm:
我使用了一些其他人抱怨的方法的小技巧,它的作用就像一个魅力:
<ul>
<li *ngFor="let i of items; let last = last">{{i}} {{last ? callFunction(i) : ''}}</li>
</ul>
Then in your component:
然后在您的组件中:
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
}
}
This doesn't address the root of the problem with this approach but it's an extremely low-cost hack that made my app run smoothly. I do hope the Angular team will implement a more friendly way to trigger some code after the *ngFor loads its content.
这并没有解决这种方法的问题根源,但它是一种成本极低的黑客,使我的应用程序运行顺利。我确实希望 Angular 团队能够实现一种更友好的方式来在 *ngFor 加载其内容后触发一些代码。
回答by bdunn
I ran into this problem as well. In my case I was calling a web service to retrieve data and needed to execute javascript to initialize each template produced by *ngFor
. Here's what I came up with:
我也遇到了这个问题。就我而言,我正在调用 Web 服务来检索数据,并且需要执行 javascript 来初始化由*ngFor
. 这是我想出的:
updateData() {
this.dataService.getData().subscribe(
function(data) {
this.data = data;
setTimeout(javascriptInitializationFunction, 0);
},
function(err) { /* handle it */ }
);
}
setTimout
will wait for the DOM To be updated before executing. This isn't exactly what you asked, but hopefully it helps.
setTimout
在执行之前会等待 DOM 更新。这不完全是你问的,但希望它有所帮助。
回答by Pardeep Jain
you can do the same by getting last index using #last
of *ngFor
and call function by getting last index value and do your stuff whatever you want. here is code for the same -
你可以通过使用#last
of获取最后一个索引来做同样的事情,*ngFor
并通过获取最后一个索引值来调用函数,然后做任何你想做的事情。这是相同的代码 -
<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");
}
working example for the same Working Plunker
相同的工作示例 Working Plunker
回答by edmond wang
I am facing the same question and find one way to walk around this. Not sure whether it is suitable for you or not.
Pre-conditions is you are using ngFor to render inbound properties.
我面临同样的问题,并找到一种方法来解决这个问题。不确定它是否适合您。
先决条件是您使用 ngFor 来呈现入站属性。
context: I need call MDL's upgradeAllRegistered to make checkbox pretty after fetch grid data from back-end.
上下文:从后端获取网格数据后,我需要调用 MDL 的 upgradeAllRegistered 以使复选框变得漂亮。
I add one setTimeout inside 'ngOnChanges';
我在 'ngOnChanges' 中添加了一个 setTimeout;
grid.componet.ts:
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:
grid.component.html:
<tr #rowDOM *ngFor="let row of rows;"></tr>
回答by Heru Phang Sebastian
I'd managed to perform some hacks to prevent event get triggred (I found that scrolling always trigger those events)
我设法执行了一些技巧以防止事件被触发(我发现滚动总是触发这些事件)
By adding : [Add in your component]
通过添加:[在您的组件中添加]
private globalFlag = -1;
and this is my event that will be triggered when looping is finished
这是我的事件,将在循环完成时触发
ev(flag){
if(flag != this.globalFlag){
console.log("TRIGGER!")
this.globalFlag = flag;
}
}
and this the looping code
这是循环代码
<div *ngFor="let var of list;let i=index;let last=last">
{{last ? ev(i) : ''}}
</div>
The main idea is to prevent event be trigger if the flag was same. So it only be trigger when the globalFlag value differed with current flag that passed from ngFor. Sorry for my bad english, hope you can understand my idea.
主要思想是防止事件在标志相同时被触发。所以只有当 globalFlag 值与从 ngFor 传递的当前标志不同时才会触发。抱歉我的英语不好,希望你能理解我的想法。
回答by Manzer
Possible solution: the answer is displayed on https://stackblitz.com/edit/angular-phpauq?file=src%2Fapp%2Fapp.component.ts
可能的解决方案:答案显示在https://stackblitz.com/edit/angular-phpauq?file=src%2Fapp%2Fapp.component.ts
app.component.html
应用程序组件.html
<div [innerHTML]="html"></div>
app.component.ts
app.component.ts
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);
}