2016-06-23 13 views
1

およびKnockOutChosenライブラリを使用しています。 RequireJSからcommonjsに変更し、現在はwebpackを使用してバンドルするまで、すべてうまくいきました。問題は、chosenの値を変更したときにknockout observableが更新されないという点です。選択されたドロップダウン値が変更されたときにノックアウト観測値が更新されない

RequireJsを使用して動作していたjavascriptコードは次のとおりです。

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 }; 
}); 

そのコンポーネントのHTML:

<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> 

はここ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')  }; 

を使用してコードだし、上記と同じhtmlファイルを使用しています。

webpack.config.jsには、jquerychosenのパスを定義します。

chosen dropdownが正しく読み込まれます。しかし、subscribeを観測可能にすると、ドロップダウンが変更されたときに値が更新されません。初期ロード時には、コンソールからの値しか表示されません。ここSOで

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

いくつかの記事はbindingHandlersを使用することを示唆しました。私は私のアプリケーションでJSFiddleからこの作業コードを試しましたが、私は最初の負荷から値を取得します。

この問題を解決する方法や原因を教えてください。

答えて

0

この問題の原因はwebpackです。問題を解決するために、私の同僚はカスタムbindingHandlerを書きました。

HTMLコード:

<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> 

カスタム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'); 

    } 

}; 
関連する問題