Knockout + JavaScript + Validation useful custom bindings and functions
Hi,
Just to post some helpful bindings and JavaScript functions that I used multiple times throughout my projects. I have been using this in creating forms using jQuery and Knockout with Ajax web services.
DatePicker
Update: be careful if you need to deal with different timezone as client timezone and server timezone might not be the same. To avoid this issue altogether you can use knockout-jqueryui extension so that the value is written as string. This way we only need to deal with server timezone.
Radio Yes/No buttons
Synchronous ajax call (normally used to populate dropdown values)
Get QueryString
IE9 Filter problem
That's all for now. Hope this helps.
Andreas
Just to post some helpful bindings and JavaScript functions that I used multiple times throughout my projects. I have been using this in creating forms using jQuery and Knockout with Ajax web services.
DatePicker
Update: be careful if you need to deal with different timezone as client timezone and server timezone might not be the same. To avoid this issue altogether you can use knockout-jqueryui extension so that the value is written as string. This way we only need to deal with server timezone.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ko.bindingHandlers.datepicker = { init: function (element, valueAccessor, allBindingsAccessor) { //initialize datepicker with some optional options var options = allBindingsAccessor().datepickerOptions || {}, $el = $(element); $el.datepicker(options); //handle the field changing ko.utils.registerEventHandler(element, "change" , function () { var observable = valueAccessor(); observable($el.datepicker( "getDate" )); }); //handle disposal (if KO removes by the template binding) ko.utils.domNodeDisposal.addDisposeCallback(element, function () { $el.datepicker( "destroy" ); }); }, update: function (element, valueAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()), $el = $(element); //handle date data coming via json from Microsoft if (String(value).indexOf( '/Date(' ) == 0) { value = new Date(parseInt(value.replace(/\/Date\((.*?)\)\ //gi, "$1"))); } var current = $el.datepicker( "getDate" ); if (value - current !== 0) { value = new Date(Date.fromISO(value)); $el.datepicker( "setDate" , value); } } }; /* Date fix for JSON date IE8 */ ( function () { var D = new Date( '2011-06-02T09:34:29+02:00' ); if (!D || +D !== 1307000069000) { Date.fromISO = function (s) { var day, tz, rx = /^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/, p = rx.exec(s) || []; if (p[1]) { day = p[1].split(/\D/); for ( var i = 0, L = day.length; i < L; i++) { day[i] = parseInt(day[i], 10) || 0; }; day[1] -= 1; day = new Date(Date.UTC.apply(Date, day)); if (!day.getDate()) return NaN; if (p[5]) { tz = (parseInt(p[5], 10) * 60); if (p[6]) tz += parseInt(p[6], 10); if (p[4] == '+' ) tz *= -1; if (tz) day.setUTCMinutes(day.getUTCMinutes() + tz); } return day; } return NaN; } } else { Date.fromISO = function (s) { return new Date(s); } } })() function isValidDate(value, format) { var isValid = true ; try { jQuery.datepicker.parseDate(format, value, null ); } catch (error) { isValid = false ; } return isValid; } $.validator.addMethod( "australianDate" , function (value, element) { return isValidDate(value, "dd/mm/yy" ); }, "Invalid date. Please enter a date in the format dd/mm/yyyy." ); jQuery.validator.addClassRules( "DateAU" , { australianDate: true }); |
Radio Yes/No buttons
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | ko.bindingHandlers.radioTrueFalseBoolean = { init: function (element, valueAccessor, allBindingsAccessor) { var updateHandler = function () { var valueToWrite; if ((element.type == "radio" ) && (element.checked)) { if (element.value != null ) { valueToWrite = element.value == "false" ? false : true ; } } else { return ; // "checked" binding only responds to checkboxes and selected radio buttons } var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue); modelValue(valueToWrite); }; ko.utils.registerEventHandler(element, "click" , updateHandler); // IE 6 won't allow radio buttons to be selected unless they have a name if ((element.type == "radio" ) && !element.name) ko.bindingHandlers['uniqueName '][' init '](element, function () { return true }); } , update: function (element, valueAccessor, allBindingsAccessor) { var value = ko.utils.unwrapObservable(valueAccessor()); var newValueAccessor = function () { if (value != null) { return value ? "true" : "false"; } else { return null; } }; ko.bindingHandlers.checked.update(element, newValueAccessor, allBindingsAccessor); } }; jQuery.validator.addMethod("requiredRadioValue", function (value, element) { var selectedValue = $(' input:radio[name= ' + element.name + ' ]:checked').length; return selectedValue > 0; }, "You must select one of the options." ); jQuery.validator.addClassRules( "requiredRadio" , { requiredRadioValue: true }); |
Synchronous ajax call (normally used to populate dropdown values)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function GetSynchronousJSONResponse(url, postData) { var xmlhttp = null ; if (window.XMLHttpRequest) xmlhttp = new XMLHttpRequest(); else if (window.ActiveXObject) { if ( new ActiveXObject( "Microsoft.XMLHTTP" )) xmlhttp = new ActiveXObject( "Microsoft.XMLHTTP" ); else xmlhttp = new ActiveXObject( "Msxml2.XMLHTTP" ); } // to be ensure non-cached version of response url = url + "?rnd=" + Math.random(); xmlhttp.open( "POST" , url, false ); //false means synchronous xmlhttp.setRequestHeader( "Content-Type" , "application/json; charset=utf-8" ); xmlhttp.send(postData); var responseText = xmlhttp.responseText; return responseText; } |
Get QueryString
1 2 3 4 5 6 7 8 9 10 | function getUrlVars() { var vars = [], hash; var hashes = window.location.href.slice(window.location.href.indexOf( '?' ) + 1).split( '&' ); for ( var i = 0; i < hashes.length; i++) { hash = hashes[i].split( '=' ); vars.push(hash[0]); vars[hash[0]] = hash[1]; } return vars; } |
IE9 Filter problem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | if (!Array.prototype.filter) { Array.prototype.filter = function (fun /*, thisp */ ) { "use strict" ; if ( this === void 0 || this === null ) throw new TypeError(); var t = Object( this ); var len = t.length >>> 0; if ( typeof fun !== "function" ) throw new TypeError(); var res = []; var thisp = arguments[1]; for ( var i = 0; i < len; i++) { if (i in t) { var val = t[i]; // in case fun mutates this if (fun.call(thisp, val, i, t)) res.push(val); } } return res; }; } |
That's all for now. Hope this helps.
Andreas
Comments
Post a Comment