Reputation: 61
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:
The logic is pretty straight forward but I'm lost on where this logic should go to follow best knockout practices.
Upvotes: 0
Views: 105
Reputation: 4304
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>
Upvotes: 1