【问题标题】:angular's ng-init alternative in Angular 2Angular 2 中 Angular 的 ng-init 替代方案
【发布时间】:2017-01-26 04:08:32
【问题描述】:

Angular 2 中 ng-init="myText='Hello World!'" 的替代方法是添加到模板中,而不是组件中

 <div ng-app="" ng-init="myText='Hello World!'">

Angular 2 中的替代方案

【问题讨论】:

  • 以上是angular1样本。我期待 angular2 中的替代方案
  • 出于好奇,你在Angular2中使用ng-init的目的是什么?
  • 期待这样的事情 *ngOnInit = "checkCategoryStart = checkCategoryStart != row.category && row.category"
  • 我在 *ngFor 内部使用
  • 我认为 Angular2 上没有类似 ng-init 的东西。无论如何,您可以在组件而不是模板上做这种事情。

标签: angular typescript


【解决方案1】:

你可以使用指令

@Directive({
  selector: 'ngInit',
  exportAs: 'ngInit'
}) 
export class NgInit {
  @Input() values: any = {};

  @Input() ngInit;
  ngOnInit() {
    if(this.ngInit) { this.ngInit(); }
  }  
}

您可以使用它来传递要调用的函数

<div [ngInit]="doSomething"

或使值可用

<div ngInit [values]="{a: 'a', b: 'b'}" #ngInit="ngInit">
  <button (click)="clickHandler(ngInit.values.a)">click me</button>
</div>
  • ngInit 添加指令
  • [values]="{a: 'a', b: 'b'}" 设置一些初始值
  • #ngInit="ngInit" 创建一个供以后使用的参考
  • ngInit.values.a 从创建的引用中读取 a 值。

另见Converting Angular 1 to Angular 2 ngInit function

【讨论】:

  • 这里有一个 plunker:plnkr.co/edit/HmWHjM8wa8gIhuClGdO2?p=preview。在几乎所有情况下,如果您正在查看此内容,您可能应该 ng g component youNeedAComponent +1 作为 exportAs 示例。
  • 不错的技巧。 :) (y)
  • &lt;div [ngInit]="doSomething(parm)" 这样的方法中传递一个参数怎么样?在自定义指令中应该如何处理?
  • 绑定到函数通常是个坏主意,因为每次更改检测运行时都会调用它。除此之外,我不明白你的问题。应该没有必要以特殊的方式处理它。
  • @Rishi 不明白你的意思。为什么它不适用于*ngFor
【解决方案2】:

另一种方法是使用@Output 装饰器和EventEmitter

import {Directive, OnInit, Output, EventEmitter} from '@angular/core';

@Directive({
    selector: '[ngInit]'
})
export class NgInitDirective implements OnInit {

    @Output()
    ngInit: EventEmitter<any> = new EventEmitter();

    ngOnInit() {
        this.ngInit.emit();
    }
}

然后像这样使用它:

<div *ngIf="condition" (ngInit)="initialize()">  ... </div>

Demo

【讨论】:

  • 清洁解决方案!
【解决方案3】:
@Directive({
  selector: '[ngxInit]',
})
export class NgxInitDirective {
  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) {
  }

  @Input() set ngxInit(val: any) {
    this.viewContainer.clear();
    this.viewContainer.createEmbeddedView(this.templateRef, {ngxInit: val});
  }
}

通过*ngxInit 设置值表达式并使用as 微语法发布:

<div *ngxInit="3 * i + j as idx">{{idx}}</div>

发布为https://www.npmjs.com/package/ngx-init

【讨论】:

【解决方案4】:

您并不总是需要为此自定义指令。 如果您对多次调用您的函数感到满意,您可以简单地执行以下操作:

&lt;input #input [attr.init]="resizeInput(input)"/&gt;

那里的“init”一词完全是任意的。缺点是 yourInitFunction 会在每个摘要循环中被调用。

注意,如果你从你的函数中返回任何东西,这将向你的元素添加一个名为“init”的属性,并带有返回值。如果返回undefined,则不会添加该属性。

这通常不是问题,请记住这一点。

【讨论】:

    【解决方案5】:

    可以使用 OnInit 生命周期钩子,如下所示,

    1. 从核心库导入 OnInit

      import {Component, OnInit} from '@angular/core'
      
    2. 在你的组件类中实现它

      export class App  implements OnInit {
      
      }
      
    3. 实现ngOnInit方法

       ngOnInit(){
          this.myText='Hello World!'
      
         }
      

    LIVE DEMO

    【讨论】:

    • 请注意,implements 子句是完全可选的,OnInit 的导入也是如此。
    • 为 ngFor 中的每个项目创建一个新的作用域变量
    【解决方案6】:

    虽然我同意初始化应该进入 ngOnInit 生命周期钩子,但还应该注意,您可以使用组件的构造函数来初始化类成员。在您的简单示例中,您甚至可以使用成员声明来设置变量,例如:

    @Component({ template: '<div>{{myText}}</div>' })
    export class MyComponent {
        myText = 'Hello World!';
    }
    

    【讨论】:

      【解决方案7】:

      小更新! 在最新版本的 Angular 中,这将不起作用:

      @Directive({
       selector: 'ngInit',
       exportAs: 'ngInit'
      })
      

      你应该使用'[]':

      @Directive({
         selector: '[ngInit]',
         exportAs: 'ngInit'
      })
      

      【讨论】:

        【解决方案8】:

        对 Günter 的回答可能有所改进:

        @Directive({
          selector: 'ngInit',
          exportAs: 'ngInit'
        }) 
        export class NgInit {
          @Input() ngInit: () => any;
          ngOnInit() {
            if(typeof this.ngInit === 'function') { 
                this.ngInit(); 
            } else {
                // preventing re-evaluation (described below)
                throw 'something';
            }
          }  
        }
        

        然后使用高阶函数传入数据,如下所示:

        // component.ts
        myInitFunction(info) {
          // returns another function
          return () => console.log(info);
        }
        

        如果你使用像这样的高阶函数,你也不必担心thismyInitFunction 内部是什么,因为实际上传递的是箭头函数。

        像这样使用指令:

        // component.html
        <another-component #ref></another-component>
        <div [ngInit]="myInitFunction(ref)"></div>
        

        如果您要尝试创建一个不以此处描述的方式将函数作为输入传递的指令,您将面临无限循环的风险。例如,如果你的整个指令只是简单地评估你给它的表达式,你就会明白这一点。

        如果您的 myInitFunction 方法没有返回另一个函数(并且您的 HTML 与上面相同),就会发生这种情况。你会安慰自己,返回 undefined,然后变更检测会重新评估它,一遍又一遍地安慰。

        【讨论】:

          【解决方案9】:

          我发现使用data 属性可以轻松解决这个问题。 在我的示例中,我只是使用它来显示,但是显然可以使用相同的方法进行切换或任何可能的操作。

          <div data-expand="false" #expandWrap>
            <span *ngIf="expandWrap.dataset.expand == 'false'">
              {{'Test expand without..'}}
              <span (click)="expandWrap.dataset.expand = 'true'">more</span>
            </span>
            <span *ngIf="expandWrap.dataset.expand == 'true'">
                 {{'Test expand with more text because now we are expanded!'}}
            </span>
          </div>
          
          

          我发了a small demo on stackblitz 说明这是如何工作的

          【讨论】:

            【解决方案10】:

            这个怎么样?

            @Directive({
              selector: '[onInit]'
            })
            export class OnInitDirective implements OnInit {
              @Output() onInit = new EventEmitter<void>();
            
              ngOnInit(): void {
                this.onInit.emit();
              }
            }
            

            这样使用:

            <div (onInit)="doSomeStuff(someValue)"></div>
            

            【讨论】:

              猜你喜欢
              • 2018-03-23
              • 1970-01-01
              • 2019-05-07
              • 1970-01-01
              • 1970-01-01
              • 2016-07-01
              • 2018-02-28
              • 2019-07-07
              • 1970-01-01
              相关资源
              最近更新 更多