Obtendo “Não é possível ler a propriedade 'nodeType' de null” ao chamar ko.applyBindings

99

Eu tenho este código nocaute:

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

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

O exemplo é o mesmo encontrado no site Knockout, mas quando eu o executo, ele retorna esta mensagem no Chrome Fire Bug:

TypeError não capturado: não é possível ler a propriedade 'nodeType' de nulo

Este está relacionado ao arquivo knockout e a esta linha do meu script:

ko.applyBindings(new TaskListViewModel());

E este erro está apontando para esta linha (1766) no nocaute:

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

O que estou fazendo de errado?

Gerep
fonte
Esse erro de digitação causaria esse SyntaxError. Corrigir o erro de digitação corrige o problema?
James Allardice
Sim ... Eu atualizei a pergunta porque outro erro ocorreu.
Gerep

Respostas:

176

Este problema estava acontecendo porque eu estava tentando vincular um HTMLelemento antes de ser criado.

Meu script foi carregado na parte superior HTML(no cabeçalho), mas precisava ser carregado na parte inferior do meu HTMLcódigo (antes da tag de fechamento do corpo).

Obrigado pela sua atenção James Allardice .

Uma possível solução é usar defer="defer"

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

Use isso se o script não for gerar nenhum conteúdo de documento. Isso dirá ao navegador que ele pode esperar o conteúdo ser carregado antes de carregar o script.

Leitura adicional .

Espero que ajude.

Gerep
fonte
4
Para enfatizar: a <script ...>tag precisa estar na parte inferior da página, logo antes da </body>tag de fechamento .
aliteralmind de
1
maravilhoso obrigado! Acabei de mover meu script para o final do corpo e funcionou perfeitamente. muitas gratidões
Eleanor Zimmermann
33

Você pode querer considerar o uso do manipulador pronto jquery para isso

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

Então você consegue duas coisas:

  1. Evite poluir o namespace global
  2. A ligação Knockout ocorre APÓS a criação do DOM. Você pode colocar seu javascript onde quer que seja adequado para a organização.

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

James Kessler
fonte
1
Alerta de spoiler para quem não fez RTM: $(handler)é equivalente a$(document).ready(handler)
Brock Hensley
21

se você tiver jQuery, coloque apply binding dentro de onloadmodo que o knockout procure pelo DOM quando o DOM estiver pronto.

$(document).ready(function(){
    ko.applyBindings(new TaskListViewModel());
});
Jhankar Mahbub
fonte
acertou em cheio, btw posso incluir outras ligações no bloco de documentos?
Allan Jikamu
1
Obrigado pela sua informação!!
karthik
5

Você cometeu um erro de grafia simples:

self.addTask = fuction() {

Deveria estar:

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