2

I want to make a copy of an object received through an @api property from a parent component (actually, there are two parent components):

/* eslint-disable no-console */
import { LightningElement, wire, api } from 'lwc';
import getFiltersJson from '@salesforce/apex/QueryFiltersEj.getFiltersJson';
export default class AccountForm extends LightningElement {
@api filters;

@wire(getFiltersJson)
loadFilters({ error, data}){
    if(data){
        //console.log(data);
        console.log(JSON.stringify(data));
        this.filters = data;
    }else if(error){
        console.log(error);
    }
}}

This component receives the filters, and passes to a child component QueryFilters:

import { LightningElement, api } from 'lwc';
export default class LwcQueryFilter extends LightningElement {
@api filters;

@api getFilters(){
    return this.filters;
}

}

Then, I do the same thing, to a child component that holds a single filter:

import { LightningElement, api } from 'lwc';
export default class LwcFilter extends LightningElement {
@api filter;

get isBoolean(){
    return this.filter.type === 'boolean';
}

get isInput(){
    return this.filter.type === 'string' || this.filter.type === 'number';
}

get isSelect(){
    return this.filter.type === 'options';
}

get isMultiSelect(){
    return this.filter.type === 'options-multiple';
}

get isComposable(){
    return this.filter.type === 'composable';
}

get composableSelectFilter(){
    if(this.filter.type === 'composable'){
        return this.filter.filters[0];
    }
}

get composableSecondFilter(){
    if(this.filter.type === 'composable'){
        return this.filter.filters[1];
    }
}

getValue(event){
    const selected = event.target.value;
    console.log(selected);
    this.filter.value = selected;
}

}

How do I make a copy of the single filter in the last component? Or do I have to copy the array of filters received in the parent component that receives the data?

1 Answer 1

3

The answer is to use a setter:

_filter;
@api set filter(value) {
  this._filter = {...value};
}
get filter(value) {
  return this._filter;
}

You can then use _filter as you like. Note that this is only a shallow copy, so if, for some reason, you need deep copy functionality, you'll want to borrow of of the many examples on the Internet, or if performance doesn't really matter, just stringify and parse:

  this._filter = JSON.parse(JSON.stringify(value));
2
  • 1
    Thanks! It solved it. Do you know why doing that in the loadFilters in the parent component doesn't work? Dec 10, 2020 at 14:42
  • 1
    @joacoiudica When the value gets passed in from the parent, it gets wrapped up in another proxy (specifically a readOnly ObservableMembrane). As such, each component that needs to mutate the input needs to make its own copy.
    – sfdcfox
    Dec 10, 2020 at 15:19

You must log in to answer this question.

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