{"id":1238,"date":"2013-08-17T20:35:39","date_gmt":"2013-08-18T00:35:39","guid":{"rendered":"http:\/\/yuguangzhang.com\/blog\/?p=1238"},"modified":"2015-11-19T13:48:20","modified_gmt":"2015-11-19T18:48:20","slug":"knockout-observable-subscription","status":"publish","type":"post","link":"http:\/\/yuguangzhang.com\/blog\/knockout-observable-subscription\/","title":{"rendered":"Show tips on startup in 4 lines of code"},"content":{"rendered":"<p><a href=\"http:\/\/fiddlesalad.com\/coffeescript\/\">Fiddle Salad<\/a>\u00a0has accumulated many features, but where are they? In keeping with one of its principles, features are hidden until the situation calls for them. One example is the JavaScript errors that are shown on hover over the results window. Recently, I&#8217;ve decided showing an unobtrusive tips window is as good as hiding features to reduce UI clutter. So, let&#8217;s start with 4 lines of Knockout code.<\/p>\n<p>[cc lang=&#8221;coffeescript&#8221;]<br \/>\nTipsPanel = -><br \/>\n  @startup = ko.observable(not store.get(&#8216;hideTipsOnStartup&#8217;))<br \/>\n  @startup.subscribe((checked) -><br \/>\n    store.set(&#8216;hideTipsOnStartup&#8217;, not checked)<br \/>\n  )<br \/>\n[\/cc]<\/p>\n<p>I start by setting <em>startup<\/em> to a storage value using <a href=\"https:\/\/github.com\/marcuswestin\/store.js\/\">store.js<\/a>. It uses HTML5 local storage with cookies for fallback. Since I want to show the tips panel by default and hideTipsOnStartup would not be set, <em>startup<\/em> is set to the opposite hideTipsOnStartup. JavaScript&#8217;s <strong>!<\/strong> and CoffeeScript&#8217;s <strong>not<\/strong> casts an expression to a boolean, as required by <a href=\"http:\/\/knockoutjs.com\/documentation\/checked-binding.html\">Knockout&#8217;s checked binding<\/a>.<br \/>\nNext, I add a <a href=\"http:\/\/www.knockmeout.net\/2011\/03\/reacting-to-changes-in-knockoutjs.html\">manual subscription<\/a> to the observable so that its value is stored each time the checkbox is checked or unchecked.<br \/>\nFinally, the checkbox is bound to <em>tips.startup<\/em> where <em>tips<\/em> is a <em>TipsPanel<\/em> instance.<br \/>\n[cc lang=&#8221;html&#8221;]<br \/>\n<label><input data-bind=\"checked: $root.tips.startup\" type=\"checkbox\"\/> Show tips on startup<\/label><br \/>\n[\/cc]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fiddle Salad\u00a0has accumulated many features, but where are they? In keeping with one of its principles, features are hidden until the situation calls for them. One example is the JavaScript errors that are shown on hover over the results window. Recently, I&#8217;ve decided showing an unobtrusive tips window is as good as hiding features to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[203,23],"tags":[133,157],"class_list":["post-1238","post","type-post","status-publish","format-standard","hentry","category-fiddle-salad","category-programming","tag-javascript","tag-knockout"],"aioseo_notices":[],"_links":{"self":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts\/1238","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/comments?post=1238"}],"version-history":[{"count":2,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts\/1238\/revisions"}],"predecessor-version":[{"id":1449,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/posts\/1238\/revisions\/1449"}],"wp:attachment":[{"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/media?parent=1238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/categories?post=1238"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/yuguangzhang.com\/blog\/wp-json\/wp\/v2\/tags?post=1238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}