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 Jan 25 '20 at 21:00
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 Kulkarni Jan 26 '20 at 4:54
  • @MohitKulkarni If names is undefined/null, then names.data would result in an error (similar to the original situation). – sfdcfox Jan 26 '20 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 Jan 26 '20 at 7:33
  • @PhilW That's correct. It was missing originally, I added that in as an edit. – sfdcfox Jan 26 '20 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 Jan 26 '20 at 20:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.