`Unresponsiveness in updating bound property after change in Angular2 child property`

Having trouble with my custom directive and ngOnChanges() not firing when changing a child property of the input.

my.component.ts

import {Component} from 'angular2/core';
import {MyDirective} from './my.directive';

@Component({
    directives: [MyDirective],
    selector: 'my-component', 
    templateUrl: 'Template.html'
})

export class MyComponent {
    test: { one: string; } = { one: "1" }

    constructor( ) {
        this.test.one = "2";
    }
    clicked() {
        console.log("clicked");
        var test2: { one: string; } = { one :"3" };
        this.test = test2; // THIS WORKS - because I'm changing the entire object
        this.test.one = "4"; //THIS DOES NOT WORK - ngOnChanges is NOT fired=
    }
}

my.directive.ts

import {Directive, Input} from 'angular2/core';
import {OnChanges} from 'angular2/core';

@Directive({
    selector: '[my-directive]',
    inputs: ['test']
})

export class MyDirective implements OnChanges {
    test: { one: string; } = { one: "" }

    constructor() { }

    ngOnChanges(value) {
        console.log(value);
    }
}

template.html

<div (click)="clicked()"> Click to change </div>
<div my-directive [(test)]="test">

Looking for help on why ngOnChanges isn't firing in this scenario. Thanks!

Answer №1

It's important to note that Angular2 does not support deep comparison, only reference comparison, which is considered normal behavior. For more information on this limitation, refer to this issue: https://github.com/angular/angular/issues/6458.

However, there are some workarounds available to notify a directive when certain fields in an object have been updated.

  • Directly referencing the directive from the component:

    export class AppComponent {
      test: { one: string; } = { one: '1' }
      @ViewChild(MyDirective) viewChild:MyDirective;
    
      clicked() {
        this.test.one = '4';
        this.viewChild.testChanged(this.test);
      }
    }
    

    In this scenario, the testChanged method of the directive is explicitly called. You can see an example of this in action here: https://plnkr.co/edit/TvibzkWUKNxH6uGkL6mJ?p=preview.

  • Utilizing an event within a service:

    A specific service defines the testChanged event

    export class ChangeService {
      testChanged: EventEmitter;
    
      constructor() {
        this.testChanged = new EventEmitter();
      }
    }
    

    The component uses the service to trigger the testChanged event:

    export class AppComponent {
      constructor(service:ChangeService) {
        this.service = service;
      }
    
      clicked() {
        this.test.one = '4';
        this.service.testChanged.emit(this.test);
      }
    }
    

    The directive subscribes to the testChanged event to be notified of updates

    export class MyDirective implements OnChanges,OnInit {
      @Input()
      test: { one: string; } = { one: "" }
    
      constructor(service:ChangeService) {
        service.testChanged.subscribe(data => {
          console.log('test object updated!');
        });
      }
    }
    

I hope this provides some clarity on the subject, Thierry

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

The table gets disrupted by the presence of an Angular child component

I am facing an issue with my Angular component when trying to use it within a table using ngFor. This is how my table is structured: <table class="table table-stripped"> <thead> <th style="width: 30%;">Network< ...

The Next.js 13 function getQueriesData does not have any matching overloads for TypeError

Having a TypeScript error issue while using the getQueriesData function in Next.js 13 with React Query. Below is my code snippet: // app/products.tsx import { getQueryClient } from "@/app/providers/getQueryClient"; import { useQuery, useQueryCli ...

Having trouble with errors when adding onClick prop conditionally in React and TypeScript

I need to dynamically add an onClick function to my TypeScript React component conditionally: <div onClick={(!disabled && onClick) ?? undefined}>{children}</div> However, I encounter the following error message: Type 'false | (() ...

Passing data to an Angular 6 component when selecting from router menu

I've implemented a navmenu component like this: <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class='glyphicon glyphicon-wrench'></span> Configuration<span cla ...

Issue R10 (Start-up delay) -> Failure of web application to connect to $PORT in the given 60 seconds after being launched (Angular)

I am currently in the process of building an Angular 7 application and attempting to connect it to Heroku (I am fairly new to using Heroku). Upon trying to run the application on Heroku, I encountered the following error: https://i.stack.imgur.com/ySmJw.p ...

Tips for organizing your CSS from scratch without relying on a pre-existing framework such as bootstrap, bulma, or materialize

As I embark on a new Angular project, the decision has been made to create our own component library instead of using frameworks like Bootstrap, Bulma, or Materialize. Despite some initial research, I'm feeling a bit lost on where to begin (other than ...

Tips for sending information back to the previous screen in React Native Navigation version 5

Recently, I upgraded to react native navigation version 5 and now I am facing an issue with sending data back to the previous screen when making a goBack() call. To navigate to the next view, I use: const onSelectCountry = item => { console.log(it ...

Can an L1 VPC (CfnVpc) be transformed into an L2 VPC (IVpc)?

Due to the significant limitations of the Vpc construct, our team had to make a switch in our code to utilize CfnVpc in order to avoid having to dismantle the VPC every time we add or remove subnets. This transition has brought about various challenges... ...

The specified property cannot be found on the object type in a Svelte application when using TypeScript

I am attempting to transfer objects from an array to components. I have followed this approach: https://i.stack.imgur.com/HHI2U.png However, it is indicating that the property titledoes not exist in this type. See here: https://i.stack.imgur.com/VZIIg.pn ...

leveraging Angular 2 in combination with an express-node js API

Hello, I’m currently trying to wrap my head around the installation of Angular JS v2. After going through numerous tutorials, I find myself feeling quite confused. Some tutorials mention using webpack to set up a server for the application, while other ...

What is the best way to generate conditional test scenarios with Protractor for testing?

Currently, there are certain test cases that I need to run only under specific conditions. it ('user can successfully log in', function() { if(siteAllowsLogin) { ..... } The problem with the above approach is that even when sitesNo ...

The compilation of the module has encountered an error with the PostCSS loader. There is a SyntaxError at line 2, character 14 indicating an unknown

I am developing an Angular 8 application. Currently, I am incorporating AlertifyJs into my project. In the styles.css file of Angular, I have imported these libraries: @import '../node_modules/alertifyjs/build/alertify.min.js'; @import '. ...

Adjust the color of an SVG icon depending on its 'liked' status

In my React/TypeScript app, I have implemented an Upvote component that allows users to upvote a post or remove their upvote. The icon used for the upvote is sourced from the Grommet-Icons section of the react-icons package. When a user clicks on the icon ...

What is the best way to perform an AJAX request in Typescript with JSON data?

Currently, I am delving into the realm of AJAX and encountering some hurdles when attempting to execute an AJAX request with parameters. Specifically, I am facing difficulties in sending JSON data: My approach involves utilizing Typescript in tandem with ...

Retrieve the value of an object without relying on hardcoded index values in TypeScript

I am working with an object structure retrieved from an API response. I need to extract various attributes from the data, which is nested within another object. Can someone assist me in achieving this in a cleaner way without relying on hardcoded indices? ...

When organizing Node.js express routes in separate files, the Express object seamlessly transforms into a Router object for efficient routing

I am currently working on a Node.js application with Express. I organize my routes using tsoa, but when I introduce swagger-ui-express to the project, an error occurs Error: TypeError: Router.use() requires a middleware function but got undefined Here is ...

What is a simple way to exclude a prop from a declaration in a React/TypeScript project in order to pass it as undefined

I'm trying to accomplish this task but encountering a typescript error indicating that the label is missing. Interestingly, when I explicitly set it as undefined, the error disappears, as shown in the image. Here's how my interface is structured ...

What is the reason behind Typescript's discomfort with utilizing a basic object as an interface containing exclusively optional properties?

Trying to create a mock for uirouter's StateService has been a bit challenging for me. This is what I have attempted: beforeEach(() => { stateService = jasmine.createSpyObj('StateService', ['go']) as StateService; } ... it(& ...

Self-referencing type alias creates a circular reference

What causes the discrepancy between these two examples? type Foo = { x: Foo } and this: type Bar<A> = { x: A } type Foo = Bar<Foo> // ^^^ Type alias 'Foo' circularly references itself Aren't they supposed to have the same o ...

Tips for retrieving the most recent number dynamically in a separate component without needing to refresh the page

Utilizing both the Helloworld and New components, we aim to store a value in localStorage using the former and display it using the latter. Despite attempts to retrieve this data via computed properties, the need for manual refreshing persists. To explore ...