2012-11-11 4 views
2

J'ai un modèle de vue qui récupère JSON via AJAX et crée une nouvelle tâche, mais Knockout continue de me donner une erreur de liaison.Knockout.js: Impossible d'analyser les liaisons à partir de JSON

Si je code directement les données provenant du serveur directement dans mon modèle de vue, je ne reçois aucune erreur.

Mon modèle de vue crée une nouvelle tâche, qui a un identifiant, une question et un certain nombre de variantes, ce qui en soi a un texte et un drapeau booléen correct.

Le code suivant fonctionne parfaitement bien:

function Task(data) { 
    var self = this; 

    self.id = data.id; 
    self.question = ko.observable(data.question); 

    var alts = new Array(); 
    $(data.alternatives).each(function(index){ 
     alts.push(new Alternative(data.alternatives[index].alternative, data.alternatives[index].correct)); 
    }); 

    self.alternatives = ko.observableArray(alts); 
} 
function Alternative(alternativeText, correctAnswer) { 
    var self   = this; 
    self.alternative = ko.observable(alternativeText); 
    self.correct  = ko.observable(correctAnswer); 
} 
function TaskViewModel() { 
    var self = this; 

    var data = { 
     id: 5, 
     question: 'test', 
     alternatives: [{ 
      alternative: 'alt 1', 
      correct: false 
     },{ 
      alternative: 'alt 2', 
      correct: true 
     },{ 
      alternative: 'alt 3', 
      correct: false 
     }] 
    }; 

    self.task = new Task(data); 
} 

Mais si j'exhcange la variable data codée en dur avec des données réelles du serveur:

function TaskViewModel() { 
    var self = this; 

    $.getJSON('/data', function(data){ 
     self.task = new Task(data); 
    }); 
} 

knock-out me donne cette erreur:

Error: Unable to parse bindings. 
Message: ReferenceError: Can't find variable: task; 
Bindings value: value: task.question 

Les données de l'URL ressemblent à ceci:

{"id":5,"question":"test","alternatives":[{"alternative":"alt 1","correct":false},{"alternative":"alt 2","correct":true},{"alternative":"alt 3","correct":false}]} 

Je ne peux pas sembler comprendre pourquoi cela ne fonctionnera pas:/

Répondre

6

Votre modèle de vue n'a pas en fait une propriété task au moment où vos fixations sont appliquées. Vous devez lui donner quelque chose à lier.

Il y a plusieurs façons de gérer cela.

Probablement le moyen le plus simple serait de rendre task observable et de le définir comme le résultat de l'appel ajax. Vous devrez peut-être ajuster vos liaisons pour tenir compte de ce changement.

function TaskViewModel() { 
    var self = this; 
    self.task = ko.observable(); 

    $.getJSON('/data', function(data){ 
     self.task(new Task(data)); 
    }); 
} 

Une option plus flexible serait d'ajouter une méthode d'initialisation séparée pour vos objets Task et définissez la tâche (non initialisée). Puis, à la suite de l'appel ajax, appelez la méthode d'initialisation pour l'initialiser. Vous devrez bien sûr ajuster le code d'initialisation de vos objets de tâche.

function TaskViewModel() { 
    var self = this; 
    self.task = new Task(); 

    $.getJSON('/data', function(data){ 
     self.task.init(data); 
    }); 
} 

function Task() { 
    var self = this; 
    self.id = ko.observable(); 
    self.question = ko.observable(); 
    self.alternatives = ko.observableArray(); 

    self.init = function (data) { 
     self.id(data.id); 
     self.question(data.question); 
     self.alternatives(ko.utils.arrayForEach(data.alternatives, function (item) { 
      return new Alternative(item.alternative, item.correct); 
     })); 
    }; 
} 
+0

Merci l'homme. En fait, j'ai compris cela après les choses que vous avez mentionnées avec une méthode d'initialisation (que vous avez présentée ici). Cela a fonctionné comme il se doit :) –

4

Ce message contient un certain nombre de façons de gérer la liaison lorsque la source est null.

KnockoutJS binding when source is null/undefined

Si vous êtes OK avec votre interface utilisateur unbindable de disparaître Je recommande d'utiliser with

Si selectedItem est nul alors l'élément ne sera pas affiché même.

<div data-bind="with: selecteditem"> 
    <form> 
     <fieldset> 
      <div> 
       <label>first name</label> 
       <input data-bind="value: firstname"></input> 
      </div> 
      <div> 
       <label>lasst name</label> 
       <input data-bind="value: lastname"></input> 
      </div> 
     </fieldset> 
     <div> 
      <a href="#" data-bind="click: $root.savechanges">Save</a> 
     </div> 
    </form> 
</div> 
+0

note: avec cette méthode, cette div est supprimée du DOM quand 'selecteditem' est null, donc si vous avez des gestionnaires d'événements non 'live', alors cela peut ne pas fonctionner –

+0

+1 Great répondre! – Legend

Questions connexes