Knockout.js jQuery 移动版 1.4 select 的 3.3.0 选项绑定
Knockout.js 3.3.0 options binding for jQuery mobile 1.4 select
我正在使用 knockout.js 3.3.0 和 jQuery 移动版 1.4。
knockout.js 与 jQuery 移动设备一起使用的问题在于,由于 html 元素的 JQM 重构,以编程方式对底层视图模型的更改并不总是反映到图形用户界面,或者小部件。因此,例如,JQM select 菜单从用户界面同步到视图模型,但不是以其他方式。
我正在尝试将 3.3.0 KO 'options' 绑定与当前 JQM 实际版本的自定义绑定结合在一起。
对于 'refresh' 问题已经在 SO 上针对 2.x 版本的 KO 提出了两种可能的解决方案:jqmSelect 和 jqmValue,作为自定义绑定。
我尝试将此建议用于最近的 KO+JQM 组合,将在 SO 找到的关于该主题的所有 answers/comments 放在一起。
这是我用来测试的js:
$(document).ready(function () {
var jsonResultData = [{
"id": 6,
"name": "First item",
"pattern": "Cheetah"
}, {
"id": 2,
"name": "Second item",
"pattern": "Viper"
}, {
"id": 1,
"name": "Third item",
"pattern": "Scorpion"
}];
ko.applyBindings(new AdminViewModel(jsonResultData));
});
function Match(data) {
this.id = ko.observable(data.id);
this.pattern = ko.observable(data.pattern);
this.name = ko.observable(data.name);
}
function AdminViewModel(allData) {
var self = this;
self.matches = ko.observableArray([]);
self.matchesFromDb = $.map(allData, function (item) {
return new Match(item);
});
self.matches = self.matchesFromDb;
self.selectedMatchId = ko.observable(self.matches[0].id());
self.selectedMatch = ko.observable(self.matches[0]);
self.setSelectedMatchId = function (match) {
if (match.id() != self.selectedMatchId()) {
self.selectedMatchId(match.id());
self.selectedMatch(match);
}
};
self.patternValues = ko.observableArray(["Shark", "Viper", "Chameleon", "Cheetah", "Scorpion"]);
}
我做了一个 fiddle 来测试 jqmValue 自定义绑定,这是在 SO 发现的最新解决方案之一,但我无法让它工作:
ko.bindingHandlers.jqmValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
if (typeof ko.bindingHandlers.value.init !== 'undefined') {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
}
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var instance;
if (typeof ko.bindingHandlers.value.update !== 'undefined') {
ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel);
}
instance = $.data(element, 'mobile-selectmenu');
if (instance) {
$(element).selectmenu('refresh', true);
}
}
};
(AdminViewModel 的原始代码作为 KO 2.x 的参考,感谢 pablo 正在处理建议的更改以在标记中反转 value/options 感谢 JohnEarles 在 google 组)
这是带有实际 KO 和 JQM 版本的 fiddle,我试图在其中包含关于该主题的所有最佳建议:
但我仍在拉长头发,但没有成功。为什么在我的测试中 fiddle 对视图模型的更改没有反映到 JQM select 菜单中?我的错误是什么?
UPDATE:两页 fiddle 测试初始化:http://jsfiddle.net/nHNzL/50/
最终版本:
我做了 2 个小修复和 1 个更改:
1)每次都要检查isInstance
2) 删除了 if (currentValue == value)
3) 反转disabled属性
此外:我在 ko foreach 循环中测试了这个自定义绑定,每个 select 元素都需要是自己容器 div.
的子元素
ko.bindingHandlers.jqmSelectMenu = {
init: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
valueObservable = allBindings.get("value"), valueSubscription,
optionsObservable = allBindings.get("options"), optionsSubscription;
var refresh = function () {
var $el = $(element);
var isInstance = !!$.data(element, 'mobile-selectmenu');
if (isInstance) {
$el.selectmenu('refresh', true);
} else {
/* instantiate the widget unless jqm has already done so */
$(element).selectmenu(options);
}
};
refresh();
/* hook up to the observables that make up the underlying <select> */
if (ko.isSubscribable(valueObservable)) {
valueSubscription = valueObservable.subscribe(refresh);
}
if (ko.isSubscribable(optionsObservable)) {
optionsSubscription = optionsObservable.subscribe(refresh);
}
/* properly dispose of widgets & subscriptions when element is removed */
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).selectmenu("destroy");
if (valueSubscription) valueSubscription.dispose();
if (optionsSubscription) optionsSubscription.dispose();
});
},
update: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
$el = $(element);
/* update any widget options if necessary */
ko.utils.objectForEach(options, function (key, value) {
if (key === "enabled") {
$el.selectmenu(value ? "enable" : "disable");
} else {
$el.selectmenu("option", key, value);
}
});
}
};
事实上你是在混合两种不同的东西。
- 存在基础
<select>
元素。它包含可用选项以及 selected 选项。
- 然后是 jQuery 移动
SelectMenu
小部件。它与用户体验部分有关。看一下它提供的 the API options 就会发现它与底层 select 框确实没有太大关系,主要用于自初始化。
当然,小部件会将值更改传达给基础 select 框,但是当您以编程方式更改值时,您必须自己通过调用 refresh
将其传达给小部件。所以即使没有淘汰,这也不是双向沟通。
我们做 有一组敲除内置绑定,可以很好地与 select 盒子一起工作,但我们不做 有一个绑定,可以将这些值的更改传达给小部件。我们还没有的是 initializing/updating 任何小部件的 API 选项的方法。
因此,我们不需要重新发明 value
绑定,而是需要一个处理小部件本身的绑定,否则只是对现有绑定进行补充:
ko.bindingHandlers.jqmSelectMenu = {
init: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
valueObservable = allBindings.get("value"), valueSubscription,
optionsObservable = allBindings.get("options"), optionsSubscription,
isInstance = !!$.data(element, 'mobile-selectmenu'),
refresh = function () { $(element).selectmenu('refresh', true); };
// instantiate the widget unless jqm has already done so
if (!isInstance) $(element).selectmenu(options);
refresh();
// hook up to the observables that make up the underlying <select>
if (ko.isSubscribable(valueObservable)) {
valueSubscription = valueObservable.subscribe(refresh);
}
if (ko.isSubscribable(optionsObservable)) {
optionsSubscription = optionsObservable.subscribe(refresh);
}
// properly dispose of widgets & subscriptions when element is removed
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).selectmenu("destroy");
if (valueSubscription) valueSubscription.dispose();
if (optionsSubscription) optionsSubscription.dispose();
});
},
update: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
$elem = $(element);
// update any widget options if necessary
ko.utils.objectForEach(options, function (key, value) {
var currentValue = $elem.selectmenu("option", key);
if (currentValue !== value) {
if (key === "disabled") {
$elem.selectmenu(value ? "disable" : "enable");
} else {
$elem.selectmenu("option", key, value);
}
}
});
}
};
我本着knockout-jQueryUI的精神写下这篇文章的。我建议看看那个图书馆。
这里也更新了 fiddle。 http://jsfiddle.net/nHNzL/46/
我正在使用 knockout.js 3.3.0 和 jQuery 移动版 1.4。 knockout.js 与 jQuery 移动设备一起使用的问题在于,由于 html 元素的 JQM 重构,以编程方式对底层视图模型的更改并不总是反映到图形用户界面,或者小部件。因此,例如,JQM select 菜单从用户界面同步到视图模型,但不是以其他方式。
我正在尝试将 3.3.0 KO 'options' 绑定与当前 JQM 实际版本的自定义绑定结合在一起。 对于 'refresh' 问题已经在 SO 上针对 2.x 版本的 KO 提出了两种可能的解决方案:jqmSelect 和 jqmValue,作为自定义绑定。 我尝试将此建议用于最近的 KO+JQM 组合,将在 SO 找到的关于该主题的所有 answers/comments 放在一起。
这是我用来测试的js:
$(document).ready(function () {
var jsonResultData = [{
"id": 6,
"name": "First item",
"pattern": "Cheetah"
}, {
"id": 2,
"name": "Second item",
"pattern": "Viper"
}, {
"id": 1,
"name": "Third item",
"pattern": "Scorpion"
}];
ko.applyBindings(new AdminViewModel(jsonResultData));
});
function Match(data) {
this.id = ko.observable(data.id);
this.pattern = ko.observable(data.pattern);
this.name = ko.observable(data.name);
}
function AdminViewModel(allData) {
var self = this;
self.matches = ko.observableArray([]);
self.matchesFromDb = $.map(allData, function (item) {
return new Match(item);
});
self.matches = self.matchesFromDb;
self.selectedMatchId = ko.observable(self.matches[0].id());
self.selectedMatch = ko.observable(self.matches[0]);
self.setSelectedMatchId = function (match) {
if (match.id() != self.selectedMatchId()) {
self.selectedMatchId(match.id());
self.selectedMatch(match);
}
};
self.patternValues = ko.observableArray(["Shark", "Viper", "Chameleon", "Cheetah", "Scorpion"]);
}
我做了一个 fiddle 来测试 jqmValue 自定义绑定,这是在 SO 发现的最新解决方案之一,但我无法让它工作:
ko.bindingHandlers.jqmValue = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
if (typeof ko.bindingHandlers.value.init !== 'undefined') {
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);
}
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var instance;
if (typeof ko.bindingHandlers.value.update !== 'undefined') {
ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel);
}
instance = $.data(element, 'mobile-selectmenu');
if (instance) {
$(element).selectmenu('refresh', true);
}
}
};
(AdminViewModel 的原始代码作为 KO 2.x 的参考,感谢 pablo 正在处理建议的更改以在标记中反转 value/options 感谢 JohnEarles 在 google 组)
这是带有实际 KO 和 JQM 版本的 fiddle,我试图在其中包含关于该主题的所有最佳建议:
但我仍在拉长头发,但没有成功。为什么在我的测试中 fiddle 对视图模型的更改没有反映到 JQM select 菜单中?我的错误是什么?
UPDATE:两页 fiddle 测试初始化:http://jsfiddle.net/nHNzL/50/
最终版本: 我做了 2 个小修复和 1 个更改: 1)每次都要检查isInstance 2) 删除了 if (currentValue == value) 3) 反转disabled属性 此外:我在 ko foreach 循环中测试了这个自定义绑定,每个 select 元素都需要是自己容器 div.
的子元素ko.bindingHandlers.jqmSelectMenu = {
init: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
valueObservable = allBindings.get("value"), valueSubscription,
optionsObservable = allBindings.get("options"), optionsSubscription;
var refresh = function () {
var $el = $(element);
var isInstance = !!$.data(element, 'mobile-selectmenu');
if (isInstance) {
$el.selectmenu('refresh', true);
} else {
/* instantiate the widget unless jqm has already done so */
$(element).selectmenu(options);
}
};
refresh();
/* hook up to the observables that make up the underlying <select> */
if (ko.isSubscribable(valueObservable)) {
valueSubscription = valueObservable.subscribe(refresh);
}
if (ko.isSubscribable(optionsObservable)) {
optionsSubscription = optionsObservable.subscribe(refresh);
}
/* properly dispose of widgets & subscriptions when element is removed */
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).selectmenu("destroy");
if (valueSubscription) valueSubscription.dispose();
if (optionsSubscription) optionsSubscription.dispose();
});
},
update: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
$el = $(element);
/* update any widget options if necessary */
ko.utils.objectForEach(options, function (key, value) {
if (key === "enabled") {
$el.selectmenu(value ? "enable" : "disable");
} else {
$el.selectmenu("option", key, value);
}
});
}
};
事实上你是在混合两种不同的东西。
- 存在基础
<select>
元素。它包含可用选项以及 selected 选项。 - 然后是 jQuery 移动
SelectMenu
小部件。它与用户体验部分有关。看一下它提供的 the API options 就会发现它与底层 select 框确实没有太大关系,主要用于自初始化。
当然,小部件会将值更改传达给基础 select 框,但是当您以编程方式更改值时,您必须自己通过调用 refresh
将其传达给小部件。所以即使没有淘汰,这也不是双向沟通。
我们做 有一组敲除内置绑定,可以很好地与 select 盒子一起工作,但我们不做 有一个绑定,可以将这些值的更改传达给小部件。我们还没有的是 initializing/updating 任何小部件的 API 选项的方法。
因此,我们不需要重新发明 value
绑定,而是需要一个处理小部件本身的绑定,否则只是对现有绑定进行补充:
ko.bindingHandlers.jqmSelectMenu = {
init: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
valueObservable = allBindings.get("value"), valueSubscription,
optionsObservable = allBindings.get("options"), optionsSubscription,
isInstance = !!$.data(element, 'mobile-selectmenu'),
refresh = function () { $(element).selectmenu('refresh', true); };
// instantiate the widget unless jqm has already done so
if (!isInstance) $(element).selectmenu(options);
refresh();
// hook up to the observables that make up the underlying <select>
if (ko.isSubscribable(valueObservable)) {
valueSubscription = valueObservable.subscribe(refresh);
}
if (ko.isSubscribable(optionsObservable)) {
optionsSubscription = optionsObservable.subscribe(refresh);
}
// properly dispose of widgets & subscriptions when element is removed
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).selectmenu("destroy");
if (valueSubscription) valueSubscription.dispose();
if (optionsSubscription) optionsSubscription.dispose();
});
},
update: function (element, valueAccessor, allBindings) {
var options = ko.toJS(valueAccessor()),
$elem = $(element);
// update any widget options if necessary
ko.utils.objectForEach(options, function (key, value) {
var currentValue = $elem.selectmenu("option", key);
if (currentValue !== value) {
if (key === "disabled") {
$elem.selectmenu(value ? "disable" : "enable");
} else {
$elem.selectmenu("option", key, value);
}
}
});
}
};
我本着knockout-jQueryUI的精神写下这篇文章的。我建议看看那个图书馆。
这里也更新了 fiddle。 http://jsfiddle.net/nHNzL/46/