当使用此JSFiddle作为参考来构建具有可组织内容的网格时,我遇到了一个问题。错误消息显示 Error: viewModel is not defined
。
它通常应该像示例中一样工作,因为我的viewModel
是在 JS 的第一行定义的。它可能与从模板中请求viewModel
有关。
在检查其他答案时,它们都太笼统了。我没有找到一个可以回答我的问题的人。
完整错误:
Uncaught ReferenceError: Unable to process binding "template: function (){return { name:'gridTmpl',foreach:gridItems,templateOptions:{ parentList:gridItems}} }"
Message: Unable to process binding "template: function (){return { name:'rowTmpl',foreach:rowItems,templateOptions:{ parentList:rowItems}} }"
Message: Unable to process binding "visible: function (){return $data !== viewModel.selectedRowItem() }"
Message: viewModel is not defined
var viewModel = {
gridItems: ko.observableArray(
[{
"rowItems": [{
"name": "Item 1"
}, {
"name": "Item 2"
}, {
"name": "Item 3"
}]
}, {
"rowItems": [{
"name": "Item 4"
}]
}, {
"rowItems": [{
"name": "Item 5"
}, {
"name": "Item 6"
}]
}]
),
selectedRowItem: ko.observable(),
selectRowItem: function(rowItem) {
this.selectedRowItem(rowItem);
}
};
//connect items with observableArrays
ko.bindingHandlers.sortableList = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
$(element).data("sortList", valueAccessor()); //attach meta-data
$(element).sortable({
update: function(event, ui) {
var item = ui.item.data("sortItem");
if (item) {
//identify parents
var originalParent = ui.item.data("parentList");
var newParent = ui.item.parent().data("sortList");
//figure out its new position
var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
if (position >= 0) {
originalParent.remove(item);
newParent.splice(position, 0, item);
}
ui.item.remove();
}
},
connectWith: '.container'
});
}
};
//attach meta-data
ko.bindingHandlers.sortableItem = {
init: function(element, valueAccessor) {
var options = valueAccessor();
$(element).data("sortItem", options.item);
$(element).data("parentList", options.parentList);
}
};
//control visibility, give element focus, and select the contents (in order)
ko.bindingHandlers.visibleAndSelect = {
update: function(element, valueAccessor) {
ko.bindingHandlers.visible.update(element, valueAccessor);
if (valueAccessor()) {
setTimeout(function() {
$(element).focus().select();
}, 0); //new RowItems are not in DOM yet
}
}
}
ko.applyBindings(viewModel);
.sortable {
list-style-type: none;
margin: 0;
padding: 0;
width: 60%;
}
.sortable li {
margin: 0 3px 3px 3px;
padding: 0.4em;
padding-left: 1.5em;
font-size: 1.4em;
height: 18px;
cursor: move;
}
.sortable li span {
position: absolute;
margin-left: -1.3em;
}
.sortable li.fixed {
cursor: default;
color: #959595;
opacity: 0.5;
}
.sortable-grid {
width: 100% !important;
}
.sortable-row {
height: 100% !important;
padding: 0 !important;
margin: 0 !important;
display: block !important;
}
.sortable-item {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.0-beta.1/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul class="sortable sortable-grid" data-bind="template: { name: 'gridTmpl', foreach: gridItems, templateOptions: { parentList: gridItems} }, sortableList: gridItems">
</ul>
<script id="gridTmpl" type="text/html">
<li class="sortable-row">
<table style="width:100%">
<tbody>
<tr class="sortable container" data-bind="template: { name: 'rowTmpl', foreach: rowItems, templateOptions: { parentList: rowItems} }, sortableList: rowItems">
</tr>
</tbody>
</table>
</li>
</script>
<script id="rowTmpl" type="text/html">
<td class="item" data-bind="sortableItem: { item: $data, parentList: $item.parentList }">
<a href="#" data-bind="text: name, click: function() { viewModel.selectRowItem($data); }, visible: $data !== viewModel.selectedRowItem()"></a>
<input data-bind="value: name, visibleAndSelect: $data === viewModel.selectedRowItem()" />
</td>
</script>
viewModel
未在视图模型中定义。调用ko.applyBindings(viewModel);
时,不会携带名称viewModel
以在绑定引用中使用;我想你想要$root
。您应该能够执行以下操作:
<td class="item" data-bind="sortableItem: { item: $data, parentList: $item.parentList }">
<a href="#" data-bind="text: name, click: function() { $root.selectRowItem($data); }, visible: $data !== $root.selectedRowItem()"></a>
<input data-bind="value: name, visibleAndSelect: $data === $root.selectedRowItem()" />
</td>
应用绑定时需要实例化视图模型,否则不会调用构造函数。这就是为什么它需要是一个函数,而不是一个对象。
ko.applyBindings(new viewModel());
这是您的视图模型必须更改的方式:
var viewModel = function() {
var self = this;
self.gridItems= ko.observableArray(
[{
"rowItems": [{
"name": "Item 1"
}, {
"name": "Item 2"
}, {
"name": "Item 3"
}
]
}, {
"rowItems": [{
"name": "Item 4"
}]
}, {
"rowItems": [{
"name": "Item 5"
}, {
"name": "Item 6"
}]
}]
);
self.selectedRowItem = ko.observable();
self.selectRowItem = function(rowItem) {
this.selectedRowItem(rowItem);
};
};
视图模型属性不应从视图模型外部更改或读取。要访问视图模型中的属性,不能使用 viewmodel
,因为它在 KO 绑定上下文中是未知的。您无法访问这些前缀$root
:
<script id="rowTmpl" type="text/html">
<td class="item" data-bind="sortableItem: { item: $data, parentList: $data.parentList }">
<a href="#" data-bind="text: name, click: function() { $root.selectRowItem($data); }, visible: $data !== $root.selectedRowItem()"></a>
<input data-bind="value: name, visibleAndSelect: $data === $root.selectedRowItem()" />
</td>
</script>