3

I am having a parent component called providerHome and it has one lightning combo box. Inside providerHome I have child component as dynamicElement and inside dynamic Element I am loading multiPicklist

ProviderHome --> dynamicElement --> multiPicklist

On onchange event of providerHome combobox I want to pass some values for validation so I am using this approach

in providerHome.js

 picklistHandleChange(event) {    
    const dependantValues = {
      controllerEvent: event.target.name,
      inputDesc: this.inputDesc
    };
    this.template
      .querySelector("c-dynamic-element")
      .constructMultiDropDown(dependantValues);  
  }

Inside dynamicElement.js

@api constructMultiDropDown(values) {
   // console.log("values :>> ", JSON.stringify(values));
    this.template
      .querySelector("c-multi-pick-list")
      .multiDropDownConstruct(values);
  
  }

In multiPickList.js

 @api
  multiDropDownConstruct(values) {
    console.log("Reached grand child:>>",values);
  }

From parent --> child its working fine but from Child --> grand child I am always getting error. I cant go for @api approach as this dynamic element component is responsible for loading all lightning components like lightning-input,lightning-combobox etc

I tried this also and not working in providerHome.js

 picklistHandleChange(event) {    
    const dependantValues = {
      controllerEvent: event.target.name,
      inputDesc: this.inputDesc
    };
    this.template
      .querySelector("c-dynamic-element")
      .querySelector("c-multi-pick-list")
      .multiDropDownConstruct(dependantValues);  
  }

Error

enter image description here


I tried by getter/setter. When the page loads I am getting console.log in grand child. After that if i change the drop down in parent component , getter/setter in grand child is not getting fired . Not sure what is the issue

In child(dynamicElement.js)

 @track childDependant = "Initialized";

  @api constructMultiDropDown(values) {
    console.log("Fired becoz of parent combobox change");
    this.childDependant = "Changed";   
  }

HTML

<template>
  <c-multi-pick-list
    label={attrs.label}
    options={attrs.options}
    disabled={attrs.disabled}
    showclearbutton="true"
    showfilterinput="true"
    showrefreshbutton="true"
    from-parent={childDependant}
  ></c-multi-pick-list>
</template>

In grand child (multiPicklist.js)

 _dependantValue;
  @api get fromParent() {
    console.log(this._dependantValue, "this._dependantValue");
    return this._dependantValue;
  }
  set fromParent(value) {
    this._dependantValue = value;
  }

enter image description here


Actually I am using only one template to render multiple fields

  <template for:each={dataForDynamicComponentCreation} for:item="item">
        <div key={item.requiredKey} class="slds-size_1-of-4">
          <div class="slds-m-around_x-small">
            <c-dynamic-element
              attrs={item.attributes}
              tag={item.componentDef}
            ></c-dynamic-element>
          </div>
        </div>
      </template>

So if a lightning-input is created it will created inside <c-dynamic-element> and similarly all will be created inside </c-dynamic-element>

So in order to find out the method inside Multipicklist component I have to do querySelectorAll, loop through it and find out the place where multi picklist is located and then fire. Instead I just did queryselector so always it searched for method in first component(lightning-input) instead where multipicklist is located.

5
  • 1
    first version seems ok, can you specify why it fails?
    – ytiq
    Oct 17, 2020 at 5:27
  • @ytiq not able to find out the exact issue. I am always getting this error pop up . I edited my question above and attached the error image Oct 17, 2020 at 5:45
  • and where this error happens?
    – ytiq
    Oct 17, 2020 at 6:10
  • 2
    The grandparent can't touch the grandchild directly. Api properties or setters are the way to go here.
    – sfdcfox
    Oct 17, 2020 at 6:11
  • @sfdcfox , Even through getter/setter also I am not able get the things properly. Only one time getter is being called. I edited my question above and added whatever I tried Oct 17, 2020 at 8:00

1 Answer 1

3

I have tried a sample code to pass data from parent ===>> child===>> grandchild in Lightning Web Component.

I have used two ways to do so. The first is @api property and another one using querySelector. Both works fine. The below code pass a value from parent to child and then child to grandchild.

parentComponent.html

<template>
    <lightning-combobox name="progress" label="Status in Parent" value={value} placeholder="Select Progress" options={options} onchange={handleChange} >
    </lightning-combobox>

    <hr></hr>
    <c-child-component value-from-parent={value}></c-child-component>
</template>

parentComponent.js

import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
    value = 'inProgress';

    get options() {
        return [
            { label: 'New', value: 'new' },
            { label: 'In Progress', value: 'inProgress' },
            { label: 'Finished', value: 'finished' },
        ];
    }

    handleChange(event) {
        this.value = event.detail.value;
        this.template.querySelector('c-child-component').handleChange(this.value);
    }
}

childComponent.html

<template>
    <lightning-combobox name="progress" label="Status in Child" value={value} placeholder="Select Progress"
            options={options} onchange={handleChange} >
    </lightning-combobox>

    <hr></hr>
    The value from Parent is {valueFromParent}

    <hr></hr>
    <c-grand-child-component value-from-child={value}></c-grand-child-component>
    
</template>

childComponent.js

import { LightningElement, api } from 'lwc';

export default class ChildComponent extends LightningElement {
    value = 'inProgress';
    @api valueFromParent;

    get options() {
        return [
            { label: 'New', value: 'new' },
            { label: 'In Progress', value: 'inProgress' },
            { label: 'Finished', value: 'finished' },
        ];
    }

    @api
    handleChange(valueFromParent) {
        this.value = valueFromParent;
        this.template.querySelector('c-grand-child-component').handleChange(valueFromParent);
    }
}

grandChildComponent.html

<template>
    <lightning-combobox name="progress" label="Status in Grand Child"
            value={value} placeholder="Select Progress" options={options} onchange={handleChange} >
    </lightning-combobox>

    <hr></hr>
    The value from Parent is {valueFromChild}
</template>

grandChildComponent.js

import { LightningElement, api } from 'lwc';

export default class GrandChildComponent extends LightningElement {
    value = 'inProgress';

    @api valueFromChild;

    get options() {
        return [
            { label: 'New', value: 'new' },
            { label: 'In Progress', value: 'inProgress' },
            { label: 'Finished', value: 'finished' },
        ];
    }

    @api
    handleChange(valueFromParent) {
        this.value = valueFromParent;
    }
}

Demo Video

enter image description here

4
  • Thank you. Actually I also followed your approach but the problem is dynamic nature of my LWC. so the template.queryselector caused the issue. FOund out and resolved the issue. Thanks for the effort Oct 17, 2020 at 11:15
  • @SFDC-Beginner, please add your own solution as an answer so there is value in this Q&A for others.
    – Phil W
    Oct 17, 2020 at 16:34
  • @PhilW . Yeah sure. I edited my question and made comment about my solution in the end. Oct 18, 2020 at 9:27
  • I didn't suggest adding it to your question, but as an answer. You don't need to iterate if you are able to add some specific "data-id" (or similar) attribute on the input of interest.
    – Phil W
    Oct 18, 2020 at 10:53

You must log in to answer this question.

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