2

I recently moved from Aura to LWC and not able to understand whats going wrong here. Below sample code

lwcpage.html

      <template for:each={names} for:item='name'>
          <div key={name.Id} class="customcss" >
             {name.Name}
          </div>
      </template>

lwcpage.js

  import { LightningElement, wire, track } from 'lwc';
  import listViewsRecords from '@salesforce/apex/UserManage.listViewsRecords';

  export default class UsermanageSearchList extends LightningElement 

       items = []; 
       names = [];

      @wire(listViewsRecords, { param : 'param1' }) 
      list({ error, data }) {
      console.log('data-->'+data);
      if(data){

       this.names = data.userLists;
       this.items = data.items;

      }else if (error) {
         this.error = error;
        this.items = undefined;
      }

   }


 }

The 'list' wired method is getting called twice and the first time returns undefined data and the second time data correctly retrieved.

data -> undefined

data -> < data >

Because its getting undefined, the component is giving an after renderer error

'afterRender threw an error in 'c:component' [Cannot read property 'Id' of undefined]'.

What I don't understand is why the wired method always gets called twice and getting undefined ? and if this is expected what needs to be done here?

1
  • 2
    Hi. It would help to know more about the type of data you are expecting from Apex and the Parameters you will be sending. Depending on your requirements you might also want to consider using track decorators. Example: "@track items;" and "@track names;"
    – Jordan
    Commented Jan 25, 2020 at 21:00

1 Answer 1

5

You just need to prevent the template from rendering until the data is ready:

  <template if:true={names} for:each={names} for:item='name'>
      <div key={name.Id} class="customcss" >
         {name.Name}
      </div>
  </template>

Further, the reason why it's called twice is because it will be called once with data from the cache (which doesn't exist yet), so the data properties will be undefined, but no error will exist yet. Later, the server responds with the data, and your wire method is called again, and the data is then available.

The other way you could handle this is to use the or operator so that the list will at least remain empty, not undefined:

  if(data){

   this.names = data.userLists || [];
   this.items = data.items || [];

  }else if (error) {
     this.error = error;
    this.items = [];
    this.names = [];
  }

Although this could look incorrect depending on how your template is structured. I'd recommend using if:true and if:false to control which templates and/or elements are being displayed.


Edit: I neglected to mention that the variables do need to be @tracked, or the component won't update correctly:

@track items = [];
@track names = [];
5
  • My answer should solve his issue right?
    – Mohit K
    Commented Jan 26, 2020 at 4:54
  • @MohitKulkarni If names is undefined/null, then names.data would result in an error (similar to the original situation).
    – sfdcfox
    Commented Jan 26, 2020 at 7:12
  • @sfdcfox, the names property should also conceptually be defined as tracked to ensure the template is re-rendered when the values change. Right??
    – Phil W
    Commented Jan 26, 2020 at 7:33
  • @PhilW That's correct. It was missing originally, I added that in as an edit.
    – sfdcfox
    Commented Jan 26, 2020 at 7:39
  • @sfdcfox For some reason the first way didn't work. The second one did with a slight modification, added another else if condition (no error condition).
    – Brav
    Commented Jan 26, 2020 at 20:30

You must log in to answer this question.

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