1

I have 2 picklist(Combo-box). On change of value in the 1st combobox - depending on the value returned from the controller - i need to render or hide the 2nd combobox. I'm using refreshapex to get the latest values from controller. After refreshapex i'm trying to get the list length. As JS is asynchronous it is not waiting till the list is populated with the fresh values. Need help in implementing Call-back function so that i get the latest count of the list which will help in deciding whether i should render or not the 2nd combobox.

@wire(fetchL2ProductValues,{productId: '$l1SavedValue',userType: '$userType'})
l2ProductList;

get l2ProductOptions(){
  return this.l2ProductList.data;
}
onSelectProductL1(event){
  this.l1SavedValue = event.target.value;
  refreshApex(this.l2ProductList);

  /*following below lines of code need to be executed only after l2ProductList values has refreshed. As now since call-back is not implemented(asynchronus), it is getting executed immediately after refreshAPex & it is holding the previous value of this.l2ProductList rather than the latest value fetched from apex */
    var key,count =0;
    for(key in this.l2ProductList){
        if(this.l2ProductList.hasOwnProperty(key)){
            count++;
        }
    }
    console.log('count is :'+count);
    if(count > 0){
        this.showProductL2 = true;
    }else{
        console.log('In else condition');
        this.showProductL2 = false;
    }
1

I think that you can wire a function rather than a var as the result of fetchL2PropertyValues.

This means it's basically a callback where you can set values and run your other logic.

So you'd write it like:

@wire(fetchL2ProductValues,{productId: '$l1SavedValue',userType: '$userType'})
l2ProductValuesCallback({ error, data }) {
    if (data) {
       this.l2ProductList = data;
        //do all the logic you wanted to run in the callback... 
       var key,count =0;
       for(key in this.l2ProductList){
         if(this.l2ProductList.hasOwnProperty(key)){
           count++;
         }
       }
       if(count > 0){
           this.showProductL2 = true;
       }else{
           this.showProductL2 = false;
       }

    } else if (error) {
        //handle your error
    }
}

Also... that logic seems like it could be simplified - try investigating array.some() which iterates until a condition evaluates to true. Depends on the data structure of your list that you are returning.

  • Since i'm using a combo-box it needs a getter. If i go by the way as you suggested..how do i populate values in the getter ?? i.e get l2ProductOptions(){ return this.l2ProductList.data; } – Sunil Jul 8 at 8:45
  • forgot to add this line: this.l2ProductList = data; which sets the var - so then your getter will work. – Caspar Harmer Jul 8 at 8:58
  • I added the line as per the above comment. But i'm getting this error in console.log lds.js:2 Uncaught (in promise) Error: Refresh failed because resolved configuration is not available. I followed this blog post :- jdspaceit.wordpress.com/2019/02/27/… .. but still error dint resolve. – Sunil Jul 8 at 10:15
  • Thanks Caspar for helping me on this :) – Sunil Jul 8 at 17:14
0

I had to introduce a new variable this.l2Result, to prevent the error -"Error: Refresh failed because resolved configuration is not available".The final working code is :-

@wire(fetchL2ProductValues,{productId: '$l1SavedValue',userType: '$userType'})
l2ProductValuesCallback(result) {
    var key,count =0;
    this.l2Result = result;
    if (result.data) {
        this.l2ProductList = result.data;
        for(key in this.l2ProductList){
            if(this.l2ProductList.hasOwnProperty(key)){
            count++;
            }
        }
       if(count > 0){
          this.showProductL2 = true;
       }else{
         this.showProductL2 = false;
      }

    } else if (error) {
    //handle your error
   }
  }

   onSelectProductL1(event){
       this.l1SavedValue = event.target.value;
       refreshApex(this.l2Result);
}
0

There are a handful of issues with your code sample that make answering this question difficult. I've copied your code below with several questions.

@wire(fetchL2ProductValues,{productId: '$l1SavedValue',userType: '$userType'})
l2ProductList;

// This is unnecessary. Use {l2ProductList.data} in the template directly.
// get l2ProductOptions() {
//   return this.l2ProductList.data;
// }

onSelectProductL1(event){
  // If this.l1SavedValue changes values then the above @wire will re-invoke the Apex method. There's no need to call refreshApex() unless the value is unchanged, in which case you need more complex logic to handle this either-or scenario.
  this.l1SavedValue = event.target.value;
  // refreshApex(this.l2ProductList);

  // This logic doesn't make sense: 
  // a. It's iterating over properties of this.l2ProductList; there will always be 2: data and error. 
  // b. If you want to check the number of keys use Object.keys(this.l2ProductList.data).length
    var key,count =0;
    for(key in this.l2ProductList){
        if(this.l2ProductList.hasOwnProperty(key)){
            count++;
        }
    }
    console.log('count is :'+count);
    if(count > 0){
        this.showProductL2 = true;
    }else{
        console.log('In else condition');
        this.showProductL2 = false;
    }

FWIW refreshApex() returns a promise that resolves/rejects after the Apex method has been reinvoked and a new value provisioned (if applicable). You can chain off that promise to perform logic specific to the refreshed value even if it doesn't change.

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.