<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{234:function(t,n,e){"use strict";e.r(n);var o=e(10),component=Object(o.a)({},(function(){this._self._c;return this._m(0)}),[function(){var t=this,n=t._self._c;return n("section",[n("h2",[t._v("Creating Custom Knockout Bindings")]),t._v(" "),n("h3",[t._v("Background")]),t._v(" "),n("p",[t._v("I've been using and enjoying "),n("a",{attrs:{href:"http://knockoutjs.com"}},[t._v("knockout.js")]),t._v(" for\nsome time now.")]),t._v(" "),n("p",[t._v("It's a great library that allows you to use MVVM in web applications\nand keeps you from writing spaghetti code to manipulate the DOM without\nrequiring a switch to a monolithic framework and the associated\ndownsides like lock-in and too many abstractions from plain html.")]),t._v(" "),n("p",[t._v("Using knockoutjs, you are still free to use DOM manipulation yourself if\nand when you need it. The great thing is, it's also easily extendable.")]),t._v(" "),n("h3",[t._v("Extending Knockout")]),t._v(" "),n("p",[t._v("Why is being extendable a big plus and why would you want to extend\nknockout? Is something essential missing from knockout?")]),t._v(" "),n("p",[t._v("Nope, I don't think so.")]),t._v(" "),n("p",[t._v("Instead of growing to a monolithic framework, it just solves a\nparticular problem, namely factoring out the UI glue code into reusable\nbindings. It comes with almost all bindings you could think of by\ndefault, but it doesn't try to be everything for everyone - and thats\nwhere custom bindings come in.")]),t._v(" "),n("p",[t._v("Using custom binding handlers, it offers you the chance to stick to DRY\nand to use declarations instead of repeating javascript snippets over\nand over again.")]),t._v(" "),n("p",[t._v("That often comes in handy, when you need to reuse some javascript code\nin multiple places and the code is tied to an element defined in html.")]),t._v(" "),n("p",[t._v("In the next few paragraphs, I am showing some small, exemplary binding\nhandlers that have proven useful to me, nothing fancy.")]),t._v(" "),n("h3",[t._v("Example BindingHandlers")]),t._v(" "),n("p",[t._v("I've been using some small knockout bindings that uses jquery's\n"),n("a",{attrs:{href:"https://api.jquery.com/fadeIn/"}},[t._v("fadeIn()")]),t._v(" /\n"),n("a",{attrs:{href:"https://api.jquery.com/fadeOut/"}},[t._v("fadeOut()")]),t._v(" methods and\n"),n("a",{attrs:{href:"https://api.jquery.com/slideDown/"}},[t._v("slideDown()")]),t._v(" /\n"),n("a",{attrs:{href:"https://api.jquery.com/fadeIn/"}},[t._v("slideUp()")]),t._v(" to achieve simple animations\non an element.")]),t._v(" "),n("h4",[t._v("FadeVisible")]),t._v(" "),n("p",[t._v("The binding is defined in the following few lines:")]),t._v(" "),n("pre",[n("code",{staticClass:"language-js"},[t._v("ko.bindingHandlers.fadeVisible = {\n  "),n("span",{staticClass:"hljs-attr"},[t._v("init")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    $(element).toggle(ko.unwrap(value));\n  },\n  "),n("span",{staticClass:"hljs-attr"},[t._v("update")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    ko.unwrap(value) ? $(element).fadeIn() : $(element).fadeOut();\n  }\n};\n")])]),t._v(" "),n("h4",[t._v("SlideDownVisible")]),t._v(" "),n("p",[t._v("The definition for the slideDown binding looks almost identical:")]),t._v(" "),n("pre",[n("code",{staticClass:"language-js"},[t._v("ko.bindingHandlers.slideDownVisible = {\n  "),n("span",{staticClass:"hljs-attr"},[t._v("init")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    $(element).toggle(ko.unwrap(value));\n  },\n  "),n("span",{staticClass:"hljs-attr"},[t._v("update")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    ko.unwrap(value) ? $(element).slideDown() : $(element).slideUp();\n  }\n};\n")])]),t._v(" "),n("p",[t._v("In turn, they both are very similar to the example knockout binding in\nknockouts "),n("a",{attrs:{href:"http://knockoutjs.com/documentation/custom-bindings.html"}},[t._v("custom-binding\ndocumentation")]),t._v("\nwhich also provides a binding that uses slideDown() and slideUp().")]),t._v(" "),n("h4",[t._v("Usage")]),t._v(" "),n("p",[t._v("As for usage, you'd replace the default "),n("a",{attrs:{href:"http://knockoutjs.com/documentation/visible-binding.html"}},[t._v("'visible'\nbinding")]),t._v(" with\n'fadeVisible' or 'slideDownVisible' respectively.")]),t._v(" "),n("pre",[n("code",{staticClass:"language-html"},[t._v("    "),n("span",{staticClass:"hljs-tag"},[t._v("&lt;"),n("span",{staticClass:"hljs-name"},[t._v("div")]),t._v(" "),n("span",{staticClass:"hljs-attr"},[t._v("data-bind")]),t._v("="),n("span",{staticClass:"hljs-string"},[t._v('"fadeVisible: isVisible"')]),t._v("&gt;")]),t._v("\n    ...\n")])]),t._v(" "),n("h4",[t._v("Nuget package")]),t._v(" "),n("p",[t._v("I've used the slideDownVisible binding already in a couple of projects\nand I've finally gotten sick of copy/pasting them, so I've packaged\nthem as nuget packages named\n"),n("a",{attrs:{href:"https://www.nuget.org/packages/knockout-fadeVisible/"}},[t._v("'knockout-fadeVisible'")]),t._v("\nand\n"),n("a",{attrs:{href:"https://www.nuget.org/packages/knockout-slideDownVisible/"}},[t._v("'knockout-slideDownVisible'")]),t._v("\nand uploaded them to nuget.org so that I can add it faster the next time\nI might need it. The (very short) source is on\n"),n("a",{attrs:{href:"https://github.com/8/ko-bindings/blob/master/ko-bindings/Scripts/knockout-fadeVisible.js"}},[t._v("github")]),t._v("\nas well.")]),t._v(" "),n("h4",[t._v("Bootstrap Modal")]),t._v(" "),n("p",[t._v("Another example of transforming javascript glue code to a declarative\nknockout binding would be the following modalVisible binding:")]),t._v(" "),n("pre",[n("code",{staticClass:"language-js"},[t._v("ko.bindingHandlers.modalVisible = {\n  "),n("span",{staticClass:"hljs-attr"},[t._v("init")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    "),n("span",{staticClass:"hljs-comment"},[t._v("/* init the modal */")]),t._v("\n    $(element).modal();\n    "),n("span",{staticClass:"hljs-comment"},[t._v("/* subscribe to the 'hidden' event and update the observable, if the modal gets hidden */")]),t._v("\n    $(element).on("),n("span",{staticClass:"hljs-string"},[t._v("'hidden.bs.modal'")]),t._v(", "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("e")]),t._v(") ")]),t._v("{\n      "),n("span",{staticClass:"hljs-keyword"},[t._v("if")]),t._v(" (ko.isObservable(value)) { value("),n("span",{staticClass:"hljs-literal"},[t._v("false")]),t._v("); }\n    });\n  },\n  "),n("span",{staticClass:"hljs-attr"},[t._v("update")]),t._v(": "),n("span",{staticClass:"hljs-function"},[n("span",{staticClass:"hljs-keyword"},[t._v("function")]),t._v(" ("),n("span",{staticClass:"hljs-params"},[t._v("element, valueAccessor")]),t._v(") ")]),t._v("{\n    "),n("span",{staticClass:"hljs-keyword"},[t._v("var")]),t._v(" value = valueAccessor();\n    ko.unwrap(value) ? $(element).modal("),n("span",{staticClass:"hljs-string"},[t._v("'show'")]),t._v(") : $(element).modal("),n("span",{staticClass:"hljs-string"},[t._v("'hide'")]),t._v(");\n  }\n}\n")])]),t._v(" "),n("p",[t._v("It wraps bootstrap javascript code in a tidy, nice to use knockout\nbinding after using the binding like:")]),t._v(" "),n("pre",[n("code",{staticClass:"language-html"},[n("span",{staticClass:"hljs-tag"},[t._v("&lt;"),n("span",{staticClass:"hljs-name"},[t._v("div")]),t._v(" "),n("span",{staticClass:"hljs-attr"},[t._v("class")]),t._v("="),n("span",{staticClass:"hljs-string"},[t._v('"modal fade"')]),t._v(" "),n("span",{staticClass:"hljs-attr"},[t._v("data-bind")]),t._v("="),n("span",{staticClass:"hljs-string"},[t._v('"modalVisible: isVisible"')]),n("span",{staticClass:"hljs-attr"},[t._v("...")]),t._v("\n")])])]),t._v(" "),n("p",[t._v("This takes care of initializing the modal and allows controlling it's\nvisibility using an observable. It handles hiding and showing of the\nmodal and therefore removes the need to manipulate the DOM from my\nViewModels javascript code.")]),t._v(" "),n("h3",[t._v("Conclusion")]),t._v(" "),n("p",[t._v("Knockoutjs is nice and flexible library that is not only easy to get\nstarted with, but also easy to extend.")]),t._v(" "),n("p",[t._v("Creating custom binding handlers may save you from writing repetitive\nand error prone code and allows you to stick view specific code\ndeclaratively right on the target html element, which makes reasoning\nabout your view easier.")]),t._v(" "),n("p",[t._v("Decoupling jQuery and other DOM manipulation code from your normal code\nalso makes that code simpler to test.")]),t._v(" "),n("p",[t._v("Take care,"),n("br"),t._v("\nMartin")]),t._v(" "),n("h3",[t._v("References")]),t._v(" "),n("ul",[n("li",[n("a",{attrs:{href:"http://knockoutjs.com"}},[t._v("Knockout.js (http://knockoutjs.com)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"http://knockoutjs.com/documentation/custom-bindings.html"}},[t._v("Creating a custom binding for Knockout\n(http://knockoutjs.com/documentation/custom-bindings.html)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"http://knockoutjs.com/documentation/visible-binding.html"}},[t._v("Knockout's 'visible' binding\n(http://knockoutjs.com/documentation/visible-binding.html)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://api.jquery.com/slideDown/"}},[t._v("jQuery slideDown()\n(https://api.jquery.com/slideDown/)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://api.jquery.com/slideUp/"}},[t._v("jQuery slideUp()\n(https://api.jquery.com/slideUp/)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://api.jquery.com/fadeIn/"}},[t._v("jQuery fadeIn()\n(https://api.jquery.com/fadeIn/)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://api.jquery.com/fadeOut/"}},[t._v("jQuery fadeOut()\n(https://api.jquery.com/fadeOut/)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://github.com/8/ko-bindings/blob/master/ko-bindings/Scripts/knockout-fadeVisible.js"}},[t._v("fadeVisible binding\n(https://github.com/8/ko-bindings/blob/master/ko-bindings/Scripts/knockout-fadeVisible.js)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"https://github.com/8/ko-bindings/blob/master/ko-bindings/Scripts/knockout-slideDownVisible.js"}},[t._v("slideDownVisible knockout binding\n(https://github.com/8/ko-bindings/blob/master/ko-bindings/Scripts/knockout-slideDownVisible.js)")])]),t._v(" "),n("li",[n("a",{attrs:{href:"http://getbootstrap.com/javascript/#modals"}},[t._v("Bootstrap Modal Javascript\n(http://getbootstrap.com/javascript/#modals)")])])])])}],!1,null,null,null);n.default=component.exports}}]);</pre></body></html>