2016-06-23 11 views
1

Wir verwenden die Bibliothek Chosen mit RequireJs und KnockOut. Alles funktionierte gut, bis wir von RequireJS zu commonjs wechselten und jetzt webpack bündeln. Das Problem ist, dass die knockout observable nicht aktualisiert wird, wenn wir den Wert in chosen Dropdown ändern.Knockout-Observable wird nicht aktualisiert, wenn der Dropdown-Wert für die Auswahl geändert wird

Hier ist der JavaScript-Code, der mit RequireJs arbeitete.

define(['knockout', 'text!./employee-setup.html', 'utils', 'panel-section', 'toastr', 'jquery', 'knockout-postbox', 'knockout-projections', 'chosen', 'jsteps'], function (ko, template, utils, PanelSection, toastr, $, _, _, _, jsteps) { 
function EmployeeSetup(params) { 
    var self = this; 
    this.agentTypes = ko.observableArray(); 
    this.agentType = ko.observable(); 


    this.loadAgentTypes = function() { 
     $.ajax({ 
      url: '/Employee/GetAgentTypes', 
      method: 'POST', 
      dataType: 'json', 
      success: function (result) { 
       if (utils.handleAjaxResult(result) && result.Data) { 
        self.agentTypes([]); 

        var agentType = [{ ID: "", Name: "" }]; 

        $.each(result.Data, function (i, item) { 
         agentType.push({ID: item.ID, Name: item.Name}); 
        }); 
        self.agentTypes(agentType); 
        $('#agentType').chosen({ allow_single_deselect: true, width: '310px' }); 
        $('#agentType').trigger("chosen:updated"); 
       } else { 
       } 

      }, 
      error: function() { 
       toastr.error('Could not load agent types'); 
      } 
     }); 
    }; 
    self.loadAgentTypes(); 
    }; 
return { template: template, viewModel: EmployeeSetup }; 
}); 

Der HTML-Code für diese Komponente:

<div class="input-container" data-bind=""> 
    <select data-bind="value: agentType, options: agentTypes, optionsText: 'Name'" data-placeholder="Select Agent Type..." id="agentType" class="chosen-select sp-uin-dropdown" tabindex="2"> </select> 
</div> 

Hier ist der Code commonjs

var ko = require('knockout'), 
    utils = require('utils'), 
    PanelSection = require('panel-section'), 
    toastr = require('toastr'), 
    $ = require('jquery'); 
require('knockout-postbox'); 

function ViewModel(params) { 
    var self = this; 
    this.agentTypes = ko.observableArray(); 
    this.agentType = ko.observable(); 

    this.loadAgentTypes = function() { 
    $.ajax({ 
     url: '/Employee/GetAgentTypes', 
     method: 'POST', 
     dataType: 'json', 
     success: function (result) { 
     if (utils.handleAjaxResult(result) && result.Data) { 
       self.agentTypes([]); 

       var agentType = [{ ID: "", Name: "" }]; 

       $.each(result.Data, function (i, item) { 
        agentType.push({ID: item.ID, Name: item.Name}); 
       }); 
       self.agentTypes(agentType); 
       $('#agentType').chosen({ allow_single_deselect: true, width: '310px' }); 
       $('#agentType').trigger("chosen:updated"); 
      } else { 
      } 
     }, 
     error: function() { 
      toastr.error('Could not load agent types'); 
     } 
    }); 
    }; 
    self.loadAgentTypes(); 
} 
module.exports = { viewModel: ViewModel, template: require('./template.html')  }; 

Und es ist mit der gleichen html Datei wie oben. In der webpack.config.js definieren wir den Pfad zu jquery und chosen.

Es lädt die chosen dropdown korrekt. Wenn jedoch subscribe beobachtbar ist, wird der Wert nicht aktualisiert, wenn sich das Dropdown ändert. Ich sehe den Wert nur einmal beim ersten Laden von der Konsole.

self.agentType.subscribe(function (value) { 
    console.log('value', value); 
}, this) 

Nur wenige Beiträge hier in SO vorgeschlagen, bindingHandlers zu verwenden. Ich habe diesen Arbeitscode von JSFiddle in meiner Anwendung ausprobiert, aber ich bekomme nur den Wert von der anfänglichen Belastung.

Irgendwelche Vorschläge zur Lösung dieses Problems oder was verursacht dies?

Antwort

0

Das Problem wurde von webpack verursacht. Um das Problem zu beheben, schrieb mein Kollege eine benutzerdefinierte bindingHandler.

HTML Code:

<div class="input-container"> 
<select data-bind=" 
       value: agentType, 
       options: agentTypes, 
       optionsText: 'Name', 
       dropdown: { 
        width: '310px', 
        allow_single_deselect: true 
       } " 
       data-placeholder="Select Agent Type..." id="agentType"> 
</select> 

Individuelle bindingHandler:

// a dropdown handler, which currently utilizes the Chosen library 

ko.bindingHandlers.dropdown = { 

    init: function(element, valueAccessor, allBindings, viewModel, bindingContext){ 

     // get chosen element 

     var $element = $(element); 

     // get options (if any) to pass to chosen when creating 

     var options = ko.unwrap(valueAccessor()); 



     // NOTE: when using Chosen w/ webpack, the knockout bindings no longer 

     // fired. This event handler is to remedy that. It watches the change 

     // event for the underlying <select> (which chosen updates), and 

     // updates the corresponding observables mapped to value and selectedOptions. 

     // Only one should be bound, value for single select, selectedOptions for multi-select 

     // binding direction: Knockout <- Chosen 

     $element.on('change', function(e, item) { 

      var valueProp = allBindings.has('value') && allBindings.get('value'); 

      var selectedOptionsProp = allBindings.has('selectedOptions') && allBindings.get('selectedOptions'); 

      if (item) { 

       if (allBindings.has('options')) { 

        var allOptions = ko.unwrap(allBindings.get('options')); 

        if (valueProp) { 

         // single select 

         if (ko.isObservable(valueProp)) { 

          if (!item.isMultiple) { 

           if (item.selecting) { 

            valueProp(allOptions[item.index]); 

           } else { 

            valueProp(null); 

           } 

          } 

         } 

        } 

        if (selectedOptionsProp) { 

         // multi select 

         if (ko.isObservable(selectedOptionsProp)) { 

          if (item.isMultiple) { 

           // handle multi select 

           if (item.selecting) { 

            // select 

            selectedOptionsProp.push(allOptions[item.index]); 

           } else { 

            // deselect 

            selectedOptionsProp.remove(allOptions[item.index]); 

           } 

          } 

         } 

        } 

       } 

      } else { 

       // this is triggered w/o args when the control is reset. This happens when deselecting during single-select 

       if (valueProp) { 

        // single select 

        if (item === undefined && ko.isObservable(valueProp)) { 

         valueProp(null); 

        } 

       } 

      } 

     }); 
     // handle updating the chosen component's UI when the underlying 

     // options, selectedOptions or value changes 

     // binding direction: Knockout -> Chosen 

     ['options', 'selectedOptions', 'value'].forEach(function(propName){ 

      if (allBindings.has(propName)){ 

       var prop = allBindings.get(propName); 

       if (ko.isObservable(prop)){ 

        //console.log('subscribing to:', propName, ' for:', $element); 

        prop.subscribe(function(value){ 

         if (value != null) { 

          //console.log('calling chosen:updated'); 

          var options = ko.unwrap(allBindings.get('options')); 

          // console.log('got options:', options); 

          if (options) { 

           if (options.indexOf(value) > -1) { 

            // item is in options 

            //  console.log('value is in options:', value); 

           } else { 

            // item is not in options, try to match ID 

            options.some(function (item) { 

             if (item.ID == value) { 

              // update the obs. to the entire item, not the ID 

              prop(item); 

             } 

            }); 

           } 

          } 

         } 

         $element.trigger('chosen:updated'); 

        }); 

       } 

      } 

     });  

     // add chosen css class (not sure this is needed) 

     $element.addClass('chosen-select'); 



     // create chosen element, passing in options if any were specified 

     if (typeof options === 'object') { 

      $element.chosen(options); 

     } else { 

      $element.chosen(); 

     } 

     $element.trigger('chosen:updated'); 

    } 

}; 
Verwandte Themen