我们一直在使用Chosen库与RequireJs和KnockOut。一切都很好,直到我们从RequireJS切换到commonjs,现在使用webpack进行捆绑。问题是,当我们更改knockout observable下拉列表中的值时,chosen不会被更新。
下面是使用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中,我们定义了jquery和chosen的路径。
它正确地加载chosen dropdown。然而,当我的subscribe被观察到时,当下拉列表发生变化时,它不会更新值。在初始加载时,我只从控制台看到一次值。
self.agentType.subscribe(function (value) {
console.log('value', value);
}, this)这里很少有这样建议使用bindingHandlers的帖子。我已经在我的应用程序中尝试过来自JSFiddle的这个工作代码,但是我只从初始加载中得到了这个值。
对于如何解决这个问题,或者是什么原因,有什么建议吗?
发布于 2016-07-01 20:29:36
这个问题是由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');
}
};https://stackoverflow.com/questions/38000962
复制相似问题