In LWC JavaScript controller splice method not working with @api variable which is an array

1.1k Views Asked by At

In console this.unselectedPlayerList.length is not shown, It will shown before using splice method. So I have doubt in splice method.

export default class MakeYourTeamChild extends LightningElement {
    @api unselectedPlayerList=[];
    SelectPlayer(event)
    { 
        for(let index = 0 ; index < this.unselectedPlayerList.length; index++)
        {
            if(this.unselectedPlayerList[index].Name == event.target.title)
            {
                this.selectedPlayer = this.unselectedPlayerList[index].Name;
                this.unselectedPlayerList.splice(index,1);
                console.log('After Splice',this.unselectedPlayerList.length);
            }
        }
    }
}
2

There are 2 best solutions below

1
Sahil Goyal On

As per my understanding, we can't update or edit the @api variable by using splice(), push(), and concat() methods. So, you have to replicate the @api variable in another temp variable and implement your logic on that temp variable. Assign back the temp variable to the @api variable. Have a look at the below code for reference:

export default class MakeYourTeamChild extends LightningElement {
    @api unselectedPlayerList=[];
    **let tempUnsltPlList = [];**
    SelectPlayer(event)
    { 
        for(let index = 0 ; index < this.tempUnsltPlList.length; index++)
        {
            if(this.tempUnsltPlList[index].Name == event.target.title)
            {
                this.selectedPlayer = this.tempUnsltPlList[index].Name;
                this.tempUnsltPlList.splice(index,1);
                console.log('After Splice',this.tempUnsltPlList.length);
            }
        }
       **this.unselectedPlayerList = [...tempUnsltPlList];**
    }
}

I hope it will help you. If yes, mark it as the best answer. Feel free to reach out to me!

0
Bartheleway On

You have a parent / child communication issue as I understand. As always, the best know approach is "props down, event up". This will ensure you easily understand how & when a variable change within a component and component behavior will not be changed by it's inner child component.

In your case, unselectedPlayerList is a prop on the child component filled by its parent component. This means parent component is owner of the data and controlling this prop value. If child component wants to modify the value of this value, it needs to ask the parent to do so, this is done by emitting an event telling the parent component what to do.

export default class ParentComponent extends LightningElement {
  unselectedPlayerList = []

  handleSelectPlayer (event) {
    const playerName = event.detail.playerName
    const playerIndex = this.unselectedPlayerList.findIndex(player => player.Name === playerName)

    const shallowPlayerList = [ ...this.unselectedPlayerList ]

    shallowPlayerList.splice(playerIndex, 1)

    this.unselectedPlayerList = shallowPlayerList
  }
}
<template>
  <c-child-component
    unselected-player-list={unselectedPlayerList}
    onselectplayer={handlePlayerSelect}
  ></c-child-component>
</template>

export default class ChildComponent extends LightningElement {
  @api unselectedPlayerList = []

  handleSelectPlayer (event) {
    this.dispatchEvent(
      new CustomEvent('selectplayer', {
        detail: {
          playerName: event.target.title,
        }
      })
    )
  }
}

There also is another way to write the parent component if you'd like using the @track decorator. In LWC all component attributes are reactive with a small exception around objects (array, js object). Changing an inner property of an object will not rerender the view unless decorating that object.

You can use this js for the parent component for the exact same result.

export default class ParentComponent extends LightningElement {
  @track unselectedPlayerList = []

  handleSelectPlayer (event) {
    const playerName = event.detail.playerName
    const playerIndex = this.unselectedPlayerList.findIndex(player => player.Name === playerName)

    this.unselectedPlayerList.splice(playerIndex, 1)
  }
}

I would not recommend using the @track version as it's heavier for performance and in any case you do stuff in a loop, every modification to the array will/might trigger view update. In first version you are assured that view will update only once which is also giving you more control on how the view (or dependent properties like getters) behave.

I hope this will help you and I invite you to read these articles: