当 *ngFor 在 angular 2 中完成时执行一个函数

IT技术 javascript angular
2021-02-26 20:48:13

我试图创建一个带有 angular 2 的应用程序,我希望在 *ngFor 中呈现最后一个元素时,执行一个函数,如下所示:

<ul>
  <li *ngFor="#i of items">{{i.text}}</li> <==== i want when this completed, execute a functuon in my class
</ul>

谢谢。

6个回答

更新

您可以@ViewChildren为此目的使用

有三种情况

1. on 初始化ngFor元素没有被渲染,因为ngIf它或者它的父元素

  • 在这种情况下,当ngIf变得真实时,您将收到ViewChildren订阅通知

2. 初始化ngFor元素被渲染,不管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.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 一起使用

然后您可以控制发生变化检测的次数,从而控制您的函数被调用的次数。

即:您可以changeDetection在数据items更改触发 next,您的函数将给出正确的指示,ngFor真正的更改呈现

这个答案更好,因为它不会产生 span
2021-05-02 20:48:13
但是您必须处理函数调用,每次更改检测滴答时都会调用它
2021-05-08 20:48:13
@smnbbrv haha​​ 也不需要span在我的答案中创建额外的内容,我创建只是为了尝试新事物:p 但没有成功。
2021-05-15 20:48:13
@PardeepJain 是的,我知道:) 答案仍然是答案。而且这个函数仍然会被调用这么多次......我真的不认为作者的意图是一个好方法
2021-05-18 20:48:13
因为递归可能,ngFor 渲染并最后调用该函数,这会触发更改检测,这会触发 ngFor 再次渲染并再次调用该函数,依此类推。我不知道为什么它会在 8 点后停止
2021-05-19 20:48:13

我使用了一些其他人抱怨的方法的小技巧,它的作用就像一个魅力:

<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 加载其内容后触发一些代码。

你可以通过使用#lastof获取最后一个索引来做同样的事情*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 Plunker

@AlirezaValizade 是的,请阅读@A_singh's答案的评论以获得更多说明
2021-04-24 20:48:13
这个函数总是执行!就像一个循环!
2021-05-07 20:48:13

我也遇到了这个问题。就我而言,我正在调用 Web 服务来检索数据,并且需要执行 javascript 来初始化由*ngFor. 这是我想出的:

updateData() {
  this.dataService.getData().subscribe(
    function(data) {
      this.data = data;
      setTimeout(javascriptInitializationFunction, 0);
    },
    function(err) { /* handle it */ }
  );
}

setTimout在执行之前会等待 DOM 更新。这不完全是你问的,但希望它有所帮助。

您也可以在此解决方案中实施已接受的答案。
2021-04-23 20:48:13
它正在工作,但在许多情况下它会产生一种hacky体验。例如,如果数据在 DOM 中显示产品,并且您需要使用 JavaScript 函数(而不是您的javascriptInitializationFunction进行设计更改此解决方案将在运行 javascript 函数之前创建产品(数据)的一瞥。我有过在 Angular 应用程序中实现Gridify 的经验
2021-05-09 20:48:13

我面临同样的问题,并找到一种方法来解决这个问题。不确定它是否适合您。
前提条件是您使用 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>