Pregunta

Después de ver el Video knockout.js con Steve Sanderson Decidí que esto sería genial para páginas de interfaz de usuario complicadas.

Trabajé a través de los ejemplos en vivo y leer la documentación. Entonces encontré El gran artículo de Ryan Niemeyer. Así que quería construir un ejemplo similar al de Ryan.

Mostraría una tabla. Cada fila de la tabla tendría un presupuesto.
El usuario puede ingresar valores para cada trimestre.
El presupuesto menos la suma de los cuartos daría el monto restante.
Si la cantidad restante no fuera cero, la fila se le aplicaría una clase. La clase convertiría el color de fondo en rojo.
Si alguna fila tuviera un restante casi igual a cero, el botón Guardar se deshabilitaría.

Lo que obtuve trabajando fue la visualización inicial de los datos.

Lo que no funciona es:

  • Todas las filas se leen incluso una con cero restante.
  • Cuando los valores del cuarto cambian el valor restante no cambia.
  • El botón Guardar nunca está habilitado.
  • JSON para salvar no es correcto.

El código se puede encontrar en este violín así como abajo.

Primero, algunas CSS para hacer que las cosas se vean bien:

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

Entonces la vista:

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

Y el 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);
¿Fue útil?

Solución

Echa un vistazo a este: http://jsfiddle.net/rniemeyer/qmxwe/

El problema principal es cómo accede a sus observables. Si solo está pasando el observable a un data-bind, luego te lo desenvuelve. Sin embargo, si está pasando una expresión, entonces debe acceder a lo observable como una función (como en su JavaScript real).

Entonces, los cambios que tendrías que hacer son:

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

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

Y en su Totalremeing DependentObservable, debe acceder a permanecer como:

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

Finalmente, para su problema de JSON, creo que una buena manera de manejarlo es agregar un método de Tojson a su oneCat escribe. Allí puede eliminar las propiedades que no desea. Se vería algo así como:

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

Luego, puede usar ko.tojson en su objeto y cuando llame a json.stringify usará su función tojson cada vez que vea un oneCat.

Espero que esto ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top