代码之家  ›  专栏  ›  技术社区  ›  Rahul

“*ngFor”循环完成后如何获得一次回拨[[副本]

  •  0
  • Rahul  · 技术社区  · 5 年前

    在Angular 1中,我编写了一个自定义指令(“repeater ready”),用于 ng-repeat 要在迭代完成时调用回调方法,请执行以下操作:

    if ($scope.$last === true)
    {
        $timeout(() =>
        {
            $scope.$parent.$parent.$eval(someCallbackMethod);
        });
    }
    

    标记中的用法:

    <li ng-repeat="item in vm.Items track by item.Identifier"
        repeater-ready="vm.CallThisWhenNgRepeatHasFinished()">
    

    我怎样才能实现类似的功能 ngFor

    0 回复  |  直到 8 年前
        1
  •  22
  •   Sasxa    8 年前

    你可以用这样的东西( ngFor local variables

    <li *ngFor="#item in Items; #last = last" [ready]="last ? false : true">
    

    那你可以 Intercept input property changes with a setter

      @Input()
      set ready(isReady: boolean) {
        if (isReady) someCallbackMethod();
      }
    
        2
  •  59
  •   Abhijit Jagtap    3 年前

    @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');
      }
    }
    

    最初的答案在这里 https://stackoverflow.com/a/37088348/5700401

        3
  •  7
  •   Leniel Maccaferri    4 年前

    对于我来说,使用Typescript在Angular2中工作。

    <li *ngFor="let item in Items; let last = last">
      ...
      <span *ngIf="last">{{ngForCallback()}}</span>
    </li>
    

    public ngForCallback() {
      ...
    }
    
        4
  •  5
  •   ZirkoViter    6 年前

    ngFor 完成将所有DOM元素打印到浏览器窗口,请执行以下操作:

    1.添加占位符

    为正在打印的内容添加占位符:

    <div *ngIf="!contentPrinted">Rendering content...</div>

    2.添加一个容器

    使用创建一个容器 display: none 对于内容。打印完所有项目后,请执行以下操作: display: block contentPrinted 是组件标志属性,默认为 false

    <ul [class.visible]="contentPrinted"> ...items </ul>

    3.创建一个回调方法

    添加 onContentPrinted() 到组件,该组件在 ngFor 完成:

    onContentPrinted() { this.contentPrinted = true; this.changeDetector.detectChanges(); }

    别忘了使用 ChangeDetectorRef ExpressionChangedAfterItHasBeenCheckedError

    4.使用NGF last

    声明 可变的 . 在里面用 li 最后一个 :

    <li *ngFor="let item of items; let last = last"> ... <ng-container *ngIf="last && !contentPrinted"> {{ onContentPrinted() }} </ng-container> <li>

    • 内容印刷 onContentPrinted() 只有一次 .
    • ng-container 不影响布局。
        5
  •  4
  •   Rajasekhar Kunati    8 年前

    使用[attr.ready]代替[ready],如下所示

     <li *ngFor="#item in Items; #last = last" [attr.ready]="last ? false : true">
        6
  •  3
  •   Warren Schilpzand    8 年前

    我在RC3中发现接受的答案不起作用。然而,我已经找到了一种方法来处理这个问题。对我来说,我需要知道ngFor何时完成运行MDL componentHandler来升级组件。

    首先,您需要一个指令。

    import { Directive, ElementRef, Input } from '@angular/core';
    
    declare var componentHandler : any;
    
    @Directive({ selector: '[upgrade-components]' })
    export class UpgradeComponentsDirective{
    
        @Input('upgrade-components')
        set upgradeComponents(upgrade : boolean){
            if(upgrade) componentHandler.upgradeAllRegistered();
        }
    }
    

    接下来将其导入组件并将其添加到指令中

    import {UpgradeComponentsDirective} from './upgradeComponents.directive';
    
    @Component({
        templateUrl: 'templates/mytemplate.html',
        directives: [UpgradeComponentsDirective]
    })
    

     <div *ngFor='let item of items;let last=last' [upgrade-components]="last ? true : false">
    

    当该属性设置为true时,它将在@Input()声明下运行该方法。在我的例子中,它运行componentHandler.upgradeAllRegistered()。但是,它可以用于您选择的任何东西。通过绑定到ngFor语句的“last”属性,它将在完成时运行。

        7
  •  1
  •   Community THelper    7 年前

    我为这个问题写了一个演示。这个理论是基于 the accepted answer 但这个答案并不完整,因为 li 应该是可以接受 ready 输入。

    我写 a complete demo 对于这个问题。

    从“@angular/core”导入{Component,Input,OnInit};

    @Component({
      selector: 'app-li-ready',
      templateUrl: './li-ready.component.html',
      styleUrls: ['./li-ready.component.css']
    })
    export class LiReadyComponent implements OnInit {
    
      items: string[] = [];
    
      @Input() item;
      constructor() { }
    
      ngOnInit(): void {
        console.log('LiReadyComponent');
      }
    
      @Input()
      set ready(isReady: boolean) {
        if (isReady) {
          console.log('===isReady!');
        }
      }
    }
    

    模板

    {{item}}
    

    应用程序组件中的使用情况

    <app-li-ready *ngFor="let item of items;  let last1 = last;" [ready]="last1" [item]="item"></app-li-ready>
    

        8
  •  -1
  •   H7O    7 年前

    我还没有深入了解ngFor如何渲染引擎盖下的元素。但从观察中,我注意到它经常倾向于对每个迭代项的表达式求值不止一次。

    这会导致在检查“last”变量时进行的任何typescript方法调用,有时会触发多次。

    为了保证ngFor在正确完成对项目的迭代时只调用一次typescript方法,您需要添加一个小的保护,以防止ngFor在后台执行的多表达式重新计算。

    指令代码

    import { Directive, OnDestroy, Input, AfterViewInit } from '@angular/core';
    
    @Directive({
      selector: '[callback]'
    })
    export class CallbackDirective implements AfterViewInit, OnDestroy {
      is_init:boolean = false;
      called:boolean = false;
      @Input('callback') callback:()=>any;
    
      constructor() { }
    
      ngAfterViewInit():void{
        this.is_init = true;
      }
    
      ngOnDestroy():void {
        this.is_init = false;
        this.called = false;
      }
    
      @Input('callback-condition') 
      set condition(value: any) {
          if (value==false || this.called) return;
    
          // in case callback-condition is set prior ngAfterViewInit is called
          if (!this.is_init) {
            setTimeout(()=>this.condition = value, 50);
            return;
          }
    
          if (this.callback) {
            this.callback();
            this.called = true;
          }
          else console.error("callback is null");
    
      }
    
    }
    

    在您的模块中声明上述指令后(假设您知道如何执行,如果不知道,请询问,我希望用代码段更新此指令),以下是如何将指令与ngFor一起使用:

    <li *ngFor="let item of some_list;let last = last;" [callback]="doSomething" [callback-condition]="last">{{item}}</li>
    

    “doSomething”在这里没有括号“()”,因为我们只是传递对typescript方法的引用,而不是在这里实际调用它。

    public doSomething=()=> {
        console.log("triggered from the directive's parent component when ngFor finishes iterating");
    }