在 Durandal 中,我正在寻找一种通过分配viewOptions: ko.observable("small")
来快速初始化活动切换按钮的方法。在发生viewOptions
更改的同时,我希望使用相应的id
切换按钮并关闭所有其他按钮。
在我尝试过的几种方法中,没有一种方法可以做到这一点。以下代码中缺少什么?
HTML:
<div class="btn-group right" id="view-selector" data-toggle="buttons" data-bind="radio: viewOptions">
<button type="button" id="small" class="btn btn-default" data-bind="css: {active: viewOptions() == 'small'}"><span class="glyphicon glyphicon-stop">Small</button>
<button type="button" id="medium" class="btn btn-default" data-bind="css: {active: viewOptions() == 'medium'}"><span class="glyphicon glyphicon-th-large">Medium</button>
<button type="button" id="large" class="btn btn-default" data-bind="css: {active: viewOptions() == 'large'}"><span class="glyphicon glyphicon-th">Large</button>
</div>
JS:
define(['jquery', 'jquery-ui', 'bootstrap', 'knockout', 'durandal/app', 'plugins/router'], function($, jqueryui, bootstrap, ko, app, router) {
return {
viewOptions: ko.observable("small"),
bindingComplete: function() { // called immediately after databinding occurs.
alert("start"); //called
console.log("validate: this:", this); // Object {__moduleId__: "app/view"}
console.log("validate: viewOptions:",this.viewOptions); // OK, non-empty
this.viewOptions.subscribe(function(newViewOptions){
alert("Hello there!"); //never gets called
alert(newViewOptions); //
});
alert("end"); //called
}
}
});
答案 0 :(得分:2)
自定义绑定&#34; radio&#34;从数据属性&#34; data-value&#34;中驱动每个切换按钮的值,因此您必须为每个选项指定该值,如:
<button type="button" id="small" class="btn btn-default" data-value="small"> ...
这应该照顾这个小提琴演示http://jsfiddle.net/ccjnj/171/
答案 1 :(得分:1)
您使用the css
binding,告诉它在active
(或中等或大)时应用viewOptions() == 'small'
课程:
<button ... data-bind="css: {active: viewOptions() == 'small'}">...</button>
示例:
var viewModel = {
viewOptions: ko.observable("small"),
};
ko.applyBindings(viewModel);
loop();
function loop() {
viewModel.viewOptions("small");
setTimeout(function() {
viewModel.viewOptions("medium");
}, 1000);
setTimeout(function() {
viewModel.viewOptions("large");
}, 2000);
setTimeout(loop, 3000);
}
&#13;
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<div class="btn-group right" id="view-selector" data-toggle="buttons" data-bind="radio: viewOptions">
<button type="button" id="small" class="btn btn-default" data-bind="css: {active: viewOptions() == 'small'}"><span class="glyphicon glyphicon-stop">Small</button>
<button type="button" id="medium" class="btn btn-default" data-bind="css: {active: viewOptions() == 'medium'}"><span class="glyphicon glyphicon-th-large">Medium</button>
<button type="button" id="large" class="btn btn-default" data-bind="css: {active: viewOptions() == 'large'}"><span class="glyphicon glyphicon-th">Large</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
&#13;
我从上面删除了订阅,因为我以为你只是用它来设置课程。如果您还想要订阅 ,只需将其添加回来(在浏览器控制台中查看):
var viewModel = {
viewOptions: ko.observable("small"),
attached: function() {
this.viewOptions.subscribe(function(newViewOptions){
console.log(newViewOptions);
}, this); // <== No need for bind, note subscribe' 2nd arg
}
};
ko.applyBindings(viewModel);
viewModel.attached();
var timeout = +new Date() + 10000;
loop();
function loop() {
viewModel.viewOptions("small");
setTimeout(function() {
viewModel.viewOptions("medium");
}, 1000);
setTimeout(function() {
viewModel.viewOptions("large");
}, 2000);
if (+new Date() < timeout) {
setTimeout(loop, 3000);
}
}
&#13;
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<div class="btn-group right" id="view-selector" data-toggle="buttons" data-bind="radio: viewOptions">
<button type="button" id="small" class="btn btn-default" data-bind="css: {active: viewOptions() == 'small'}"><span class="glyphicon glyphicon-stop">Small</button>
<button type="button" id="medium" class="btn btn-default" data-bind="css: {active: viewOptions() == 'medium'}"><span class="glyphicon glyphicon-th-large">Medium</button>
<button type="button" id="large" class="btn btn-default" data-bind="css: {active: viewOptions() == 'large'}"><span class="glyphicon glyphicon-th">Large</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
&#13;
答案 2 :(得分:1)
T.J。克劳德有一个很好的答案。我只是认为在viewmodel中创建按钮项并使用foreach
绑定来渲染它们似乎是个好主意。保存重复的HTML。
function buttonData(label, value) {
return {
label: label,
value: value
};
}
var viewModel = {
buttons: [
buttonData('Small', 'small'),
buttonData('Medium', 'medium'),
buttonData('Large', 'large')
],
selectedButton: ko.observable("small"),
setOption: function(data) {
console.debug("Set option", data.value);
viewModel.selectedButton(data.value);
}
};
ko.applyBindings(viewModel);
viewModel.selectedButton.subscribe(function(newViewOptions) {
alert("Hello there!");
alert(newViewOptions);
});
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="btn-group right" id="view-selector" data-toggle="buttons" data-bind="foreach: buttons">
<button type="button" class="btn btn-default" data-bind="click:$root.setOption, text:label, css: { active: value == $root.selectedButton()}"></button>
</div>
答案 3 :(得分:0)
将解决方案的各个方面结合起来就能找到答案。我意识到Durandal中的事件处理模型与Knockout略有不同,在我错过ko.bindingHandlers.radio
和bindingComplete
之前需要以下代码:
define(['jquery', 'jquery-ui', 'bootstrap', 'knockout', 'durandal/app', 'plugins/router'], function($, jqueryui, bootstrap, ko, app, router) {
ko.bindingHandlers.radio = {
init: function(element, valueAccessor, allBindings, data, context) {
var $buttons, $element, observable;
observable = valueAccessor();
if (!ko.isWriteableObservable(observable)) {
throw "You must pass an observable or writeable computed";
}
$element = $(element);
if ($element.hasClass("btn")) {
$buttons = $element;
}
else {
$buttons = $(".btn", $element);
}
var elementBindings = allBindings();
$buttons.each(function() {
var $btn, btn, radioValue;
btn = this;
$btn = $(btn);
radioValue = $btn.attr("id");
$btn.on("click", function() {
observable(ko.utils.unwrapObservable(radioValue));
});
return ko.computed({
disposeWhenNodeIsRemoved: btn,
read: function() {
$btn.toggleClass("active", observable() === ko.utils.unwrapObservable(radioValue));
}
});
});
}
};
var vm = {
viewOptions: ko.observable(),
bindingComplete: function() {
vm.viewOptions.subscribe(function(newViewOptions){
alert("Hello there!");
alert(newViewOptions);
});
vm.viewOptions("large");
}
}
return vm;
});