Question

Après avoir regardé le Knockout.JS vidéo avec Steve Sanderson j'ai décidé cela être grand pour les pages de l'interface utilisateur compliquée.

J'ai travaillé par les exemples en direct et lisez la documentation . Je me suis alors trouvé Ryan Niemeyer grand article . Alors, je voulais construire un exemple similaire à Ryan.

Il afficherait une table. Chaque ligne de la table aurait un budget.
L'utilisateur peut saisir des valeurs pour chaque trimestre.
Le budget moins la somme des quarts donneraient le montant restant.
Si le montant restant n'a pas été la ligne zéro aurait une classe appliquée. La classe tournerait la couleur d'arrière-plan rouge.
Si toutes les lignes ont un reste de ne pas égal à zéro, alors le bouton Enregistrer serait désactivé.

Ce que je suis arrivé travail a été l'affichage initial des données.

Qu'est-ce qui ne fonctionne pas est:

  • Toutes les lignes sont lues même un zéro restant.
  • Lorsque les valeurs trimestre changent la valeur restante ne change pas.
  • bouton Enregistrer est jamais activé.
  • JSON pour sauver n'est pas correct.

Le code se trouve dans ce violon ainsi que ci-dessous.

Tout d'abord, un peu de CSS pour rendre les choses à droite:

   table.pretty {  
       margin: 1em 1em 1em 2em;  
       background: whitesmoke;  
       border-collapse: collapse;  
    }  
    table.pretty th, table.pretty td {  
       border: 1px silver solid;  
       padding: 0.2em;  
    }  
    table.pretty th {  
       background: gainsboro;  
       text-align: left;  
    }  
    table.pretty caption {  
       margin-left: inherit;  
       margin-right: inherit;  
    }  
    .RowError {  
       background-color: Red;  
       color: White;  
    }  

Alors la vue:

<br /><br />  
<p>  
   There are <span data-bind="text: catagoryDetails().length">&nbsp;</span> rows in array<br />  
   I am flexible on changing the structure of data from server.<br />  
   I am flexible on how viewModel is built as long as it can be loaded from server <br />  
   I am flexible on how table is built.  
</p>  
<p>
   As Q1-Q4 values change the Remaining for row changes <br />  
   Row turns red if Remaining != 0 <br />  
   Unable to Save until all rows have a remaining of 0.<br>  
</p>  

<table id="pretty" > 
   <thead>
       <tr>
           <th>CatName</th>
           <th>Budget</th>
           <th>Q1Amt</th>
           <th>Q2Amt</th>
           <th>Q3Amt</th>
           <th>Q4Amt</th>
           <th>Remaining</th>
       </tr>
   </thead>
   <tbody data-bind="template: { name: 'catagoryDetailRowTemplate', foreach: catagoryDetails }"></tbody> 
</table>  

<script type="text/html" id="catagoryDetailRowTemplate"> 
   <tr data-bind="css: { RowError: Remaining !=  0 }">
       <td>
           <input type="hidden" data-bind="value: CatId"/>
           <span data-bind="text: CatName"> </span>
       </td>

       <td><span data-bind="text: BudgetAmt"> </span></td>
       <td><input data-bind="value: Q1Amt"/></td>
       <td><input data-bind="value: Q2Amt"/></td>
       <td><input data-bind="value: Q3Amt"/></td>
       <td><input data-bind="value: Q4Amt"/></td>
       <td><span data-bind="text: Remaining"> </span></td>
   </tr> 
</script>
<form action="ActionOnServer" >
   <input type="hidden" value="Not Set" id="ForServer" name="ForServer"/>
   <input type="submit" onclick="SendDataToServer()" value="Save" data-bind="enable: totalRemaining = 0" />
   <input type="button" onclick="alert('I would do cancel action')" value="Cancel" />
</form>

Et le Javascript:

   function SendDataToServer() {
      // build data to send via json 
      var prepDataToSend = ko.toJS(viewModel.catagoryDetails);
      var mapDataForServer = ko.utils.arrayMap(prepDataToSend, function(item) {
         delete item.CatName;
         delete item.Remaining;    
         return item;
      });

      $("#ForServer").val(mapDataForServer);

      // if not debug return true and remove alert.
      alert(mapDataForServer);
      return false;
   }

   // data from the server
   // var dataFromServer = <%= new JavaScriptSerializer().Serialize(Model) %>; 

   // Hard code for now
   var dataFromServer = [
   { "CatId": 1000, "CatName": "Car wax", "Q1Amt": 50, "Q2Amt": 60, "Q3Amt": 90, "Q4Amt": 80, "BudgetAmt": 280 },
   { "CatId": 2000, "CatName": "Car Wippers", "Q1Amt": 20, "Q2Amt": 40, "Q3Amt": 60, "Q4Amt": 80, "BudgetAmt": 200 },
   { "CatId": 3333, "CatName": "Oil Change", "Q1Amt": 30, "Q2Amt": 70, "Q3Amt": 90, "Q4Amt": 10, "BudgetAmt": 200 },
   { "CatId": 4040, "CatName": "Gas", "Q1Amt": 0, "Q2Amt": 0, "Q3Amt": 0, "Q4Amt": 0, "BudgetAmt": 3000 }
   ];

   // constructor for each row of categories  ( adds obserbale )
   function oneCat(CatId, CatName, Q1Amt, Q2Amt, Q3Amt, Q4Amt, BudgetAmt) {
      this.CatId = CatId;
      this.CatName = CatName;
      this.Q1Amt = ko.observable(Q1Amt);
      this.Q2Amt = ko.observable(Q2Amt);
      this.Q3Amt = ko.observable(Q3Amt);
      this.Q4Amt = ko.observable(Q4Amt);
      this.BudgetAmt = ko.observable(BudgetAmt);
      this.Remaining = ko.dependentObservable(function () {
         var total = this.BudgetAmt();
         total = total - this.Q1Amt();
         total = total - this.Q2Amt();
         total = total - this.Q3Amt();
         total = total - this.Q4Amt();
         return total;
      }, this);
   }

   var mappedFromServer = ko.utils.arrayMap(dataFromServer, function (item) {
       return new oneCat(item.CatId, item.CatName, item.Q1Amt, item.Q2Amt, item.Q3Amt, item.Q4Amt, item.BudgetAmt);
   });

   // Here's my data model 
   var viewModel = {
       catagoryDetails: ko.observableArray([])
   };

   // add total of remaining
   viewModel.totalRemaining = ko.dependentObservable(function () {
      var total = 0;
      ko.utils.arrayForEach(this.catagoryDetails(), function (item) {
          var value = parseInt(item.Remaining, 10);
          if (!isNaN(value)) {
              total += value;
          }
      });
      return total;
   }, viewModel);

   viewModel.catagoryDetails(mappedFromServer);

   // turn on Knockout with the model viewModel    
   ko.applyBindings(viewModel);
Était-ce utile?

La solution

Jetez un oeil à celui-ci: http://jsfiddle.net/rniemeyer/qmXWE/

La question principale est à quel point vous accédez à vos observables. Si vous ne passez l'observable à un data-bind, puis pour vous déballe. Toutefois, si vous passez une expression, vous devez accéder à l'observable en fonction (comme dans votre JavaScript réelle).

Ainsi, les changements que vous avez à faire sont:

data-bind="css: { RowError: Remaining() != 0 }"

data-bind="enable: totalRemaining() == 0"

et dans votre totalRemaining dependentObservable, vous avez besoin d'accès restant comme:

var value = parseInt(item.Remaining(), 10);

Enfin, pour votre question JSON, je pense qu'une bonne façon de le manipuler est d'ajouter une méthode de toJSON à votre type de oneCat. Là, vous pouvez supprimer les propriétés que vous ne voulez pas. Il ressemblerait à quelque chose comme:

oneCat.prototype.toJSON = function() {
    var copy = ko.toJS(this);  //easy way to get a copy
    delete copy.CatName;
    delete copy.Remaining;
    return copy;
}

Ensuite, vous pouvez simplement utiliser ko.toJSON sur votre objet et lorsque vous appelez JSON.stringify il utilisera votre fonction toJSON chaque fois qu'il voit un oneCat.

Hope this helps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top