Search code examples
aureliabootstrap-select

How to refresh bootstrap-select's options after load data from ajax api


I have create aurelia custom attribute code as below

@customAttribute('bt-select')
@inject(Element)
export class BootstrapSelect {
  @bindable val;
  @bindable list;

  constructor(element) {
    this.element = element;

  }

  attached() {
    $(this.element).selectpicker();
  }

  valChanged(newValue, oldValue) {
      $(this.element).selectpicker("val",_.isObject(newValue)?newValue.id:newValue);
  }

  listChanged(newValue, oldValue) {
    setTimeout(()=>{
       $(this.element).selectpicker("refresh");
    },300)
  }

  detached(){
    this.val = null;
    this.list = null;
    $(this.element).selectpicker("destroy");
  }

}

and use it as below

<select value.bind="form.category" data-width="100"
                                bt-select="val.bind:form.category;list.bind:categorys;">
                          <option value="">select:category</option>
                          <option repeat.for="category of categorys"
                                  value="${category.id}">
                            ${category.name}
                          </option>
                        </select>

the select's options tag repeat from class prop categorys,this.categorys loda data from ajax api,it's async step to render select option tag and I have to add setTimeout func in listChanged method to wait aurelia render the select's options tag complete and then force refresh bootstrap-select component

I feel it's not good, but I haven't better way to resolve it, I konw many jQuery plugin should use completed dom element and render them,but in aurelia framework attached() method ,some data load from async api is there have some post-processing methods or event to invoke after async data had bind to dom


Solution

  • You can queue a micro-task, ensuring that your function will run after updating the DOM. For example:

    //...
    import { TaskQueue } from 'aurelia-task-queue';
    
    @inject(Element, TaskQueue)
    export class BootstrapSelect {
      //...
      constructor(element, taskQueue) {
        this.element = element;
        this.taskQueue = taskQueue;
      }
    
      listChanged(newValue, oldValue) {
        // at this point, a micro-task for updating the dom is already queued.
        // now, you should queue a new task that will run after the previous one is completed. 
        this.taskQueue.queueMicroTask(() => {
          $(this.element).selectpicker("refresh");
        });
      }
    }
    

    Similar question: @bindable changeHandler fires before bindings are done updating

    Hope this helps!