5

amo Bootstrap-Select e sto attualmente utilizzando attraverso l'aiuto di una direttiva fatta da un altro utente joaoneto/angular-bootstrap-select e funziona come previsto, tranne quando si tenta di riempire il mio elemento <select> con una $http o in il mio caso è un wrapper dataService. Mi sembra di avere qualche problema di temporizzazione, i dati arrivano dopo che lo selectpicker è stato visualizzato/aggiornato e quindi ho finito per avere un elenco di Bootstrap-Select vuoto .. anche se con Firebug, vedo l'elenco dei valori nell'originale <select>. Se poi vado in console e eseguo manualmente un $('.selectpicker').selectpicker('refresh'), allora funziona.
Ho funzionato temporaneamente eseguendo una patch e aggiungendo un .selectpicker('refresh') all'interno di un $timeout ma come sapete non è ideale dato che stiamo usando jQuery direttamente in un ngController ... ouch!

Quindi credo che la direttiva probabilmente manchi di un osservatore o almeno qualcosa per far sì che ngModel venga modificato o aggiornato.

Html codice di esempio:angolare Bootstrap-Select problema di temporizzazione per aggiornare

<div class="col-sm-5"> 
    <select name="language" class="form-control show-tick" 
     ng-model="vm.profile.language" 
     selectpicker data-live-search="true" 
     ng-options="language.value as language.name for language in vm.languages"> 
    </select> 
    <!-- also tried with an ng-repeat, which has the same effect --> 
</div> 

poi dentro il mio controller angolare:

// get list of languages from DB 
dataService 
    .getLanguages() 
    .then(function(data) { 
     vm.languages = data; 

     // need a timeout patch to properly refresh the Bootstrap-Select selectpicker 
     // not so good to use this inside an ngController but it's the only working way I have found 
     $timeout(function() { 
      $('.selectpicker, select[selectpicker]').selectpicker('refresh'); 
     }, 1); 
    }); 

e qui è la direttiva da parte (joaoneto) su GitHub for Angular-Bootstrap-Select

function selectpickerDirective($parse, $timeout) { 
    return { 
    restrict: 'A', 
    priority: 1000, 
    link: function (scope, element, attrs) { 
     function refresh(newVal) { 
     scope.$applyAsync(function() { 
      if (attrs.ngOptions && /track by/.test(attrs.ngOptions)) element.val(newVal); 
      element.selectpicker('refresh'); 
     }); 
     } 

     attrs.$observe('spTheme', function (val) { 
     $timeout(function() { 
      element.data('selectpicker').$button.removeClass(function (i, c) { 
      return (c.match(/(^|\s)?btn-\S+/g) || []).join(' '); 
      }); 
      element.selectpicker('setStyle', val); 
     }); 
     }); 

     $timeout(function() { 
     element.selectpicker($parse(attrs.selectpicker)()); 
     element.selectpicker('refresh'); 
     }); 

     if (attrs.ngModel) { 
     scope.$watch(attrs.ngModel, refresh, true); 
     } 

     if (attrs.ngDisabled) { 
     scope.$watch(attrs.ngDisabled, refresh, true); 
     } 

     scope.$on('$destroy', function() { 
     $timeout(function() { 
      element.selectpicker('destroy'); 
     }); 
     }); 
    } 
    }; 
} 
+0

Versione AngularJS? – tasseKATT

+0

La versione di AngularJS è 1.3.11 – ghiscoding

risposta

9

Un problema con l'angolare -bootstrap-select direttiva, è che guarda solo ngModel, e non l'oggetto che sta effettivamente popolando le opzioni nel sele ct. Ad esempio, se vm.profile.language è impostato su '' per impostazione predefinita e vm.languages dispone di un'opzione '', la selezione non verrà aggiornata con le nuove opzioni, poiché ngModel rimane invariato. Ho aggiunto un attributo selectModel alla selezione e modificato leggermente il codice di selezione angolare-bootstrap.

<div class="col-sm-5"> 
    <select name="language" class="form-control show-tick" 
     ng-model="vm.profile.language" 
     select-model="vm.languages" 
     selectpicker data-live-search="true" 
     ng-options="language.value as language.name for language in vm.languages"> 
    </select> 
</div> 

Poi, nel codice angolare bootstrap-select, ho aggiunto

if (attrs.selectModel) { 
    scope.$watch(attrs.selectModel, refresh, true); 
} 

Ora, quando vm.languages è aggiornato, il prescelto sarà aggiornata anche. Un metodo migliore sarebbe probabilmente quello di rilevare semplicemente quale oggetto dovrebbe essere visto utilizzando ngOptions, ma l'utilizzo di questo metodo consente l'uso di ngRepeat all'interno di una selezione.

Edit:

Un'alternativa all'utilizzo selectModel rileva automaticamente l'oggetto da guardare da ngOptions.

if (attrs.ngOptions &&/in /.test(attrs.ngOptions)) { 
    scope.$watch(attrs.ngOptions.split(' in ')[1], refresh, true); 
} 

Edit 2:

Invece di utilizzare la funzione refresh, si sarebbe probabilmente meglio solo chiamare element.selectpicker('refresh'); ancora una volta, come si desidera aggiornare solo in realtà il valore del SELECT quando ngModel modifiche. Mi sono imbattuto in uno scenario in cui veniva aggiornato l'elenco di opzioni e il valore della selezione è cambiato, ma il modello non è cambiato e, di conseguenza, non corrisponde al selectpicker. Questo risolto per me:

if (attrs.ngOptions &&/in /.test(attrs.ngOptions)) { 
    scope.$watch(attrs.ngOptions.split(' in ')[1], function() { 
     scope.$applyAsync(function() { 
      element.selectpicker('refresh'); 
     }); 
    }, true); 
} 
+0

Concetto molto interessante, questo mi ha dato l'idea di utilizzare l'aggiornamento senza nemmeno la necessità di un attributo. Dato che abbiamo già il nome dell'oggetto direttamente all'interno di 'ngOptions', puoi farlo modificando solo la direttiva stessa e aggiungendo qualcosa come la seguente:' if (attrs.ngOptions &&/in /.test(attrs.ngOptions) {scope. $ watch (attrs.ngOptions.split ('in') [1], refresh, true);} '... modifica la tua risposta con questa opzione, o meglio, e accetterò la tua risposta ... grazie mille :) – ghiscoding

+0

Questa è un'ottima soluzione per me, grazie! – WiseGuy

0

Mi dispiace, ma dove nel angolare bootstrap-selezionare il codice hai aggiungere che il codice? Sto chiedendo perché dice che gli attrs non sono definiti.