Frage

Nachdem sie das beobachtet haben Knockout.js Video mit Steve Sanderson Ich entschied, dass dies für komplizierte UI -Seiten großartig wäre.

Ich habe durchgearbeitet Die Live -Beispiele und durchlesen die Dokumentation. Ich fand dann Ryan Niemeyers großer Artikel. Also wollte ich ein ähnliches Beispiel wie Ryan bauen.

Es würde eine Tabelle anzeigen. Jede Zeile der Tabelle hätte ein Budget.
Der Benutzer kann Werte für jedes Quartal eingeben.
Das Budget abzüglich der Summe der Quartale würde den verbleibenden Betrag geben.
Wenn der verbleibende Betrag nicht null wäre, hätte die Zeile eine Klasse darauf angewendet. Die Klasse würde die Hintergrundfarbe rot machen.
Wenn irgendwelche Zeilen eine Verleihung von etwa nicht gleich Null hätten, wäre die Save -Taste deaktiviert.

Was ich gearbeitet habe, war die erste Anzeige der Daten.

Was nicht funktioniert, ist:

  • Alle Zeilen werden sogar eine mit Null gelesen.
  • Wenn sich die Quarterwerte ändern, ändert sich der verbleibende Wert nicht.
  • Die Schaltfläche Speichern ist niemals aktiviert.
  • JSON für Save ist nicht korrekt.

Der Code kann in gefunden werden Diese Geige sowie unten.

Erstens einige CSS, damit die Dinge richtig aussehen:

   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;  
    }  

Dann die Ansicht:

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

Und das 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);
War es hilfreich?

Lösung

Schauen Sie sich diesen an: http://jsfiddle.net/rniemeyer/qmxwe/

Das Hauptproblem ist, wie Sie auf Ihre Observablen zugreifen. Wenn Sie nur die Beobachtbaren an a übergeben data-bind, dann packt es es für dich aus. Wenn Sie jedoch einen Ausdruck übergeben, müssen Sie als Funktion auf die Beobachtbare zugreifen (wie in Ihrem tatsächlichen JavaScript).

Die Änderungen, die Sie vornehmen müssten, sind also:

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

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

Und in Ihrem TotalRemaining -abhängigen Diensten müssen Sie auf verbleibende Zugriffe zugreifen wie:

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

Für Ihr JSON -Problem denke ich schließlich, dass eine gute Möglichkeit, dies zu behandeln oneCat Typ. Dort können Sie die Eigenschaften löschen, die Sie nicht wollen. Es würde ungefähr aussehen wie:

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

Dann können Sie nur Ko.tojson in Ihrem Objekt verwenden und beim Aufrufen von JSON.Stringify werden Ihre TOJSON -Funktion verwendet, wenn sie a oneCat.

Hoffe das hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top