Bidirectional Data Binding in an Angular 2+ Element

I am facing an issue with my Ionic application. I have created a component to display data of an object, but the problem is that when I update the data in the parent component, the changes are not reflected in the child component:

my-card.component.ts

@Component({
    selector: 'my-card',
    templateUrl: './my-card.html'
})
export class MyCard {
    @Input('item') public item: any;
    @Output() itemChange = new EventEmitter();
    constructor() {

    }

    ngOnInit() {
        // Performing an AJAX call here to fetch more data and populate additional fields in the item.
        this.getMoreData().subscribe(data => {
            if (data.item){
                this.item = data.item;
            }
            this.itemChange.emit(this.item);
        });
    }
}

my-card.html

<div class="comment-wrapper" *ngFor="let subitem of item.subitems">
    {{subitem.title}}
</div>

In the parent component, I use the child component like this:

<my-card [(item)]="item"></my-card>

Here is the ts file for the parent component:

@IonicPage()
@Component({
    selector: 'page-one',
    templateUrl: 'one.html',
})
export class OnePage {
    public item = null;
    constructor(public navCtrl: NavController, public navParams: NavParams) {
        this.item = {id:1, subitems:[]};
    }

    addSubItem():void{
        // Making an AJAX call to save the new item to the database and retrieve the new subitem.
        this.addNewSubItem().subscribe(data => {
            let newSubItem = data.item;
            this.item.subitems.push(newSubItem);
        }
    }
}

However, when I call the addSubItem() function, the component does not update and the ngFor loop still does not display anything.

Answer №1

When making an API request, it's important to consider how you handle the object reference. Assigning a new value can cause the original input value from the parent to be overwritten, resulting in the objects no longer pointing to the same object. To achieve two-way binding, consider using Output:

Child Component:

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

// ..

@Input() item: any;
@Output() itemChange = new EventEmitter();

ngOnInit() {
  // Perform an AJAX call here to fetch additional data for the item.
  this.getMoreData(item.id).subscribe(data => {
    this.item = data;
    // 'Recreate' the object reference
    this.itemChange.emit(this.item)
  });
}

By following this approach, you ensure that both parent and child components reflect changes made to the shared object.

Answer №2

When the `getMoreData` function returns an observable, the code should be structured like this:

ngOnInit() {
    // Making an AJAX call here to fetch additional data for the item.
    this.getMoreData().subscribe(
        updatedItem => this.item = updatedItem
    );
}

The `subscribe` method triggers the asynchronous operation and returns an observable. Upon receiving the data from the async operation, it runs the specified callback function and updates the value of the item with the returned data.

Answer №3

Your declared item using the @Input() decorator appears as follows:

 @Input('item') public item: any;

However, you are attempting to use two-way binding on it:

<my-card [(item)]="item"></my-card>

If it is meant to be an input only, then it should be

<my-card [item]="item"></my-card>

When you call addSubItem(), it should display the newly added item.

    this.item = this.getMoreData();

The use of getMoreData() doesn't seem appropriate if you intend to utilize the item passed via the @Input() method in your card component.

Answer №4

Your component interactions may need some adjustments. Take a look at the Angular documentation for guidance (https://angular.io/guide/component-interaction). It's recommended to utilize ngOnChanges (https://angular.io/guide/component-interaction#intercept-input-property-changes-with-ngonchanges) or consider using a service to efficiently communicate changes between parent and child components (https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service).

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

Switch out the checkbox for a span for a different approach

Working with Angular 9 reactive forms, I am currently using the following form setup: <form [formGroup]="form" (ngSubmit)="onSubmit()"> <label for="active">Active</label> <input id="active" type="checkbox" formCo ...

Communication breakdown between Angular frontend and Java backend leads to failed calls with no specific error reported

While working on my Angular project that connects to a Java backend (REST API), I encountered an issue. Despite completing the project basics, I faced difficulties in implementing advanced calls. Specifically, when trying to add a new method, the request f ...

Show only the lower left quadrant within the img tag during the prepend operation

I'm attempting to add an <img> tag in front of a <div> similar to this example on JSFiddle. However, I have a specific requirement to only display the bottom left quarter of the image instead of the entire one. HTML Markup <div id="my ...

I am restricted from using history with BrowserRouter in Typescript

Trying out React and decided to experiment with TypeScript. Code: import { BrowserRouter } from 'react-router-dom' import history from './utilities/history' ReactDOM.render( <BrowserRouter history={history}> <App /> ...

Transmitting JSON and FormData between Angular and Spring

Angular Tutorial processRegistration(user: any, file: File): Observable<any>{ let formData = new FormData(); formData.append("user", JSON.stringify({username:'User'})); formData.append("file", file); return this. ...

Creating a split button can be enhanced by incorporating a disabled button with a tooltip feature

I am attempting to create a split button using Material UI components such as ButtonGroup and Button. You can find more information about split buttons here. The issue I am facing is that the first button may need to be disabled and display a tooltip when ...

Enhancing your comprehension of JavaScript

What method does this script use to determine the current day of the week as Tuesday? let currentDate = new Date(); let currentDay = currentDate.getDay(); let daysOfTheWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] ...

Using npm to trigger the package.json file will activate both the harp and browser-sync applications

I am looking for a way to simultaneously start a harp.js server and run a browser-sync process. This setup works perfectly on Linux with the following package.json configuration: { "scripts": { "dev": "bash ./serve.sh" } } Here is the content of ...

What is a superior option to converting to a promise?

Imagine I am creating a function like the one below: async function foo(axe: Axe): Promise<Sword> { // ... } This function is designed to be utilized in this manner: async function bar() { // acquire an axe somehow ... const sword = await foo ...

JS - Reducing in size increases request size

I'm facing an issue with compressing my request - instead of reducing the size, it seems to be increasing it: const requestData = LZString.compress(JSON.stringify({ data: bigBase64StringHere })); await axios.post("api-endpoint", requestData, ...

What is the best way to calculate the total of elements from multiple arrays of various lengths using Javascript?

Is there a way to modify the code below to allow for adding an arbitrary number of arrays as arguments? For instance, how can I adjust it so that ([1, 2, 3], [4, 5], [6]) would result in an array of [11, 7, 3]? function addArrays(...arrays) { let resu ...

Creating a responsive DataTable filled from a $.ajax request is a straightforward process that can greatly

I am in the process of creating an application that retrieves a lot of data from a web-service query and populates a data table with it. The data shows up correctly and styled properly on desktop, but when I switch to viewing it on a mobile device, the dat ...

How can you transform a nested array into a flat JavaScript map?

If we consider a JavaScript Map structured like this: [ { id: 1, name: "Foo", contents: [1,2,3], morecontents: ["a","b"], }, { id: 2, name: "Bar", c ...

Converting an object to an array with the help of jQuery

I have been working with a json file and created an object using jquery's $.get method. Here is what it looks like when I log it: console.log(array); [Object, Object, Object, Object, Object, Object, Object, Object] 0 : Object country ...

Invoke a particular function from a remote PHP file using the remote method in jQuery Validate

I am utilizing the jQuery Validate plugin to validate fields on my registration page. Within my validation JS, I have code that checks if a username already exists: "remote": { url: "../assets/php/checkUsername.php", type: "post", data: { ...

Tips for creating a vertical drawer using jQuery and CSS

Hello, I am currently working on developing a drawer component using Ember.js. If you want to view the progress so far, feel free to check out this jsbin http://jsbin.com/wulija/8/edit My goal is to have the drawer look like the following initially: +--- ...

Fixing a div at the top post scroll - bug on iOS mobile device

I am looking to achieve a similar effect as demonstrated in the example below: https://css-tricks.com/scroll-fix-content/ Essentially, the goal is to have a div become fixed at the top of the page after scrolling to a certain point. Initially, the div wil ...

Choose the property category

Is there a more efficient way to specify the type of a property in TypeScript without resorting to casting? Take a look at this example: interface Overlay { type: "modal" | "drawer" other?: number } const rec = { obj1: { ty ...

What are the steps for sending a file?

I am looking to send an image to my telegram bot using JavaScript, without the use of Node.js. To achieve this, I require the token of the bot and my Telegram user ID. While sending text messages is successful, I have also managed to send photos by provid ...

Generate an Array reference using the index of elements instead of duplicating the values

When initializing b, it appears that the array data is being copied from a instead of referencing it, as originally intended: let a = [0,1]; let b = [a[0], 2]; a[0]=3; console.log(b); The resulting output is 0,2. What is the reason for the output not ...