3

I've below two components: Parent & Child. I'm getting array of objects(having two properties) in Parent component and passing that to child component as two individual fields (city & open).

helloParent.html

<template>
    <lightning-card title="Parent-Child Component Composition">
        <div class="slds-m-around_medium">
            <lightning-button variant="brand" label="Get List" title="Get List of Cities" onclick={getCityList}
                class="slds-m-left_x-small"></lightning-button>
            <h1>This is Parent Component</h1>
            <div class="slds-box slds-box_xx-small">
                <lightning-layout multiple-rows="true">
                    <template for:each={cityList} for:item="city">
                        <lightning-layout-item key={city.city} size="12">
                            <c-hello-child-component city={city.city} open={city.open}>
                            </c-hello-child-component>
                        </lightning-layout-item>
                    </template>
                </lightning-layout>
            </div>
        </div>
    </lightning-card>
</template>

helloParent.js

import { LightningElement, track } from 'lwc';

export default class HelloParentComponent extends LightningElement {
    @track cityList
    getCityList() {
        this.cityList = ['London', 'Paris', 'New York', 'Mumbai', 'Sydney'];
        this.cityList = this.randomizeArray(this.cityList);
        this.cityList = this.cityList.map(city => ({ 'city': city, 'open': false }))
        console.log(this.cityList);
    }

    randomizeArray(arr) {
        const randomArr = arr;
        // Randomize the array
        for (let i = randomArr.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * i);
            const temp = randomArr[i];
            randomArr[i] = randomArr[j];
            randomArr[j] = temp;
        }
        return randomArr;
    }
}

Here two field values are displayed

helloChildComponent.html

<template>
    <div onclick={makeTrue}>
        {city} - {open}
    </div>
</template>

I've method in child component where I can update the value of one field i.e. open. False is passed from parent. This method makes it as true.

helloChildComponent.js

import { api, LightningElement } from 'lwc';
export default class HelloChildComponent extends LightningElement {
    @api city;
    @api open;

    makeTrue() {
        if (!this.open) {
            this.open = true;
        }
    }
}

Issue is happening when I'm again clicking 'Get List' button in parent and again the randomized list of cities along with 'open' property value (which is default false) is created and passed to child. However, the value of open field is not updated on child. It still shows the true (if it was updated in child component).

1
  • 2
    Hi, and welcome to SFSE! This is a great first question. If you haven't yet, I'd like to invite you to read about How to Ask and take the tour to get acquainted with our network (though, if this question is any indication, you're already well ahead of the usual learning curve). We hope you enjoy your stay, and look forward to future contributions!
    – sfdcfox
    Commented Aug 26, 2021 at 19:11

1 Answer 1

5

The reason why this happens, is that updating the child's @api property within the child doesn't inform the parent of the change (it still thinks that open is false).

Consequently, when the parent's cityList notices it has been changed, it causes a render cycle, which compares the old values that were in cityList previously to the new values that are in cityList.

Since false === false, the child component's property isn't updated, because no change was detected in the parent's data.

Instead, set the value from the parent:

// in helloChildComponent.js
makeTrue() {
    this.dispatchEvent(new CustomEvent('open',{detail:{city:this.city}}))
}

<!-- in c-hello-parent-component.html -->
<c-hello-child-component onopen={openCity} city={city.city} open={city.open}>

// helloParentComponent.js
openCity(event) {
    this.cityList.find(item => item.city === event.detail.city).open = true
}

Demo


This ensures that elements that have changed are tracked at the parent level, and the children will update accordingly.

1
  • I have a similar scenario, but in my case the value is changes on onchange method which is there on a lightning-input field. I have a checkbox whose value I want to pass to the child, everytime its changed. How can I achieve that? Commented Jul 20, 2023 at 13:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .