调用 ko.applicyBindings 时获取“ Can not read property‘ nodeType’of null”

我有个击倒密码:

function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}


function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() });
});


// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.remove(task) };
}


ko.applyBindings(new TaskListViewModel());

这个 html:

<head>
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="knockout-2.0.0.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h3>Tasks</h3>


<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>


<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title, disable: isDone" />
<a href="#" data-bind="click: $parent.removeTask">Delete</a>
</li>
</ul>


You have <b data-bind="text: incompleteTasks().length">&nbsp;</b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
</body>

这个例子和在 Knokout 网站上找到的一样,但是当我运行它的时候,它会在 Chrome Fire Bug 上返回以下信息:

未捕获的 TypeError: 无法读取 null 的“ nodeType”属性

这个是关于淘汰赛的文件和我的脚本的这一行:

ko.applyBindings(new TaskListViewModel());

这个错误指向了淘汰赛中的这条线(1766) :

var isElement = (nodeVerified.nodeType == 1);

我做错了什么?

79264 次浏览

You have a simple spelling mistake:

self.addTask = fuction() {

Should be:

self.addTask = function() { //Notice the added 'n' in 'function'

This problem was happening because I was trying to bind an HTML element before it was created.

My script was loaded on top of the HTML (in the head) but it needed to be loaded at the bottom of my HTML code (just before the closing body tag).

Thanks for your attention James Allardice.

A possible workaround is using defer="defer"

<script src="script.js" type="text/javascript" defer="defer"></script>

Use this if the script is not going to generate any document content. This will tell the browser that it can wait for the content to be loaded before loading the script.

Further reading.

Hope it helps.

You might want to consider using the jquery ready handler for this

$(function() {
function TaskListViewModel() {
...
ko.applyBindings(new TaskListViewModel());
});

Then you achieve two things:

  1. Avoid polluting the global namespace
  2. Knockout binding occurs AFTER the DOM is created. You can place your javascript wherever it is suited for organization.

See http://api.jquery.com/ready/

if you have jQuery put apply binding inside onload so that knockout looks for the DOM when DOM is ready.

$(document).ready(function(){
ko.applyBindings(new TaskListViewModel());
});