Angular 5 seems to be experiencing issues with the function ngOnChanges() not functioning correctly

I have been attempting to trigger the ngOnChanges() function in my Angular 5.x component whenever there is a change in the variable this.test either in the component lifecycle or the template. However, I am encountering an issue where the ngOnChanges() function is not being called at all. Can someone please provide assistance?

src/app.ts:

import {Component, NgModule, Input, OnChanges, SimpleChanges} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <input type="text" placeholder="Test field" value="{{ test }}">
    </div>
  `,
})
export class App implements OnChanges {
  @Input() test: string;
  name: string;
  constructor() {
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('ngOnChanges');

    if (changes.test && !changes.test.isFirstChange()) {
      // exteranl API call or more preprocessing...
    }

    for (let propName in changes) {
      let change = changes[propName];
      console.dir(change);
      if(change.isFirstChange()) {
        console.log(`first change: ${propName}`);
      } else {
        console.log(`prev: ${change.previousValue}, cur: ${change.currentValue}`);
      }
    }
  }


}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

Live preview: https://plnkr.co/edit/ZHFOXFhEkSv2f1U3lehv

Any help would be greatly appreciated!

Answer №1

Input properties serve as a way for a parent component to send data to a child component. They should not be used to transfer data from a template to its component.

The onChanges method is only triggered by changes made to the input property defined by the PARENT component.

I have made updates to the plunker by fixing the missing FormsModule and adding a child component to illustrate how to utilize the input property and the onChanges lifecycle hook:

https://plnkr.co/edit/1JF0wV28HnjXDZxMSifY?p=preview

Child Component

@Component({
  selector: 'my-child',
  template: `
    <div>
      <input type="text" [(ngModel)]="test" placeholder="Test field">
    </div>
  `,
})
export class ChildComponent implements OnChanges {
  @Input() test: string;
  name: string;
  constructor() {  }

  ngOnChanges(changes: SimpleChanges) {
    console.log('in ngOnChanges');
    if (changes.test && !changes.test.isFirstChange()) {
      // external API call or more preprocessing...
    }

    for (let propName in changes) {
      let change = changes[propName];
      console.dir(change);
      if(change.isFirstChange()) {
        console.log(`first change: ${propName}`);
      } else {
        console.log(`prev: ${change.previousValue}, cur: ${change.currentValue}`);
      }
    }
  }
}

Parent Component

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <my-child [test]='parentTest'></my-child>
      <button (click)='onClick()'>Change Value</button>
    </div>
  `,
})
export class App {
  parentTest: string;
  name: string;
  counter = 1;

  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

  onClick() {
    this.parentTest = `test: ${this.counter}`;
    this.counter++;
  }
}

To detect changes from the template in the template's component, use a setter instead:

  // To catch changes from the template
  _test: string;
  get test(): string {
    return this._test;
  }

  @Input()
  set test(value: string) {
    this._test = value;
    console.log("Textbox value changed: " + this._test);
  }

Alternatively, you can follow Sajeetharan's suggestion to capture changes from the template in its corresponding component. This approach will also be effective.

Answer №2

If you're looking to detect model changes, consider using ngModelChange instead of ngOnChanges.

<input type="text" placeholder="Test field" (ngModelChange)="printVal()">

Then, in your component:

printVal(){
  // Implement logic to detect model change here
}

ngOnChanges is typically used with @Input event emitters.

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

Is it a bad idea to incorporate JavaScript functions into AngularJS directives?

I came across this snippet of code while working with ng-repeat: <div ng-show="parameter == 'MyTESTtext'">{{parameter}}</div> Here, parameter represents a string variable in the $scope... I started exploring if it was possible to c ...

Use jQuery to duplicate an image that has the "active" class, then assign it as the background image for a div element

I am utilizing the default carousel from Twitter Bootstrap to create a basic slider. What I aim to do is, when an item becomes active, the image inside that item should be duplicated and set as the background image for the div with the 'testimonials-b ...

Enhancing the Appearance of HTML Select Dropdowns in JavaFX 2.2 WebEngine

I am currently working on a project that is unable to be updated to Java 1.8 to support the latest JavaFX version. While this may or may not impact the issue I am facing, I have been exploring various solutions from the internet to customize the look and f ...

Creating a Jest TypeScript client mock that returns an array filled with undefined elements instead of the expected resolved values

At the moment, I am in the process of writing tests for a helper function that I created. This function takes a client and an array as parameters. Essentially, the function is designed to retrieve all tasks for all sites on a website. So far, the method is ...

The seamless integration of React.js with HTML

My friend and I are beginners in the world of programming, with a solid grasp of html, CSS, and JavaScript. We're currently collaborating on a small project where we aim to create a chat system. While researching resources for our project, we came acr ...

Error encountered while executing ExpressJs function that was converted to a promise

Understanding how errors are handled in promises can be a bit tricky, especially for someone new to promises like myself. I'm trying to make the most of them, but I'm not quite there yet. Here is the code snippet I'm working with: app.list ...

Creating a versatile Express Router that can serve multiple websites by utilizing conditional routes based on the domain name

Instead of suggesting changes to my application architecture, I am seeking practical solutions for my specific requirements. I have code that serves different static files based on the domain name, allowing me to run multiple static HTML sites from the sam ...

Tips for including MUI icon within a list displayed on a map:

Initially, I brought in the AccountCircle Icon from MUI: import { AccountCircle } from '@mui/icons-material'; Then, I utilized styled to customize the icon: const UserIcon = styled(AccountCircle)({ margin: '0px 0px 0px 0px', }); My ex ...

Guide on retrieving documents from a collection in mongodb by utilizing the $nin operator

My user schema looks like this const userSchema= new mongoose.Schema({ Username:{ type:String, trim:true, required:true }, email:{ type:String, trim:true, required:true }, hashed_password:{ type:String, trim:t ...

Animate the removal of a div message with the help of CSS and jQuery

To display a success message in PHP, I use the following code snippet: <div class='alert alert-success'>Success!!</div> In addition to that, I have implemented a CSS3 animation called Animate: .animated { -webkit-animation-durati ...

Displaying the value of a jquery variable in an HTML document

I'm tackling a problem differently today compared to yesterday, but my knowledge of jQuery and JavaScript is quite basic. My goal is to increment the transform value of a div every 5 seconds: <div style="transform: translateX(0px);" id="slide_ima ...

Ways to mock a static method within an abstract class in TypeScript

Having a difficult time testing the function Client.read.pk(string).sk(string). This class was created to simplify working with dynamoDB's sdk, but I'm struggling to properly unit test this method. Any help or guidance would be greatly appreciate ...

Error: The "require" function is not recognized within the Rollup bundle JavaScript file

Recently, I've been utilizing rollup to bundle my JavaScript files designed for integration with three.js. It got me thinking about minimizing and bundling the three.js files using rollup.js as well. To achieve this, I used npm and executed the comman ...

Mapping over an array and ignoring any undefined properties in a dynamic object

Looking for a way to dynamically create objects in the 'map' function to reduce the final array size. The goal is to avoid adding properties with undefined values. For example, if 'offst: undefined', skip this property but add others wi ...

What are the steps to integrate DeviceOrientationControls with scrolling on iOS 13?

I am currently using DeviceOrientationEvents data to animate the rotation of a camera in three.js using DeviceOrientationControls. The controls are updated with each animation frame, and everything is functioning as expected. However, I have noticed that w ...

What could be causing my AngularJs routing and animation to bypass the second redirection?

Recently started working with Angular and experimenting with routing and animations to manage my page transitions. I followed a helpful guide that helped me set everything up. I encountered a few issues: When trying to link back to the landing page (home ...

Is there a way for me to personally include pages in the browser's cache?

My webpage currently sends two requests: one to /login and another to /treeContents?rootID=9. I am interested in combining them into one request, specifically /loginAndTreeContents?rootID=9 The original method stores subsequent responses from /treeContent ...

What is the best way to create a responsive Toolbar with collapsible overflowing buttons that does not rely on setTimeout()?

Currently in the process of developing a toolbar for my richTextEditor tool, Tiptap. My goal is to have buttons that exceed the width of the editor hidden under a "more" button. I stumbled upon a Reddit post discussing this concept but am encountering diff ...

What is the best way to verify in Nest.js that a DTO is a number and not blank?

I'm attempting to ensure the validity of a request using DTO. The validation requirements are that the value must be a number and cannot be empty. Upon trying to use just the IsNumber() decorator and sending a body with an empty property, the validat ...

Clicking on the Google Maps direction service can add additional markers to the map

If you can help me create a Google Maps direction service between two points or markers on a map click event, it would be greatly appreciated. I've set up a fiddle to demonstrate that when you click on the map for a second time, a third marker is dis ...