Hi all,
I am using jQuery UI's spinner with KnockoutJS and Durandal right now. I followed the answer/example here to create a custom binding that takes care of initializing the spinner and of observing the changes made to the spinner.
Now, I have saved that custom binding as a common module to be loaded in the lib folder, to be invoked by whichever modules that need to use spinners in the future. My problem here is I want to, on this particular page, to retrieve the value of the spinner/<input> to make an ajax call each time the spinner and thus the quantity is updated. I know I can't possibly be putting my custom ajax code in the common module, and that I should be putting it in the relevant viewmodel, but I don't know how to invoke it there.
Here's the view (partial):
<p class="qty">
<input class="spinner" data-bind="spinner: quantity, spinnerOptions: { min: 1, numberFormat: 'n' }" />
<a class="remove" href="#">Remove</a>
</p>
And this is the corresponding viewmodel (partial):
function Item(data) {
(...)
self.updateQuantity = function(){
$.ajax(apiUrl + self.id, {
data: self.quantity,
type: 'patch',
contentType: 'application/json',
success: function(result) {
alert(result);
}
});
};
}
(...)
return {
checkedOutItems: checkedOutItems, //checkedoutItems is the array of Item that's passed to the view, which can call Item's updateQuantity method
(...)
}
Here's the custom binding I've built for the jQuery UI spinner and which I require in my shell.js:
define(function(require) {
var system = require('durandal/system'),
app = require('durandal/app'),
ko = require('knockout');
ko.bindingHandlers.spinner = {
init: function(element, valueAccessor, allBindingsAccessor) {
//initialize datepicker with some optional options
var options = allBindingsAccessor().spinnerOptions || {};
$(element).spinner(options);
//handle the field changing
ko.utils.registerEventHandler(element, 'spinchange', function () {
var observable = valueAccessor();
observable($(element).spinner('value'));
});
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).spinner('destroy');
});
},
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor()),
current = $(element).spinner('value'),
msg = 'You have entered an Invalid Quantity. \n Please enter at least 1 or remove this item if you do not want to include it in the shopping cart.';
system.log(value);//shows the new quantity as changed by the user via spinner
if(isNaN(parseInt(value))) {
alert(msg);
}
if (value !== current && !isNaN(parseInt(value))) {
$(element).spinner("value", value);
}
}
};
});
As far as I know, I should have something like data-bind="value: quantity, click: updateQuantity"
to call the updateQuantity function as soon as the observable quantity changes. However, now that I'm using the spinner
custom binding via the custom binding in the lib folder, I'm no longer sure how to call the updateQuantity
function anymore. Each change caused by the spinner will be captured by the code in the custom binding (as the system.log shows in Chrome inspector), but in my viewmodel, I don't know where and how to call the function that captures
the new quantity to be used in the ajax call.I don't even know the event that's supposed to bind to the method, since everything from click to onFocus doesn't seem to match the event. I am now wondering if I should write custom code for the ajax call for this page only to the custom binding (under update: function), which however means I will have a good chunk of repeated code next time I want to use the spinner.
I realize my understanding of KnockoutJS and Durandal is still fuzzy (just started few weeks ago), so I will be most glad if someone would enlighten me as to where I should go from here. Thank you in advance.
<input class="spinner" data-bind="spinner: quantity, spinnerOptions: { min: 1, numberFormat: 'n' }, callbackFunction:
callbackOnUpdate" />
Then you would be able to pick out the function from the allBindings parameter.
var cb = allBindings.get('
callbackFunction
');
if (cb){
cb(valueUnwrapped);
}