Is the @Output decorator in Angular limited to working only with click events?

Could someone help me understand why I am unable to pass data from the child component to the parent component with a variable value? It seems that changes made in the child component are not reflecting in the parent component. Is it possible that the @Output decorator only works with click events triggered in the child component? I also experimented with using event emitters within different methods like the constructor or ngOnInit, but still no luck.

Child component:

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

@Component({
selector: 'app-server',
templateUrl: './server.component.html',
styles: [
 `.online {
   color: white;
}
`
]
})
export class ServerComponent {
serverId: number = 10;
serverStatus: string = 'offline';
serverName: 'Random server';

@Output() serverNameEmitter = new EventEmitter<string>();

constructor() {
    this.serverStatus = Math.random() > 0.5 ? 'online' : 'offline';
}

ngOnInit(): void {
    this.passServerName(this.serverName);
}

passServerName(serverName: string) {
    this.serverNameEmitter.emit(serverName);
}

getColor() {
    return this.serverStatus == 'online' ? 'green' : 'red';
}
getServerStatus() {
    return this.serverStatus;
}
}

Parent component

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-servers',
  templateUrl: './servers.component.html',
  styleUrls: ['./servers.component.css'],
})
export class ServersComponent implements OnInit {
allowNewServer = false;
serverCreationStatus = 'No server was created!';
serverNames = "";
serverStatus = false;
servers = [];

serverName = {
   name: "Test server"
};

constructor() {
  setTimeout(() => {
    this.allowNewServer = true;
  }, 2000);
}

ngOnInit(): void {}

onCreateServer() {
 this.serverStatus = true;
 this.servers.push(this.serverName.name);
 this.serverCreationStatus = 'Server has been created! Name is ' + this.serverName.name;
}

onUpdateServerName(event: Event) {
 this.serverNames = (event.target as HTMLInputElement).value;
}

changeServerName() {
 this.serverName.name = this.serverNames;
}

gettingServerName(serverName: string) {
  this.serverNames = serverName;
}
}

Parent component HTML

<label>Server Name</label>
<input type="text" class="form-control" (input)="onUpdateServerName($event)">

<button class="btn btn-primary" [disabled]="!allowNewServer" 
(click)="onCreateServer()">Add Server</button>

<p>Here's {{ serverNames }}</p>
<p *ngIf="serverStatus; else noServer">Server was created, server name is {{ 
   serverName.name }}</p>
<ng-template #noServer>
<p>No server was created!</p>
</ng-template>

<button class="btn btn-primary" (click)="changeServerName()">Change server name</button>
<app-server *ngFor="let server of servers" 
(serverNameEmitter)="gettingServerName($event)"></app-server>

Answer №1

To prevent the ExpressionChangedAfterItHasBeenCheckedError, you can trigger change-detection manually every time gettingServerName() is called without needing to use a timeout, as Flo suggested.

Simply include the ChangeDetectorRef in your code:

  import { ChangeDetectorRef } from '@angular/core';

Inject it into your constructor and then invoke detectChanges() at the end of the gettingServerName() method:

  constructor(private cdRef: ChangeDetectorRef) {}

  gettingServerName(serverName: string) {
    this.serverNames = serverName;
    this.cdRef.detectChanges();
  }

It's worth mentioning that you may not be utilizing @Output as intended.

Answer №2

Hey there! I've successfully set up a Stackblitz project using your provided code. However, there's something that doesn't quite make sense to me.... You're able to set a new server name in the parent component and add a new server, but you never actually assign the name to the child if it's created. As a result, the child emits the event (which works fine), and you always set the serverNames to be "Random server."

The one issue I noticed is that you'll receive an ExpressionChangedAfterItHasBeenCheckedError if you emit the serverName from the child during onInit(). A simple workaround for this is to use setTimeout.

Feel free to check out the Stackblitz and experiment with it yourself. If you have any further questions, don't hesitate to reach out.

Best regards, Flo

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

Identifying mismatches in data mapping

I'm currently working on combining multiple observables into a single observable using RXJS and the CombineLatest operator. Initially, my code was functioning correctly with 6 observables, but upon adding 5 more, the compiler started encountering issu ...

Find all objects in an array that have a date property greater than today's date and return them

I have an array of objects with a property called createdDate stored as a string. I need to filter out all objects where the createdDate is greater than or equal to today's date. How can this be achieved in typescript/javascript? notMyScrims: Sc ...

Steps to retrieve the search box input value and submit it in an AngularJs component using the Enter key

I'm facing an issue where I am trying to fetch the search list using speciesName from a table. However, when I attempt to retrieve the data by pressing the enter key, it is returning an error stating that the input data is undefined. Is there a way ...

What could be causing Angular to replace the original variable?

As a newcomer to Angular, I've been working on this code for hours now. Hopefully, it will all come together for someone out there who can make sense of it. export class QuizComponent implements OnInit { originalArray: IArray[] = []; tempArray: I ...

What are the steps to successfully upload a nestjs application (using typescript) onto the heroku

After creating a nestjs app, I am now seeking the most efficient way to deploy it on Heroku for production environment. Upon attempting to deploy the code generated by nest-cli as-is, I received the following logs from Heroku: 2018-12-28T08:37:23.881261+ ...

MatIconRegistry import error in Angular Material

Currently, I am using 'Angular: 10.0.14' along with '@angular/material 10.2.7'. However, when attempting to import MatIconRegistry, I encountered the following error message: ERROR in node_modules/@angular/material/icon/icon-registry.d ...

Rephrased: "Revamping Angular2 with

I am currently working on developing a mobile web application using Angular2. Everything runs smoothly when I test the project locally, but once I push it to our production system, issues arise. I suspect that the problem lies with Apache Rewriting! Here ...

How does Angular2 indicate the modification in a segment of Component?

ReactJs utilizes virtual DOM for rendering changes, whereas Angular2 does not have a virtual DOM. However, Angular2 is reactive similar to ReactJS. In Angular2, with any change, the whole component does not need to be modified, only the portion of the co ...

Updated TypeScript definitions for Node.js version 2.0 available now with @

I've recently started using the new @typings feature, and I noticed that when I run npm install --save @types/react, it creates an @typings folder within the node_modules directory. Additionally, it adds the dependency @types/react: ^0.14.43 in the pa ...

Angular 5 encountering net::ERR_UNKNOWN_URL_SCHEME error while trying to load an image served from an Express

I'm struggling to display an image from my node.js (express server) localhost:3000/assets/images/uploads in my Angular 5 app. When I enter the URL in the browser, the image displays correctly. However, when I try to assign it to a variable and bind it ...

Learning how to effectively incorporate two matSuffix mat-icons into an input field

I'm currently experiencing an issue where I need to add a cancel icon in the same line as the input field. The cancel icon should only be visible after some input has been entered. image description here Here's the code I've been working on ...

The expiration of the Gitlab CI/CD cache leads to the failure of the build process

I have an AWS CDK application in TypeScript and a simple GitLab CI/CD pipeline with 2 stages for deployment: image: node:latest stages: - dependencies - deploy dependencies: stage: dependencies only: refs: - master changes: - ...

Create an array that can contain a mix of nested arrays and objects

Working on my project using Angular and TypeScript includes defining an array that can contain arrays or objects. public arrangedFooterMenu: IMenuItemType[][] | IMenuItemType[] = []; typesOfData.forEach(type => { let filteredData: IMenuItemType | ...

Executing two webservice calls in Angular 9 using both dispatch and subscribe methods

I am facing an issue where my create account API is being called twice. I noticed that when I remove the constructor part, the API is only called once, but I need to ensure that my account creation is successful. The double call to the web service occurs ...

Setting up a create-react-app project with TypeScript to include local packages within the src folder

In my create-react-app project, I utilize TypeScript and local private packages that are intended to be shared across multiple apps with their own repositories. My goal is to have these local packages located in the src/packages folder. The current folder ...

Karma Unit test: Issue with accessing the 'length' property of an undefined value has been encountered

While running karma unit tests, I encountered a similar issue and here is what I found: One of my unit tests was writing data to a json file, resulting in the following error: ERROR in TypeError: Cannot read property 'length' of undefined a ...

Effortless Tree Grid Demonstration for Hilla

As someone who is just starting out with TypeScript and has minimal experience with Hilla, I kindly ask for a simple example of a Tree Grid. Please bear with me as I navigate through this learning process. I had hoped to create something as straightforwar ...

Retrieve the selected rows in AG grid based on their group index

Important: The data in the grid is organized into groups. I am attempting to retrieve selected rows at a specific group index. I have attempted using the getDisplayedRowAtIndex(index).allLeafChildren method and looping through each node to find those tha ...

Tips on how to effectively simulate a custom asynchronous React hook that incorporates the useRef() function in jest and react-testing-library for retrieving result.current in a Typescript

I am looking for guidance on testing a custom hook that includes a reference and how to effectively mock the useRef() function. Can anyone provide insight on this? const useCustomHook = ( ref: () => React.RefObject<Iref> ): { initializedRef: ...

Trouble encountered when attempting to call a function within another function in StencilJS

I am currently following a tutorial on building a drag and drop file uploader using StencilJS for some practice and fun. However, I have encountered an error in the code. Below is a snippet of the code, but I can provide more if necessary. @Component({ ...