In my experience with Angular 8, I have found that the ViewChild() method is successful when used with an array, but does not work

How do I achieve the following functionality: I want a child component to have an input field and a SEND button. When the button is clicked, the value entered in the input field should be displayed in the parent component.

This approach currently works: The child component's input field uses ngModel for two-way data binding. The SEND button triggers a function that adds the current input value to an array. The parent component utilizes ViewChild() to display each new value in the list using *ngFor loop.

Is there a way to accomplish this with just a single value variable instead of an array? The commented-out code (for array implementation) is functioning correctly. Check out the Stackblitz link for reference: Stackblitz

Your assistance on this matter would be greatly appreciated. Thank you.

Child Component
template:
<input type="text" [(ngModel)]="currentMsgToParent">
<button (click)="msgToParent()">send</button>

.ts:
export class Child1Component {
  name = 'Child';

  currentMsgToParent = '';
  // msgFromChild1 = []

  msgToParent() {
    this.currentMsgToParent;
    // this.msgFromChild1.push(this.currentMsgToParent);
  }
}

parent component:
template:
<div class="child1">
  <p><b>Message from Child</b><br> via ChildView():</p>
  <p>{{ currentMsgToParent }}</p>
  <!-- <ul *ngFor="let item of msgFromChild1">
    <li>{{ item }}</li>
  </ul> -->
  <hr>
  <app-child1></app-child1>
</div>

ts.:
export class AppComponent implements AfterViewInit {
  @ViewChild(Child1Component, {static: false}) child1: Child1Component;

  name = 'Parent';
  msgFromChild1: any;
  currentMsgToParent = '';

  ngAfterViewInit() {
    this.currentMsgToParent = this.child1.currentMsgToParent;
    // this.msgFromChild1 = this.child1.msgFromChild1;
  }
}

Answer №1

The issue arises from the fact that the parent component's value update occurs only once, specifically in the ngAfterViewInit hook:

ngAfterViewInit() {
  this.currentMessageFromChild = this.child1.currentMessageToParent;
}

Consequently, the parent view consistently shows the initial value, which is an empty string.

In contrast, if the parent component property is assigned to an array within the child component, both properties point to the same array. Therefore, any modifications made to the array will be reflected in both components. This scenario is akin to having two components sharing a reference to an object, where the child input is connected to a property of that particular object (refer to this stackblitz example).


The conventional method for updating the parent involves event binding using an @Output property. However, if direct referencing of the child component in code is necessary, you can define the parent component property as a getter. This approach guarantees that the displayed value in the view remains current.

get currentMessageFromChild() {
  return this.child1 ? this.child1.currentMessageToParent : "";
}

For a practical demonstration, please see this stackblitz demo.

Answer №2

It is not possible to directly incorporate ViewChild within an ngFor loop in HTML files. However, there is an alternative method that achieves a similar outcome. By utilizing Directives, you can nest ViewChild inside them. To create a Directive, use the command

ng generate directive directive_name
and implement ViewChild within it. Additionally, you can assign attributes to this directive similarly to how you do with components. For the functionality of ViewChild, you must include elementRef as a parameter in the constructor:

constructor(private elementRef: ElementRef)

which will enable the usage of ViewChild.

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

Navigating between child routes in an Angular2 component with two child routers is posing a challenge for me

I have a main component that sets up a Router pointing to 2 child components, each of which also has its own Router setup. Here's an example: Main Component import { Component } from '@angular/core'; import { RouteConfig, ROUTER_DIRECTIVES ...

Ionic npm run build --aot command resulted in Heap Out of Memory Error

A critical error has occurred: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory Normally, I execute the command npm run build --aot After conducting some research online, I attempted the following command, but e ...

Deactivating upcoming weeks according to the year in Angular 8

In the user interface, there are dropdowns for selecting a year and a week. Once a year is selected, the list of weeks for that year is displayed in the week dropdown. Now, the requirement is to disable the selection of future weeks. For example, for the ...

Is there a way to programmatically add a timestamp to a form in Angular6?

Is there a way to automatically populate new forms with the current datetime value? this.editForm.patchValue({ id: chatRoom.id, creationDate: chatRoom.creationDate != null ? chatRoom.creationDate.format(DATE_TIME_FORMAT) : null, roo ...

How to Define Intersection Type with Symbol in TypeScript?

I'm currently working on a helper function that associates a Symbol with a value. function setCustomSymbol<S extends symbol, T>(symbol: S, data: T, defaultValue: any = true): S & T { /*...*/ } The issue I'm facing is trying to instruc ...

Why is it necessary to re-export both * and { default } in zustand.js?

As I delved into analyzing the codebase of zustand, I stumbled upon this snippet in index.ts: export * from './vanilla' export * from './react' export { default as createStore } from './vanilla' export { default } from '. ...

Angular Typescript subscription value is null even though the template still receives the data

As a newcomer to Angular and Typescript, I've encountered a peculiar issue. When trying to populate a mat-table with values retrieved from a backend API, the data appears empty in my component but suddenly shows up when rendering the template. Here&a ...

Which is the superior option: Angular Services or the Typescript Singleton Approach?

How do Angular Singletons compare to TS Singleton patterns? What are the advantages of using Angular's injection over traditional patterns? ...

Navigating through JSON data in an Angular application

I am currently facing an issue with uploading and parsing a JSON file in my Angular application. The problem lies in the fact that even though I can successfully upload the file, I am unable to access the data from it. To ensure the correct file is being ...

Achieve an overlapping effect between absolutely positioned sibling divs without the need to specify a background color

Exploring the development of a swipe-to-action list component. <div class="list-container"> <div class="row"> <div class="content"> Sample Content 1 </div> <div class="action"> ...

Guide to adding a custom font to your Angular 5 project

I am looking to integrate a new font into my Angular 5 project. So far, I have attempted: 1) Moving the file to assets/fonts/ 2) Including it in the styles section of .angular-cli.json However, it seems that the file is not a regular .css file; it is a ...

The Cordova InAppBrowser plugin has not been properly set up

After running cordova plugin list, I noticed that the InAppBrowser plugin is listed. However, when I try to run my code on an android device, I receive this message in the console via Chrome Remote Debugger: Native: InAppBrowser is not installed or you ar ...

Discovering various kinds of data with a single generic type

I am looking to define a specific type like this: type RenderItems<T> = { [K in keyof T]: { label: string; options: { defaultValue: T[K]['options'][current_index_of_array]; item: (value: T[K][&apo ...

Set the variable value by clicking on another component within *ngFor in Angular 2

I am attempting to use *ngFor to pass an object to another component, but only the last object in the table is being passed. The object that was clicked should be displayed instead. How can I solve this issue? <tr data-toggle="control-sidebar" *ngFor=" ...

The issue with the dark/light theming in an input arises when the autocomplete attribute is set to "on"

Seeking advice on applying a light/dark theme to an input field. I have created the input tag in Angular and styled it using Bootstrap for my application. HTML <form [formGroup]="exportDialogueForm"> <div class="form-floating mb- ...

Unsubscribing from a nested observable - a step-by-step

In our Angular component, we leverage the ngOnDestroy() method to handle canceling http requests that are still pending when navigating away from a page. To avoid reloading data that has already been fetched, we utilize a custom generic cache helper on cer ...

A guide to sending data via POST in Angular2 using a service class

As I venture into developing a simple application form and posting data to the server, my Angular2 skills are being put to the test. I am particularly curious about how to smoothly transfer the data from the component to the service and eventually onto th ...

Create a TypeScript type that represents an empty collection

I recently acquired some knowledge about TypeScript through a university course I took this month. Is it possible for this to represent an empty set? type emptySet=0&1; Whenever I attempt to assign this to any value (for example: boolean, number, st ...

Does Angular 8 development mode implement tree-shaking?

I am curious to know if tree-shaking occurs during Angular 8 development mode. When running the following command: ng build I understand that tree-shaking happens when I use the command below: ng build --optimization=true|false ...

Unexpected TypeError when using Response.send()

Here is a snippet of my simple express code: const api = Router() api.post('/some-point', async (req, res, next) => { const someStuffToSend = await Promise.resolve("hello"); res.json({ someStuffToSend }); }) In my development environmen ...