Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boostrap-multiselect plugin in Aurelia

I am trying to get bootstrap-multiselect to work with Aurelia. have got it working more or less but not sure it is the best solution or if I might run into trouble.

Bootstrap-multiselect is a jquery plugin that turns a normal select (multi) into a drop down with checkboxes (http://davidstutz.github.io/bootstrap-multiselect/)

My first problem is to get it working with dynamically created options. I solved that by using the plugins "rebuild" feature when my array of options (created as a bindable property) changes. However the options of the original select hhas then not yet been created so I use setTimeout to delay rebuilding so Aurelia have rebuilt the select. Feels like a "dirty" solution and I know to little about the Aurelia lifecyle to be sure it will always work.

Second problem is that value for component will not be updated, however the change method will fire. I solved this by firing off a change event (found an example for some other plugin that do the same). Works fine, value wiill be updated but the change method will fire twice. Not a big problem but might be a problem if a change does some time consuming work (like getting data from a database etc).

Any suggestions to improve code ?

       <template>
          <select value.bind="value" multiple="multiple">
              <option repeat.for="option of options"Value.bind="option.value">${option.label}</option>
           </select>
       </template>

import {customElement, bindable, inject} from 'aurelia-framework';
import 'jquery';
import 'bootstrap';
import 'davidstutz/bootstrap-multiselect';

@inject(Element)
export class MultiSelect {

    @bindable value: any;
    @bindable options: {};
    @bindable config: {};

    constructor(private element) {
        this.element = element;
    }

    optionsChanged(newVal: any, oldVal: any) {
        setTimeout(this.rebuild, 0);
    }

    attached() {
        var selElement = $(this.element).find('select');
        selElement.multiselect(
            {
                includeSelectAllOption: true,
                selectAllText: "(All)",
                selectAllNumber: false,
                numberDisplayed: 1,
                buttonWidth: "100%"

            })
           .on('change', (event) => {
                if (event.originalEvent) { return; }
                var notice = new Event('change', { bubbles: true });
                selElement[0].dispatchEvent(notice);
            });
    }

    detached()  {
        $(this.element).find('select').multiselect('destroy');
    }
    
    rebuild = () => {
        $(this.element).find('select').multiselect('rebuild');
    }
}
like image 725
Magnus Avatar asked Nov 09 '22 03:11

Magnus


1 Answers

Your first problem could be solved by pushing the $(this.element).find('select').multiselect('rebuild'); onto the microTaskQueue, inside the optionsChanged() handler. In this way, Aurelia will fire this event after rendering the new options.

Your second problem is not actually a problem. What is happening is that @bindable properties are one-way by default. You should declare the value property as two-way. Then, you should update the value inside the multiselect.change event.

Finally, your custom element should be something like this:

import {inject, bindable, bindingMode, TaskQueue} from 'aurelia-framework';

@inject(TaskQueue)
export class MultiselectCustomElement {

  @bindable options;
  @bindable({ defaultBindingMode: bindingMode.twoWay }) value = [];

  constructor(taskQueue) {
   this.taskQueue = taskQueue;
  }

  attached() {
    $(this.select).multiselect({ 
      onChange: (option, checked) => {
        if (checked) {
          this.value.push(option[0].value);
        } else {
          let index = this.value.indexOf(option[0].value);
          this.value.splice(index, 1);
        }
      }
    });
  }

  optionsChanged(newValue, oldValue) {
    if (oldValue) { 
      this.taskQueue.queueTask(() => { 
        this.value = [];
        $(this.select).multiselect('rebuild');
      });
    }
  }
}

Running example: https://gist.run/?id=60d7435dc1aa66809e4dce68329f4dab

Hope this helps!

like image 148
Fabio Luz Avatar answered Dec 21 '22 15:12

Fabio Luz