2010-12-09 14 views
3

J'ai joué un peu avec knockoutjs et j'ai produit l'exemple suivant, assez pour être excité par l'idée de construire ces viewmodels en javascript pour que la vue puisse être écrite de manière beaucoup plus simple et déclarative, ie d'abord définir vous voulez observer, puis avec les attributs data-bind définir ce que vous voulez lorsque votre viewmodel change de certaines façons.Comment utiliser KnockoutJS pour observer les données sur le serveur via AJAX?

Mais tout cela se passe uniquement sur le client.

Comment pourrais-je étendre cet exemple pour utiliser knockoutjs afin d'observer l'état des objets sur le serveur, par ex. via les appels AJAX?

index.htm:

<!doctype html> 
<html> 
    <title>Knockout example</title> 
    <head> 
     <script type="text/javascript" src="js/knockout-1.1.1.debug.js"></script> 
     <script type="text/javascript" src="js/main.js"></script> 
     <link rel="stylesheet" href="css/main.css" type="text/css"/> 
    </head> 
    <body> 

     <!-- FIRST AREA --> 
     <div class="infobox"> 
      <div data-bind="visible: noNamesFilled"> 
       <p>This is an example with NO names filled.</p> 
      </div> 
      <div data-bind="visible: bothNamesFilled"> 
       <p>This is an example with both names filled.</p> 
      </div> 
      <div data-bind="visible: firstNameOnlyFilled"> 
       <p>This is an example with only the first name filled.</p> 
      </div> 
      <div data-bind="visible: lastNameOnlyFilled"> 
       <p>This is an example with the last name filled but not the first name</p> 
      </div> 
     </div> 

     <!-- SECOND AREA --> 
     <p>First name: <input data-bind="value: firstName, valueUpdate:'afterkeydown'" /></p> 
     <p>Last name: <input data-bind="value: lastName, valueUpdate:'afterkeydown'" /></p> 
     <div data-bind="visible: bothNamesFilled"> 
      <h2 class="normal">Hello, <span data-bind="text: fullName"></span>.</h2> 
     </div> 
     <div data-bind="visible: firstNameOnlyFilled"> 
      <h2 class="informal">Hi there <span data-bind="text: fullName"></span>!</h2> 
     </div> 
     <div data-bind="visible: lastNameOnlyFilled"> 
      <h2 class="formal">Hello, Mr. <span data-bind="text: fullName"></span>.</h2> 
     </div> 

     <!-- THIRD AREA --> 
     <div data-bind="visible: noNamesFilled"> 
      <p><span class="bad">:-(</span> Please fill in both names.</p> 
     </div> 
     <div data-bind="visible: bothNamesFilled"> 
      <p><span class="good">:-)</span> Good job, both names are filled!</p> 
     </div> 
     <div data-bind="visible: firstNameOnlyFilled"> 
      <p><span class="ok">:-(</span> Please fill in the last name, too.</p> 
     </div> 
     <div data-bind="visible: lastNameOnlyFilled"> 
      <p><span class="ko">:-(</span> Please fill in the first name as well.</p> 
     </div> 
    </body> 
</html> 

main.css:

* { margin: 0; padding: 0} 
body { margin: 10px} 
p { margin: 10px} 
.infobox { 
    background-color: #eee; 
    width: 300px; 
    height: 100px; 
    padding: 10px; 
} 
.informal { 
    color: purple; 
    font-family: arial; 
} 
.normal { 
    color: black; 
    font-family: new courier; 
} 
.formal { 
    color: black; 
    font-size: 11pt; 
    font-family: times roman; 
    background-color: #eee; 
} 
.good { 
    width: 20px; 
    background-color: lightgreen; 
} 
.ok { 
    width: 20px; 
    background-color: yellow; 
} 
.bad { 
    width: 20px; 
    background-color: tomato; 
} 

main.js:

window.onload= function() { 

    var viewModel = { 
     firstName : ko.observable(''), 
     lastName : ko.observable('') 
    }; 
    viewModel.fullName = ko.dependentObservable(function() { 
     return viewModel.firstName() + " " + viewModel.lastName(); 
    }); 

    viewModel.bothNamesFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length > 0 && viewModel.lastName().length > 0; 
    }, this); 
    viewModel.firstNameOnlyFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length > 0 && viewModel.lastName().length == 0; 
    }, this); 
    viewModel.lastNameOnlyFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length == 0 && viewModel.lastName().length > 0; 
    }, this); 
    viewModel.noNamesFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length == 0 && viewModel.lastName().length == 0; 
    }, this); 

    ko.applyBindings(viewModel); 
} 

Répondre

4

J'utiliserais setTimeout pour appeler une fonction qui utilise JQuery pour faire un appel à $ .ajax. Quand il renvoie des données JSON, définissez ces données comme votre modèle de vue et enfin, setTimeout à nouveau pour appeler la fonction.

0

Voici un exemple mis à jour qui met principalement à jour main.js pour travailler avec JQuery pour faire l'appel ajax.

Le fichier HTML inclut Knockout 3 au lieu de 1. Le code HTML inclut également JQuery plus récent pour que la fonctionnalité JQuery fonctionne. Le fichier js/server_data.js est là pour que vous ayez quelques données json valides pour commencer. Vous pouvez changer l'url dans les paramètres $ .ajax à n'importe quel script sur le serveur, mais essayez de définir son type de contenu sur application/json. Par exemple, les scripts PHP peuvent définir l'en-tête Content-type comme: header ('Content-type: application/json'); avant d'imprimer les données au format JSON.

nouvelles main.html:

<!doctype html> 
<html> 
    <title>Knockout example</title> 
    <head> 
     <script type="text/javascript" src="js/knockout-3.0.0.debug.js"></script> 
     <script src="http://code.jquery.com/jquery-latest.min.js"></script> 
     <script type="text/javascript" src="js/main.js"></script> 
     <link rel="stylesheet" href="css/main.css" type="text/css"/> 
    </head> 
    <body> 

     <!-- FIRST AREA --> 
     <div class="infobox"> 
      <div data-bind="visible: noNamesFilled"> 
       <p>This is an example with NO names filled.</p> 
      </div> 
      <div data-bind="visible: bothNamesFilled"> 
       <p>This is an example with both names filled.</p> 
      </div> 
      <div data-bind="visible: firstNameOnlyFilled"> 
       <p>This is an example with only the first name filled.</p> 
      </div> 
      <div data-bind="visible: lastNameOnlyFilled"> 
       <p>This is an example with the last name filled but not the first name</p> 
      </div> 
     </div> 

     <!-- SECOND AREA --> 
     <p>First name: <input data-bind="value: firstName, valueUpdate:'afterkeydown'" /></p> 
     <p>Last name: <input data-bind="value: lastName, valueUpdate:'afterkeydown'" /></p> 
     <div data-bind="visible: bothNamesFilled"> 
      <h2 class="normal">Hello, <span data-bind="text: fullName"></span>.</h2> 
     </div> 
     <div data-bind="visible: firstNameOnlyFilled"> 
      <h2 class="informal">Hi there <span data-bind="text: fullName"></span>!</h2> 
     </div> 
     <div data-bind="visible: lastNameOnlyFilled"> 
      <h2 class="formal">Hello, Mr. <span data-bind="text: fullName"></span>.</h2> 
     </div> 

     <!-- THIRD AREA --> 
     <div data-bind="visible: noNamesFilled"> 
      <p><span class="bad">:-(</span> Please fill in both names.</p> 
     </div> 
     <div data-bind="visible: bothNamesFilled"> 
      <p><span class="good">:-)</span> Good job, both names are filled!</p> 
     </div> 
     <div data-bind="visible: firstNameOnlyFilled"> 
      <p><span class="ok">:-(</span> Please fill in the last name, too.</p> 
     </div> 
     <div data-bind="visible: lastNameOnlyFilled"> 
      <p><span class="ko">:-(</span> Please fill in the first name as well.</p> 
     </div> 
    </body> 
</html> 

js/main.js:

$(document).ready(function() { 

    var viewModel = { 
     firstName : ko.observable(''), 
     lastName : ko.observable('') 
    }; 
    viewModel.fullName = ko.dependentObservable(function() { 
     return viewModel.firstName() + " " + viewModel.lastName(); 
    }); 

    viewModel.bothNamesFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length > 0 && viewModel.lastName().length > 0; 
    }, this); 
    viewModel.firstNameOnlyFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length > 0 && viewModel.lastName().length == 0; 
    }, this); 
    viewModel.lastNameOnlyFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length == 0 && viewModel.lastName().length > 0; 
    }, this); 
    viewModel.noNamesFilled = ko.dependentObservable(function() { 
     return viewModel.firstName().length == 0 && viewModel.lastName().length == 0; 
    }, this); 

    ko.applyBindings(viewModel); 

    // send request to the server to download the server's model information. 
    $.ajax(
    { 
     'url': 'js/server_data.js', 
     'dataType': 'json', 
     'method': 'post', 
     'error': function(jqXHR, textStatus, errorThrown) 
     { 
      // error callback in case you play with this code and run into trouble. 
      alert('There was a problem handling the ajax request. The error information is: jqXHR: ' 
      +jqXHR+", textStatus: "+textStatus+", errorThrown: "+errorThrown); 
     }, 
     'success': function(data) 
     { 
      // when it is downloaded and parsed to create the "data" parameter, update the viewModel. 
      viewModel.firstName(data.firstName); 
      viewModel.lastName(data.lastName); 
     } 
    } 
    ); 
} 
); 

js/server_data.js représentant des données générées dynamiquement qui peuvent être à partir d'une base de données:

{ 
    "firstName": "John", 
    "lastName": "Doe" 
} 

jsteve a la bonne idée générale mais n'utilise pas setTimeout si vous voulez juste télécharger les données quand le chargement de la page s. Au lieu de cela, utilisez le rappel de document prêt de JQuery et le rappel ajax succès de JQuery afin que les choses s'exécutent précisément quand vous le souhaitez.

Si vous souhaitez écouter en continu et réagir aux modifications apportées aux données sur le serveur, examinez les techniques d'interrogation longue. Le poller long est plus efficace et chronométré avec précision que l'attente occupée qui nécessite une nouvelle demande fréquente au serveur.