Beim Aufrufen von ko.applyBindings wird die Eigenschaft 'nodeType' von null nicht gelesen

99

Ich habe diesen Knockout-Code:

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());

Dieses 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>

Das Beispiel ist das gleiche wie auf der Knockout-Website, aber wenn ich es ausführe, wird diese Meldung in Chrome Fire Bug zurückgegeben:

Nicht erfasster TypeError: Die Eigenschaft 'nodeType' von null kann nicht gelesen werden

Dieser bezieht sich auf die Knockout-Datei und auf diese Zeile meines Skripts:

ko.applyBindings(new TaskListViewModel());

Und dieser Fehler zeigt auf diese Zeile (1766) beim Knockout:

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

Was mache ich falsch?

Gerep
quelle
Dieser Tippfehler würde diesen SyntaxError verursachen. Behebt das Beheben des Tippfehlers das Problem?
James Allardice
Ja ... Ich habe die Frage aktualisiert, weil ein weiterer Fehler aufgetreten ist.
Gerep

Antworten:

176

Dieses Problem trat auf, weil ich versuchte, ein HTMLElement zu binden , bevor es erstellt wurde.

Mein Skript wurde oben auf HTML(im Kopf) geladen, aber es musste unten in meinem HTMLCode geladen werden (kurz vor dem schließenden Body-Tag).

Vielen Dank für Ihre Aufmerksamkeit James Allardice .

Eine mögliche Problemumgehung ist die Verwendung defer="defer"

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

Verwenden Sie diese Option, wenn das Skript keinen Dokumentinhalt generiert. Dadurch wird dem Browser mitgeteilt, dass er warten kann, bis der Inhalt geladen ist, bevor das Skript geladen wird.

Weiterführende Literatur .

Ich hoffe es hilft.

Gerep
quelle
4
Hervorheben: Das <script ...>Tag muss sich kurz vor dem Schließen des </body>Tags am Ende der Seite befinden .
Aliteralmind
1
wunderbar, danke! Ich habe mein Skript einfach an das Ende des Körpers verschoben und es hat perfekt funktioniert. viele Dankbarkeit
Eleanor Zimmermann
33

Möglicherweise möchten Sie hierfür den jquery ready-Handler verwenden

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

Dann erreichen Sie zwei Dinge:

  1. Vermeiden Sie es, den globalen Namespace zu verschmutzen
  2. Die Knockout-Bindung erfolgt NACH dem Erstellen des DOM. Sie können Ihr Javascript überall dort platzieren, wo es für die Organisation geeignet ist.

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

James Kessler
quelle
1
Spoiler Alarm für diejenigen, die nicht RTM: $(handler)ist gleichbedeutend mit$(document).ready(handler)
Brock Hensley
21

Wenn Sie jQuery eingefügt haben, wenden Sie eine Bindung an, onloaddamit Knockout nach dem DOM sucht, wenn das DOM bereit ist.

$(document).ready(function(){
    ko.applyBindings(new TaskListViewModel());
});
Jhankar Mahbub
quelle
Übrigens, kann ich andere Bindungen in den Dokumentenblock einfügen?
Allan Jikamu
1
Danke für deine Information!!
Karthik
5

Sie haben einen einfachen Rechtschreibfehler:

self.addTask = fuction() {

Sollte sein:

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