Two way binding not working on bootstrap-select wi

2020-04-15 15:35发布

问题:

I have managed to create a custom element to use the boostrap-select element. However, I can pass/bind values to it from the main view (parent) but I am unable to get the selection out from the element when I use two-way binding.

My custom element is:

import {inject, customElement, bindable} from 'aurelia-framework';
import * as selectpicker from 'bootstrap-select'

@customElement('select-picker')
export class BootStrapSelectPicker {
  @bindable selectableValues = null;
  @bindable newValue = null;
  @bindable selectedValue = 10;

 constructor(){
 }


 attached(){
  $('.selectpicker').selectpicker({
       style: 'btn-info',
       size: 4
  });

 $('.selectpicker').on('change', function(){
    var selected = $(this).find("option:selected").val();

     this.selectedValue = selected;
     console.log(this.selectedValue);
  });

   $('.selectpicker').val(this.selectedValue); <-- the selection here is correct
   $('.selectpicker').selectpicker('refresh');

 }
}

The corresponding view is:

<template>
  <select class="selectpicker">
    <option repeat.for="p of selectableValues">${p}</option>
  </select>
</template>

My containing view that uses the custom element is:

<template>
   <require from="./select-picker"></require>

   <ul class="list-group">
     <li class="list-group-item" repeat.for="p of messageProperties">
     <div if.bind="p.propertyType == 'string'">
       <div class="form-group">
         <label for="ln">Name: ${p.propertyName}</label>
         <input type="text" value.bind="p.propertyValue" class="form-control" id="ln" >
      </div>
    </div>
    <div if.bind="p.propertyType == 'integer'">
        <div class="form-group">
         <label for="ln">Name: ${p.propertyName}</label>
         <input type="text" value.bind="p.selectedValue" class="form-control" id="ln" >
        <select-picker selectable-values.bind="p.selectableValues"
             selected-value.two-way="p.selectedValue"></select-picker>
    </div>
    </div>
  </li>


 </ul>
</template>

I expected p.selectedValue to change once a selection is made with the select control as shown here with the two-way command:

 selected-value.two-way="p.selectedValue"

However, p.selectedValue is not changing.

Any ideas why this is not working?

回答1:

Turns out to be a simple scope issue:

attached(){
  $('.selectpicker').selectpicker({
       style: 'btn-info',
       size: 4
  });

 $('.selectpicker').on('change', function(){
    var selected = $(this).find("option:selected").val();

     this.selectedValue = selected; // <-- This here doesn't refer to the VM any more
     // if you look at the line above you are wrapping $(this) with jq, this works 
     // because 'this' is now in the scope of the calling element but 
     // doesn't refer to the aurelia viewmodel
     console.log(this.selectedValue);
  });

   $('.selectpicker').val(this.selectedValue); 
   $('.selectpicker').selectpicker('refresh');

 }

Simple fix is:

attached(){

  var self = this; // <--- Create a ref to the VM

$('.selectpicker').selectpicker({
       style: 'btn-info',
       size: 4
  });

 $('.selectpicker').on('change', function(){
    var selected = $(this).find("option:selected").val();
     // Change this to self
     self.selectedValue = selected; // <--- Correct object gets the value now - binding works
     console.log(this.selectedValue);
  });

   $('.selectpicker').val(this.selectedValue); 
   $('.selectpicker').selectpicker('refresh');

 }

I'm not sure how this will actually be handled in ES6/7 - I'm sure I read somewhere about how this will change, but since you are transpiling to ES5 it's definitely something to watch out for



回答2:

The following code works for me, in case anyone has the same issue:

import {inject, customElement, bindable} from 'aurelia-framework';
import 'bootstrap-select'

@customElement('select-picker')
@inject(Element)
export class BootStrapSelectPicker {
    @bindable name: string;
    @bindable selectableValues;
    @bindable selectedValue;

    constructor(private element) {
    }

    attached() {
        var self = this;
        var $: any = jQuery;
        var $elm = $(self.element).find('select');
        if ($elm.length > 0) {
            $elm.selectpicker();
            $elm.on('change', function () {
                self.selectedValue = $(this).find("option:selected").val();
            });
            this.refreshPicker($elm);
        }
    }

    selectedValueChanged(newValue, oldValue) {
        var $: any = jQuery;        
        var $elm = $(this.element).find('select');
        this.refreshPicker($elm);
    }

    private refreshPicker = ($elm) => {        
        $elm.val(this.selectedValue);
        $elm.selectpicker('refresh');        
    }
}


标签: aurelia