[Angular] @ViewChildren and QueryLists (ngAfterViewInit)

When you use @ViewChildren, the value can only be accessable inside ngAfterViewInit lifecycle. This is somehow different from @ViewChild, which value can be accessed from ngAfterContentInit lifecycle.

import { Component, ChangeDetectorRef, Output, ViewChildren, AfterViewInit, EventEmitter, ContentChildren, QueryList, AfterContentInit } from ‘@angular/core‘;

import { AuthRememberComponent } from ‘./auth-remember.component‘;
import { AuthMessageComponent } from ‘./auth-message.component‘;

import { User } from ‘./auth-form.interface‘;

@Component({
  selector: ‘auth-form‘,
  template: `
    <div>
      <form (ngSubmit)="onSubmit(form.value)" #form="ngForm">
        <ng-content select="h3"></ng-content>
        <label>
          Email address
          <input type="email" name="email" ngModel>
        </label>
        <label>
          Password
          <input type="password" name="password" ngModel>
        </label>
        <ng-content select="auth-remember"></ng-content>
        <auth-message
          [style.display]="(showMessage ? ‘inherit‘ : ‘none‘)">
        </auth-message>
        <auth-message
          [style.display]="(showMessage ? ‘inherit‘ : ‘none‘)">
        </auth-message>
        <auth-message
          [style.display]="(showMessage ? ‘inherit‘ : ‘none‘)">
        </auth-message>
        <ng-content select="button"></ng-content>
      </form>
    </div>
  `
})
export class AuthFormComponent implements AfterContentInit, AfterViewInit {

  showMessage: boolean;

  @ViewChildren(AuthMessageComponent) message: QueryList<AuthMessageComponent>;

  @ContentChildren(AuthRememberComponent) remember: QueryList<AuthRememberComponent>;

  @Output() submitted: EventEmitter<User> = new EventEmitter<User>();

  constructor(private cd: ChangeDetectorRef) {}

  ngAfterViewInit() {
    console.log("this.message:", this.message); // QueryList {...}
    if (this.message) {
      this.message.forEach((message) => {
        message.days = 30;
      });
      this.cd.detectChanges();
    }
  }

  ngAfterContentInit() {
    console.log("this.message:", this.message); // undefined
    if (this.remember) {
      this.remember.forEach((item) => {
        item.checked.subscribe((checked: boolean) => this.showMessage = checked);
      });
    }
  }

  onSubmit(value: User) {
    this.submitted.emit(value);
  }

}

Here we try to modify the value inside ngAfterViewInit lifecycle. but in developement mode, there is change detection error! We cannot modify the ‘messages.day‘ after view init.

We can bypass this problem by using ‘ChangeDetectRef‘.

this.cd.detectChanges();

To tell Angular change detection everything is fine. And this error won‘t show up in production mode, only in development mode.

时间: 2024-10-26 12:18:15

[Angular] @ViewChildren and QueryLists (ngAfterViewInit)的相关文章

Angular2基础知识

使用Component注解的selector属性来告诉Angular2框架,当编译.链接模板时,如果 看到这个选择符,就实例化一个组件对象. 标签名选择符 @Component({selector:"ez-one",template:"TAGNAME-SELECTOR"}) 将匹配:<ez-one>...</ez-one> CSS类选择符 @Component({selector:".ez-two",template:&q

Angular 2 中的 ViewChild 和 ViewChildren

https://segmentfault.com/a/1190000008695459 ViewChild ViewChild 是属性装饰器,用来从模板视图中获取匹配的元素.视图查询在 ngAfterViewInit 钩子函数调用前完成,因此在 ngAfterViewInit 钩子函数中,才能正确获取查询的元素. @ViewChild 使用模板变量名 import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular

[Angular] Difference between ngAfterViewInit and ngAfterContentInit

Content is what is passed as children. View is the template of the current component. The view is initialized before the content and ngAfterViewInit() is therefore called before ngAfterContentInit(). @Component({ selector: 'parent-cmp', template: '<d

Angular 2 ElementRef

Angular 2 的口号是 - "一套框架,多种平台.同时适用手机与桌面(One framework.Mobile & desktop.)",即 Angular 2 是支持开发跨平台的应用,比如:Web应用.移动Web应用.原生移动应用和原生桌面应用等. 为了能够支持跨平台,Angular 2 通过抽象层封装了不同平台的差异,统一了 API 接口.如定义了抽象类 Renderer .抽象类 RootRenderer 等.此外还定义了以下引用类型:ElementRef.Temp

Angular开发实践(四):组件之间的交互

在Angular应用开发中,组件可以说是随处可见的.本篇文章将介绍几种常见的组件通讯场景,也就是让两个或多个组件之间交互的方法. 根据数据的传递方向,分为父组件向子组件传递.子组件向父组件传递及通过服务传递三种交互方法. 父组件向子组件传递 子组件通过@Input装饰器定义输入属性,然后父组件在引用子组件的时候通过这些输入属性向子组件传递数据,子组件可通过setter或ngOnChanges()来截听输入属性值的变化. 先定义两个组件,分别为子组件DemoChildComponent和父组件De

Angular使用总结 --- 如何正确的操作DOM

无奈接手了一个旧项目,上一个老哥在Angular项目中大量使用了JQuery来操作DOM,真的是太不讲究了.那么如何优雅的使用Angular的方式来操作DOM呢? 获取元素 1.ElementRef  ---   A wrapper around a native element inside of a View. 在组件的 constructor中注入ElementRef,可以获取到整个组件元素的包裹. @Component({ selector: 'app-test-page', templ

Angular中操作DOM

使用ViewChildren监听DOM事件 官方文档 You can use ViewChildren to get the QueryList of elements or directives from the view DOM. Any time a child element is added, removed, or moved, the query list will be updated, and the changes observable of the query list w

Angular 4 设置组件样式的几种方式

你用Angular吗? 一.介绍 如何只改动最简单的css代码,呈现完全不一样的视图效果. 第一种:最基本的设置: 图1 代码 图2 界面运行效果图 平常,想给一个label或者p等标签添加样式,我们就是这样操作,在Angular中也是一样的. 现在,如果我想要将字体换成红色呢,首先想到的就是去修改.label里的color属性值,可如果样式表是封装的或者外部引用的,不方便修改呢? 这时候就要用到ElementRef 和Renderer2了.可以去Angular 官网里搜索哟. renderer

Angular 2 模板语法与常用指令简介

一.模板语法简介 插值表达式 <div>Hello {{name}}</div> 等价于 <div [textContent]="interpolate(['Hello'], [name])"></div> 模板表达式 1.属性绑定 1.1输入属性的值为常量 <show-title title="Some Title"></show-title> 等价于 <show-title [titl