简体   繁体   中英

Knockout.js Observable Array Operations

I am somewhat new to knockout.js and I'm having trouble wrapping my head around where to put certain operations on observable arrays. Here is what my code looks like:

var Building = function() {
    var self = this;
    self.nLocation = ko.observable();
    self.nBuilding = ko.observable();
    ...
    self.increaseLocNum = function() {
        self.nLocation(self.nLocation + 1);
    };
}
var Quote = function() {
    var self = this;
    var nQuoteID = ko.observable();
    ...
    self.buildings = ko.observableArray([]);
    self.addBuilding = function(){
        ...
        // Build new building with next loc/building number
        buildings.push();
    }
    ...
}
ko.applyBindings(new Quote());

So essentially I have a quote that can have multiple buildings on it. Each building is bound to a different tab on a tab control. On these tabs is a 'Location' field that has +/- buttons that increase/decrease the location number.

I need to use 'enable' binding to set the enable of the +/- buttons (for example, if a building is the only building at the highest location number. Here are a few examples of simple rules:

  • Location number can't be decreased if the building is at location 1
  • Location number can't be increased if the building is the only building on the highest location
  • Location number can't be increased if there is only one building

The logic is pretty straight forward but I'm lost on where this logic should go to follow best knockout practices.

The decrease function is easy because the individual building view-model doesn't need to know about any external factors to make the decision; it can be a straightforward computed based on its location observable. The increase function is trickier because it depends on the states of all the other buildings in the collection.

Here's one option that avoids the child class having to know about the parent class. Place a canIncrease observable on each building, but have the parent view-model handle the actual increasing/decreasing so that it can loop through all children and update their observables whenever a location is changed.

 var Building = function(location) { var self = this; self.nLocation = ko.observable(location); self.nBuilding = ko.observable("-Building Name Here-"); self.canIncrease = ko.observable(); //set by parent self.canDecrease = ko.computed(function(){ //Location number can't be decreased if the building is at location 1 return self.nLocation() > 1; }); } var Quote = function() { var self = this; var nQuoteID = ko.observable(); self.buildings = ko.observableArray([new Building(1)]); self.addBuilding = function() { // Build new building with next loc/building number self.buildings.push(new Building(self.highestLocation() + 1)); self.enableChildren(); } self.highestLocation = ko.computed(function(){ var highest=0; $.each(self.buildings(), function(key,value){ if(value.nLocation() > highest) highest = value.nLocation(); }); return highest; }); self.increaseLocNum = function(building) { building.nLocation(building.nLocation() + 1); self.enableChildren(); }; self.decreaseLocNum = function(building) { building.nLocation(building.nLocation() - 1); self.enableChildren(); }; self.enableChildren = function(){ //Location number can't be increased if the building is the only building on the highest location //Location number can't be increased if there is only one building $.each(self.buildings(), function(key, building){ if(building.nLocation() === self.highestLocation() || self.buildings().length === 1){ building.canIncrease(false); }else{ building.canIncrease(true); } }); } } ko.applyBindings(new Quote()); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <input type="button" data-bind="click: addBuilding" value="Add Building" /> <span style="margin-left: 8px;">Total Buildings: <label data-bind="text: buildings().length" /></span> <span style="margin-left: 8px;">Highest Location: <label data-bind="text: highestLocation" /></span> <br/> <table> <thead> <tr> <th></th> <th>Location</th> <th>Building Name</th> </tr> </thead> <tbody data-bind="foreach: buildings"> <tr style="border: 1px solid blue;"> <td> <input type="button" data-bind="enable: canDecrease, click: $parent.decreaseLocNum" value="-" /> <input type="button" data-bind="enable: canIncrease, click: $parent.increaseLocNum" value="+" /> </td> <td> <span data-bind="text: nLocation"></span> </td> <td> <span data-bind="text: nBuilding"></span> </td> </tr> </tbody> </table> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM