Utilizing @ViewChildren in Angular 2 for seamless communication between Parent and Child components

Trying to grasp the concept of the @ViewChildren() decorator. I've created a Component named Component-A that takes in a user's email address. Next, I built a parent component called "Component-B" which includes two instances of Component-A. I have come across tutorials on how parent and child components can communicate using Event and property binding with the help of @Input() and @Output() decorators. But is there a way to achieve the same functionality using @ViewChildren(), where we compare both entered emails and display a message if they match?

@Component({
    selector: 'component-A'
    styleUrls: [],
    templateUrl: `<form>
                   <div>
                     <fieldset>
                     <legend>Component A</legend>
                       <div class="form-horizontal">
                          <div class="form-group">
                            <label for="inputEmail3" class="col-sm-2 control-label">Email</label>
                             <div class="col-sm-10">
      <input type="email" class="form-control" id="inputEmail3" placeholder="Email">
    </div>
</div>
</fieldset>
})

  export class ComponentA {

  }

Now let's look at Component B:

@Component({
    selector: 'component-B',
    styleUrls: [],
    templateUrl: `
                  <form>
                    <div>
                      <fieldset>
                        <legend>Parent Component</legend>
                          <div class="form-horizontal">
                            <div class="form-group">
                              <label for="1" class="col-sm-2 control-label">1</label>
                               <div class="col-sm-10">
                                   <component-A></component-A>
                               </div>

                              <div class="form-group">
                              <label for="2" class="col-sm-2 control-label">2</label>
                               <div class="col-sm-10">
                                   <component-A></component-A>
                               </div>
                         </div>
                     </div>
               </fieldset>
            </div>
         </form>
})

   export class Parent {
}

Answer №1

Having recently delved into this topic myself, I understand the challenges of grasping the change detection flow in Angular2. It's a powerful concept, but can be quite perplexing at first. Allow me to share my insights on your question.

@ViewChildren and AfterViewChecked

In addition to using the @ViewChildren decorator as mentioned before, here is some extra code to consider:

@Component({
    template: `
       <my-component #component *ngFor="let component of components"></my-component>
    `
})
export class Parent implements AfterViewChecked {
  private different: boolean = false;
  private components: any[] = [];
  @ViewChildren("component") componentList: QueryList<MyComponent>;

  // Inject the change detector for later use.
  constructor(private detector: ChangeDetectorRef) {

  }

  // Utilize the "AfterViewChecked" hook to compare and update differences.
  // This will execute after each change detection iteration.
  ngAfterViewChecked() {
    var email: string;
    var different = false;
    this.componentList.forEach(component => {
      if (email == undefined) {
        email = component.email;
      }

      if (email != component.email) {
        different = true;
      }
    });

    if (different != this.different) {
      this.different = different;

      // ENSURE TO NOTIFY CHANGE DETECTOR.
      this.detector.detectChanges();
    }
  }
}

The code above may seem extensive for a simple comparison task, but it effectively uses the AfterViewChecked event to analyze child elements and trigger change detection when needed.

Understanding Angular2's Approach

Angular2 greatly emphasizes the use of @Input and @Output for managing data exchange between components:

Online tutorials demonstrate how parent and child components communicate through Event and property binding with @Input() and @Output() decorators.

By employing Inputs and Outputs alongside directives like *ngFor, you can streamline data transfer without relying heavily on @ViewChildren.

<my-component 
    *ngFor="let component of components"
    (emailChanged)="emailChanged(email)">
</my-component>

These directives encapsulate Angular2's change detection mechanism, simplifying the process within standard cycles.

Efficiency in Tracking Changes

The rationale behind Angular2's approach lies in efficient change tracking methods. Contrastingly, Angular.js lacked clarity in monitoring changes, often resorting to cumbersome functions like scope.apply(). With Angular2, automated change tracking triggers upon specific events, operating within distinct application zones to maximize performance.

An Alternative Perspective

If circumstances prevent the use of @Input or @Output functionality (e.g., dynamic lists), @ViewChildren becomes vital. When adjusting parent states based on child modifications, signaling the change detector becomes imperative. Failure to do so results in misaligned change detection rounds and potential errors, necessitating interventions like detectChanges().

For further details on this subject, refer to the advanced documentation provided by Angular here.

Answer №2

class MainParent {
  @ViewChild(SubComponentA) subComponent:SubComponentA;

  afterViewInit() {
    console.log(this.subComponent);
  }
}

To learn more, visit

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Typescript is encountering errors indicating that it is unable to locate modules for imported assets, such as images

Having trouble with TS not recognizing image imports. Although the site runs fine, TypeScript seems to have an issue identifying them: import React, { Component } from 'react'; import SlackIcon from './assets/social/slack-icon-thumb.png&apos ...

I'm currently utilizing CSS GRID to create a map layout, but I'm encountering an issue where the layout is not filling the entire screen. I'm wondering how I can achieve this in Angular

Here is the unique html code snippet for a layout that dynamically creates grids using json input: <!DOCTYPE html> <html lang="en"> <head> <title>Booking Page</title> </head> <body> <div ...

TypeORM's one-to-many relationship alters the primary entity once the relationship has been established

When working on my side project, I decided to implement a friend request system using NestJS + TypeORM for the backend. However, I encountered a peculiar issue where every time I tried to associate a Friend entity with a specific user, the target field of ...

The act of securing a host connection and actively monitoring it for

Wondering how to incorporate host listeners and host bindings in Angular 2? In my attempts to use a host listener, I encountered an error message indicating "Declaration Expected". Here's what I tried: In the app.component.ts file: import {Componen ...

Transitioning from angular 5 to angular 6 - What to expect in @angular/core

After upgrading my project from angular 5.2.9 to angular 6.0.0-rc.5, everything seemed to be in order except for a few RxJS fixes in the packages path. One helpful resource I used during the upgrade process was this guide. However, I've run into an i ...

Firebase cloud function encountered an issue: Error: EISDIR - attempting to perform an unauthorized operation on a directory

I am currently working on a task that involves downloading an image from a URL and then uploading it to my Firebase cloud storage. Below is the code I have implemented for this process. import * as functions from 'firebase-functions'; import * a ...

When working with async functions in JavaScript using await, the second function may not necessarily wait for the first function to complete before executing again

My goal is to implement async await in Angular 10 for loading a list of users from the backend database (built with Spring Boot and MariaDB) using an http request, and then filtering that list for one specific user. However, I'm facing an issue where ...

Setting up next-i18next with NextJS and Typescript

While using the next-i18next library in a NextJS and Typescript project, I came across an issue mentioned at the end of this post. Can anyone provide guidance on how to resolve it? I have shared the code snippets from the files where I have implemented the ...

The data type 'null' is not a valid index type to be used in the Array.reduce() accumulator

This is a follow-up inquiry from: How can JavaScript convert multiple key-value pairs in object lists into one nested object? The initial objective was to merge numerous objects with various key-value pairs into a single nested object. For example, start ...

Why is @faker-js/faker not usable in a TypeScript project, showing undefined error, while the older "faker" import still functions correctly?

Currently, my packages.json file includes: "faker": "^5.5.3", "@types/faker": "^5.5.3", I am sticking with version 5.5.3 due to another project dependency (codecept) that requires this specific version. The ...

Utilizing Conditional CSS Classes in React Material-UI (MUI) 5

I am in the process of migrating from React material-ui 4 to MUI 5. How can I implement this particular design pattern using the new styled API (or any other suitable method)? My project is written in Typescript. const useStyles = makeStyles(theme => ...

The polyfills.js script encountered an error due to an undefined reference to exports at line 17

I recently started learning Angular JS and I'm following a tutorial on how to set up an Angular JS project using Visual Studio. However, I encountered an issue with an undefined "exports" variable in one of the JavaScript files (polyfill.js) included ...

Error: Angular 2 and Express - SystemJS Traceur (404) resource not located

I have been working on setting up a MEAN app using angular2 version 2.0.0. After configuring gulp and systemJS, I was able to run gulp without any errors. However, when I tried to start the server, I encountered several errors which you can see here. I su ...

Using TypeScript: Incorporating a map function in type declarations

My current situation involves the following types: type Value = boolean | number | string class Struct<T extends Value[] = Value[]> { constructor(fmt: string) { } pack(...args: T): Buffer { } } I am seeking guidance on how to replace &l ...

Showing the chosen dropdown option using formControlName in ReactiveForms

I have a dropdown menu with validation using formControlName. I also wanted to display the selected option from the dropdown. To achieve this, I used ngModel. However, I encountered an error message stating: It seems that you are using ngModel on the same ...

Handling preflight requests in ASP .NET Core API with Angular and Windows Authentication

Recently, I was given the task of developing the company's internal website using ASP.NET Core 3.0 API and Angular 8. To authorize users, I configured the API Project with Windows Authentication and added it to Startup.cs public void Configu ...

Encountering an error in Jest with TypeScript (Backend - Node/Express) that reads "Cannot use import statement outside a module

Currently, I am in the process of developing Jest tests for a Node/Express TypeScript backend. Recently, I came across the concept of global test setup which I am integrating to streamline the usage of variables and function calls that are repeated in all ...

Encountering issues passing the --aot and --prod flags to the ng build command

I'm having trouble passing flags to ng build. Here is the line of code I have: "build:aot:prod": "node --max_old_space_size=8092 ./node_modules/@angular/cli/bin/ng build --aot --prod" However, it seems to only run ng build without the flags. What co ...

Ionic 2 - Dynamically Loading Segments

I am dealing with categories and dishes. Each dish is associated with a specific category. My goal is to send an http request to retrieve all the dishes belonging to a particular category. This will result in an array like: { Soup[{'Name',&ap ...

Organize Dates in React Table

I need help with sorting the Date column in my code. Currently, the sorting is being done alphabetically. Here is the JSON data and code snippet: JSON [ { "date": "Jun-2022" }, { "date": "Jul-2022" } ...