Reputation: 472
I've written a jsfiddle to demonstrate what I'm trying to accomplish below. Have a requirement when a value is entered in the parent (excursion) pay amount input, the child (charge) pay amounts should be disabled. And vice versa, when a pay amount is entered into either child (charge) pay amount input, the parent disables. I've think I have it working perfectly for the parent - it disables both child inputs - but when entering a value in the second charge input, it doesn't disable the parent. It's also hardcoded, so I'm needing help with this part:
charges()[0].payAmount() != '' || charges()[0].payAmount() != 0
I've seen this - Knockoutjs Update child when parent's observable changes - to add a subscriber, but I don't think I can still access/disable the children from there. Or maybe I can, with jQuery? I've also seen this - Is there any way to disable a bunch of form elements at once? - using a binding handler to potentially handle the disabling of the $parent maybe when entering a value in the children's inputs. Seems complicated though. I noticed that in the ko enable binding documentation that you can pass an abitrary expression, but you can't seem to pass in any parameters, like the current object. And, on the function signature, if I add excursion as an argument, I've verified it's undefined. Here's a function I had tried to attach to the disable binding on the parent, to no avail, as encounter is undefined:
function hasChildEntries(encounter) {
ko.utils.arrayFirst(encounter.charges(), function (charge) {
console.log(charge + ', ' + charge.payAmount() + '...');
if (charge.payAmount() != '' || charge.payAmount() != 0)
return true;
});
return false;
};
view:
<div>
<ul class="payments">
<!-- ko foreach: excursions -->
<li class="payments">
<div class="payments">
<a href='#' class="expand glyphicon glyphicon-minus-sign" style="color:grey"></a>
<a href='#' class="collapse glyphicon glyphicon-plus-sign" style="color:grey"></a>
</div>
<div class="payments" data-bind="text: 'Excursion ID: ' + id + ' Pay Amount: '"></div>
<input class="payments" data-bind="
textInput: payAmount,
valueUpdate: 'afterkeydown',
disable: charges()[0].payAmount() != '' || charges()[0].payAmount() != 0" />
<ul class="payments bullet">
<!-- ko foreach: charges -->
<li class="payments">
<div class="payments" data-bind="text: name + ' Pay Amount: '"></div>
<input class="payments" data-bind="
textInput: payAmount,
valueUpdate: 'afterkeydown',
disable: $parent.payAmount() != '' || $parent.payAmount() != 0" />
</li>
<!-- /ko -->
</ul>
</li>
<!-- /ko -->
</ul>
</div>
view model/javascript:
var viewModel = function () {
var self = this;
self.excursions = ko.observableArray().extend({ rateLimit: 0 });
function Excursion(id, name, chgAmount, payAmount, charges) {
this.id = id;
this.name = name;
this.chgAmount = chgAmount;
this.payAmount = ko.observable('');
this.charges = ko.observableArray(charges).extend({ rateLimit: 0 });
};
function Charge(id, name, date, chgAmount, payAmount) {
this.id = id;
this.name = name;
this.date = date;
this.chgAmount = chgAmount;
this.payAmount = ko.observable('');
};
self.excursions.push(new Excursion('1234', 'Excursion 1', 90.00, 0, undefined));
ko.utils.arrayFirst(self.excursions(), function (excursion) {
if (excursion.id = '1234') {
excursion.charges.push(new Charge(1, 'Trunk Bay', '02/10/2015', 50.00, 0));
excursion.charges.push(new Charge(2, 'Cinnamon Bay', '02/10/2015', 40.00, 0));
}
});
self.excursions.push(new Excursion('1235', 'Excursion 2', 80.00, 0, undefined));
ko.utils.arrayFirst(self.excursions(), function (excursion) {
if (excursion.id == '1235')
excursion.charges.push(new Charge(3, 'Coral Bay', '02/11/2015', 80.00, 0));
});
}
var vm = new viewModel();
ko.applyBindings(vm);
$(".expand").click(function () {
$(this).toggle();
$(this).next().toggle();
$(this).parent().parent().children().last().toggle();
});
$(".collapse").click(function () {
$(this).toggle();
$(this).prev().toggle();
$(this).parent().parent().children().last().toggle();
});
CSS:
.altRow:nth-child(even) td { background-color: #D8D8D8; }
ul.payments { list-style:none; float:left; width:100% }
li.payments { padding-top:10px; float:left; width:100% }
div.payments { float:left }
.expand { width:15px;height:15px; }
.collapse { width:15px;height:15px;display:none }
ul.payments.bullet {list-style-type: disc;}
input.payments { width:80px;height:20px; }
Upvotes: 0
Views: 860
Reputation: 2258
Add a computed to your excursion model:
this.hasCharges = ko.computed(function() {
for(var i = 0, len = charges().length; i < len; i++ ) {
if( charges()[i].payAmount() ) {
return true;
}
}
return false;
});
and then in your markup, replace
disable: charges()[0].payAmount() != '' || charges()[0].payAmount() != 0"
with
disable: hasCharges
This will disable the parent no matter how many children it has
edit: a fiddle for you: http://jsfiddle.net/8j8k7h1c/33/
try to avoid using 'this' in your functions, scoping gets messed up. I used
var self = this;
to keep the charges observable accessible by the computed function.
Upvotes: 1