{"id":411,"date":"2012-01-02T21:30:00","date_gmt":"2012-01-03T04:30:00","guid":{"rendered":"http:\/\/blog.monnet-usa.com\/?p=411"},"modified":"2012-01-02T18:07:32","modified_gmt":"2012-01-03T01:07:32","slug":"creating-rich-interactive-web-apps-with-knockout-js-part-4","status":"publish","type":"post","link":"https:\/\/blog.monnet-usa.com\/?p=411","title":{"rendered":"Creating Rich Interactive Web Apps With KnockOut.js &#8211; Part 4"},"content":{"rendered":"<h3>Intro <a id='part4-intro'><\/a><\/h3>\n<p>In <a href='https:\/\/blog.monnet-usa.com\/?p=404'>part 3<\/a> we built a complete working version of the <a href=\"http:\/\/savings-goal-simulator.heroku.com\/\">Savings Goal Simulator<\/a> where each view model and view mediator is nicely separated in its own module and corresponding source file. But what about the view? Well the goal of part 4 is to <b>modularize<\/b> and <b>extract each view<\/b> component.<\/p>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-intro1.png\" alt=\"Breaking up [views] is not hard to do ...!\" title=\"Breaking up [views] is not hard to do ...!\" \/><\/p>\n<h3>Synopsis Of The Approach <a id='part4-approach'><\/a><\/h3>\n<p>The approach will need to meet the following requirements:<\/p>\n<ol>\n<li>The view markup needs to have its own <a href=\"#part4-view-url\"><strong>url<\/strong><\/a> and be cacheable<\/li>\n<li>The view markup needs an <a href=\"#part4-view-id\"><strong>ID<\/strong><\/a><\/li>\n<li>The view should have an HTML <a href=\"#part4-view-element\"><strong>element<\/strong><\/a> <\/li>\n<li>The view HTML element should be <a href=\"#part4-view-renderable\"><strong>renderable<\/strong><\/a><\/li>\n<\/ol>\n<h5>View Markup With A URL <a id='part4-view-url'><\/a><\/h5>\n<p>Just like script blocks and images can be &#8220;sourced&#8221; externally from any url, we need a similar mechanism for our views.<\/p>\n<pre class=\"brush: javascript\">    &lt;view src=\"http:\/\/my.view.html\"&gt;\r\n    &lt;\/view&gt;\r\n<\/pre>\n<p>So since the <strong>script<\/strong> tag allow us to do that already, let&#8217;s use it, assign an id, but let&#8217;s use a more appropriate <strong>type<\/strong> like <strong>text\/html<\/strong>. <\/p>\n<pre class=\"brush: javascript\">    &lt;script src=\"http:\/\/my.view.html\" \r\n            type=\"text\/html\"&gt;\r\n    &lt;\/script&gt;\r\n<\/pre>\n<h5>View Markup With An ID <a id='part4-view-id'><\/a><\/h5>\n<p>To make it possible to reference the &#8220;script-view-markup&#8221; later on in our page or Javascript code, we&#8217;ll just assign the script an ID like so:<\/p>\n<pre class=\"brush: javascript\">    &lt;script id=\"my-view-markup\"\r\n            src=\"http:\/\/my.view.html\" \r\n            type=\"text\/html\"&gt;\r\n    &lt;\/script&gt;\r\n<\/pre>\n<h5>View HTML Element <a id='part4-view-element'><\/a><\/h5>\n<p>Now that we have a way to define how a view markup can be &#8220;included&#8221; in our page, we&#8217;ll just define our view &#8220;container&#8221; as a normal HTML element. We can use a &#8220;<strong>div<\/strong>&#8221; or any of the more semantically significant HTML5 elements like &#8220;<strong>section<\/strong>&#8220;:<\/p>\n<pre class=\"brush: javascript\">    &lt;div id=\"my-view\"&gt;\r\n    &lt;\/div&gt;\r\n<\/pre>\n<p>What we&#8217;re missing is a mechanism to:<\/p>\n<ul>\n<li><strong>associate<\/strong> the view element and the view markup together<\/li>\n<li><strong>render<\/strong> the actual view<\/li>\n<li>optionally: <strong>data-bind<\/strong> any view model to the view<\/li>\n<\/ul>\n<h5>Renderable View <a id='part4-view-renderable'><\/a><\/h5>\n<p>To render the markup for a given view we need a <strong>view rendering engine<\/strong>. As of this writing, the most prevalent option is <a href=\"#jqtpl\">jQuery Template<\/a>. <\/p>\n<p><em><u>Note:<\/u> The <a href=\"#jqtpl\">jQuery Template<\/a> implementation is rock solid and in use in many production web sites and internal applications. However the <a href=\"#jqui\">jQuery UI<\/a> core team is in the process of deprecating its use and eventually replace it with another implementation. A serious contender for this is the <a href=\"#jsrv\">jsRender + jsViews<\/a> library. Other options also include <a href=\"#musta\">Mustache<\/a> and <a href=\"#hdbars\">Handlebars<\/a>. Although this tutorial is leveraging jQuery Template as its platform, I recommend you perform some additional due diligence once you&#8217;re ready to settle on library.<\/em><\/p>\n<p><a href=\"#ko\">KnockoutJS<\/a> goes one step further by integrating the view rendering engine with data-binding capabilities.<\/p>\n<p><em><u>Note:<\/u> <a href=\"#ko\">KnockoutJS<\/a> will allow pluggable view rendering engines over time, making it possible to use the one you choose (as long a as a plugin exists).<\/em><\/p>\n<p>So <a href=\"#ko\">KnockoutJS<\/a> can take a <strong>view element<\/strong> with a corresponding &#8220;<strong>view template<\/strong>&#8221;  and a <strong>view model<\/strong>, and render the resulting <strong>view<\/strong>.<\/p>\n<p>Since we introduced the notion of &#8220;<strong>view template<\/strong>&#8220;, let&#8217;s spend some time getting familiar with the concept before proceeding with externalized views.<\/p>\n<h3>Introduction To Templating <a id='part4-tpl-intro'><\/a><\/h3>\n<h5>Simple String-Based Templates <a id='part4-string-tpl'><\/a><\/h5>\n<p>An string-based template is just a string containing text plus <strong>placeholders<\/strong> for variables. A <strong>placeholder<\/strong> is the name of the <strong>variable<\/strong> surrounded by <strong>curly braces<\/strong> and a prefixed by a <strong>dollar sign<\/strong>. So for example a template to display a <strong>time<\/strong> variable would look like:<\/p>\n<pre class=\"brush: javascript\">    var viewTemplate = \"${firstName}, the time is now ${time}\"\r\n<\/pre>\n<p>We can group our &#8220;variables&#8221; in a Javascript object literal like so:<\/p>\n<pre class=\"brush: javascript\">    var viewData = { firstName: 'Chris',\r\n                     time:  (new Date()).toLocaleTimeString()\r\n                    }\r\n<\/pre>\n<p>We can get the engine to bind the template and the data like so:<\/p>\n<pre class=\"brush: javascript\">    var viewContent = $.tmpl(viewTemplate, viewData);\r\n<\/pre>\n<p>Finally assuming a div with the id &#8216;my-view&#8217;, jQuery can render the view content like so:<\/p>\n<pre class=\"brush: javascript\">    $('#my-view').html(viewContent);\r\n<\/pre>\n<p>In summary here is a diagram showing the relationships between the various components used in templating:<br \/>\n<br \/><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-intro2.png\" alt=\"Template Engine Schematic\" title=\"Template Engine Schematic\" \/><\/p>\n<p>To try this out yourself:<\/p>\n<ol>\n<li>Create a web page named index.html<\/li>\n<li>Add script references to both jQuery and jQuery Template using their content distribution network urls:\n<ul>\n<li>http:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.7.0\/jquery.min.js<\/li>\n<li>http:\/\/ajax.aspnetcdn.com\/ajax\/jquery.templates\/beta1\/jquery.tmpl.min.js<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Add a div with the id &#8216;my-view&#8217; in the body of the page<\/p>\n<pre class=\"brush: javascript\">&lt;div id='my-view'&gt;&lt;\/div&gt;\r\n<\/pre>\n<\/li>\n<li>\n<p>Add a Javascript script block with a jQuery ready function with our template rendering code:<\/p>\n<pre class=\"brush: javascript\">&lt;script type=\"text\/javascript\" &gt;\r\n    $(document).ready(function () {\r\n        var viewTemplate = \"${firstName}, the time is now ${time}\";\r\n        var viewData = { firstName: 'Chris',\r\n                         time:  (new Date()).toLocaleTimeString()\r\n        }\r\n        var viewContent = $.tmpl(viewTemplate, viewData);\r\n        $(\"#my-view\").html(viewData);\r\n    }\r\n&lt;\/script&gt;\r\n<\/pre>\n<\/li>\n<\/ol>\n<p>You should be able to open the <strong>index.html<\/strong> web page in a browser and the div should now contain the rendered text with the first name and the current time.<\/p>\n<p>Now we have an idea of how templating using jQuery Template is working. But in this example we are just using a string to hold our template. The library actually has a feature where you can store the template in a script tag on the same page.<\/p>\n<h5>Simple Inline Templates <a id='part4-inline-tpls'><\/a><\/h5>\n<p>The jQuery Template library also allow us to store the template in a script tag with a text\/html type like so:<\/p>\n<pre class=\"brush: javascript\">&lt;script id='my-view-template' type='text\/html'&gt;\r\n    ${firstName}, the time is now ${time}\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>The template can then be rendered with a slightly different form of the <strong>tmpl<\/strong> API:<\/p>\n<pre class=\"brush: javascript\">var viewContent = $('#my-view-template').tmpl(viewData);\r\n<\/pre>\n<p>Having the template moved out of the code is a step in the right direction, but what we need is the ability to externalize the template to an external url. We&#8217;ll tackle that subject soon I promise, but in the meantime let&#8217;s look at what <a href=\"#ko\">KnockoutJS<\/a> brings us in terms of additional templating power.<\/p>\n<h5>KnockoutJS Databinding Support For Inline Templates <a id='part4-knockoutjs-tpl-databindng'><\/a><\/h5>\n<p>Up to now, we have had to write the actual code to: a) <strong>render<\/strong> the template, and then b) <strong>insert<\/strong> the resulting text in an HTML element. Well, let&#8217;s see what <a href=\"#ko\">KnockoutJS<\/a> can do to simplify our task. (This will be very handy especially when your main page has many views.)<\/p>\n<p>As you know, <a href=\"#ko\">KnockoutJS<\/a> provides a &#8220;<strong>data-bind<\/strong>&#8221; attribute where you can specify the visual or behavioral <strong>aspects<\/strong> <em>(e.g. value, text, visible, enable, &#8230;)<\/em> to <u>link<\/u> to a <strong>value model<\/strong> or <strong>dependent observable function<\/strong>. When we want to data-bind an HTML element to both a template and a view model, we&#8217;ll use the following syntax:<\/p>\n<pre class=\"brush: javascript\">&lt;div id='my-view'\r\n     data-bind='template: { name: \"my-view\",\r\n                            data: myViewModel }'&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p><a id='introToAfterRender'><\/a>It is even possible to specify a Javascript function in an <a href=\"#koafterrender\"><strong>afterRender<\/strong><\/a> template parameter. That function will the be invoked <strong>once the HTML element has been rendered<\/strong>. This can be useful if you need to <strong>dynamically attach<\/strong> new behaviors or event handlers to the produced content. For example, you could invoke jQuery UI component configuration APIs such as applying icons for a jQuery UI button.  <\/p>\n<pre class=\"brush: javascript\">&lt;div id='my-view'\r\n     data-bind='template: { name: \"my-view\",\r\n                            data: myViewModel,\r\n                            afterRender: myViewHookup }'&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>Our view model would then be re-written as follows: <\/p>\n<pre class=\"brush: javascript\">var myViewModel = { firstName: ko.observable('Chris'),\r\n                    time: ko.observable((new Date()).toLocaleTimeString())\r\n}\r\n<\/pre>\n<p>And our &#8220;myViewHookup&#8221; <a href=\"#koafterrender\"><strong>after-render<\/strong><\/a> function would have the following form:<\/p>\n<pre class=\"brush: javascript\">function myViewHookup(renderedElements, viewModel) {\r\n    \/\/ E.g. highlight the new content for 3 seconds\r\n    renderedElements.effect('highlight', \r\n                            { color: 'LightGreen' }, \r\n                            3000); \r\n}\r\n<\/pre>\n<p>And finally our page initialization code would ask <a href=\"#ko\">KnockoutJS<\/a> to apply the data bindings using the  ko.applyBindings API:<\/p>\n<pre class=\"brush: javascript\">$(document).ready(function () {\r\n    var myViewModel = { firstName: ko.observable('Chris'),\r\n                        time: ko.observable((new Date()).toLocaleTimeString())\r\n    }\r\n\r\n    ko.applyBindings(viewModel);        \r\n});                 \r\n<\/pre>\n<p>So when using jQuery, <a href=\"#jqtpl\">jQuery Template<\/a>, and <a href=\"#ko\">KnockoutJS<\/a>, we can define a template-based view and data-bind it to a view model so it can be rendered dynamically.<\/p>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-intro3.png\" alt=\"Knockout Templating\" title=\"Knockout Templating\" \/><\/p>\n<p>Now we have covered all but one requirement: the ability to externalize the view template to a specific url.<\/p>\n<h3>Externalized View Templates<\/h3>\n<h5>Basic Mechanism Needed To Externalize A Template<\/h5>\n<p>Let&#8217;s review our simple &#8220;template script markup&#8221;:<\/p>\n<pre class=\"brush: javascript\">&lt;script id='my-view-template' type='text\/html'&gt;\r\n    ${firstName}, the time is now ${time}\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>What we really need at this point is a way to <strong>externalize<\/strong> this template into its own file (maybe in a sub-folder named after the parent page, itself organized under a &#8220;<strong>view<\/strong>&#8221; folder):<\/p>\n<table>\n<tr>\n<th>\/view\/mypage\/my.view.html<\/th>\n<\/tr>\n<tr>\n<td style='padding:4px;border:1px solid #aaa'>${firstName}, the time is now ${time}<\/td>\n<\/tr>\n<\/table>\n<p>We would then just add a <strong>src<\/strong> tag to our <strong>script<\/strong> block:<\/p>\n<pre class=\"brush: javascript\">&lt;script id='my-view-template' \r\n        type='text\/html'\r\n        src='\/view\/mypage\/_my.view.html' &gt;\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>If you try this out you will notice that the browser will indeed [wget] &#8220;<strong>fetch<\/strong>&#8221; the content of <strong>_my.view.html<\/strong>, and using the web developer tool of your browser you will actually see the template markup. <\/p>\n<p>But if you try to access the content of the script element using jQuery using:<\/p>\n<pre class=\"brush: javascript\">$(\"#my-view-template\").text()\r\n<\/pre>\n<p>&#8230; you will notice that the content is <strong><em>empty<\/em><\/strong>! The browser engine has retrieved the content but <u>did not store<\/u> it in the actual DOM element for the script. This is due to the fact that a script of type text\/html is not recognized as being a script to interpret.<\/p>\n<p>So we need a mechanism to fetch and store the source. The approach consists of re-fetching the source using jQuery&#8217;s <a href=\"#jqget\"><strong>$.get<\/strong><\/a> API. Since it was fetched once, the content is stored in the browser&#8217;s cache so retrieval wil be very fast. We then store it in the DOM&#8217;s element.<br \/>\nHere is a simplistic example of what the code would look like:<\/p>\n<pre class=\"brush: javascript\">$(document).ready(function () {\r\n    $.get(\"\/view\/mypage\/_my.view.html\", \r\n                function(data, textStatus, jqXHR) {     \r\n                    $(\"#my-view-template\")\r\n                        .text(jqXHR.responseText);\r\n                }\r\n    );\r\n});                 \r\n<\/pre>\n<p>So finally we can integrate our <a href=\"#ko\">KnockoutJS<\/a> view model code in the ready function:<\/p>\n<pre class=\"brush: javascript\">$(document).ready(function () {\r\n    $.get(\"\/view\/mypage\/_my.view.html\", \r\n                function(data, textStatus, jqXHR) {\r\n                    $(\"#my-view-template\")\r\n                        .text(jqXHR.responseText);\r\n\r\n                    var myViewModel = { firstName: ko.observable('Chris'),\r\n                                        time: ko.observable((new Date()).toLocaleTimeString())\r\n                    }\r\n\r\n                    ko.applyBindings(viewModel);        \r\n                }\r\n    );\r\n}); \r\n<\/pre>\n<p>You now have <strong>externalized<\/strong> the view template, <strong>dynamically loaded<\/strong> it, <strong>data-bound<\/strong> it to a view model using <a href=\"#ko\">KnockoutJS<\/a>, and <strong>rendered<\/strong> using the <a href=\"#jqtpl\">jQuery Template<\/a> engine!<\/p>\n<p>Our example was fairly basic but it illustrates the overall concept and approach. <\/p>\n<h5>Generic ViewLoader Plugin<\/h5>\n<p>The <a href=\"#viewldr\">jQuery ViewLoader<\/a> plugin will take us even further by providing the ability to:<\/p>\n<ol>\n<li>Handle <strong>nested<\/strong> externalized templates<\/li>\n<li><strong>Parallelize<\/strong> the processing of each template<\/li>\n<li>Provide a simple way to handle all templates on a page and <strong>synchronize their post-processing<\/strong> so that the page initialization logic can proceed.<\/li>\n<\/ol>\n<p>Here is what the minimum syntax looks like:<\/p>\n<pre class=\"brush: javascript\">$(document).viewloader({\r\n    logLevel: \"debug\",\r\n    success: function () {\r\n        ko.applyBindings(viewModel);\r\n    }\r\n});\r\n<\/pre>\n<p>The plugin will identify all scripts of <strong>type text\/html<\/strong> and a source url ending in &#8220;<strong>.view.html<\/strong>&#8220;, including <strong>nested<\/strong> template scripts and request their <strong>parallel loading<\/strong>. Once <strong>all<\/strong> template scripts have been succesfully <strong>processed<\/strong> the <strong>success<\/strong> function is invoked.<\/p>\n<p>Behind the scenes, <a href=\"#viewldr\">jQuery ViewLoader<\/a> relies on the jQuery concept of <a href=\"#jqdfd\">&#8220;<strong>Deferred<\/strong>&#8220;<\/a>, an action which can be <strong>launched for &#8220;deferred&#8221; (i.e. later) execution<\/strong>, but can <strong>trigger a callback when completed<\/strong>. Actions can be grouped together so that a specific callback can be triggered once all of them have completed.<\/p>\n<p>Here is a diagram of the approach:<br \/>\n<br \/><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-intro4.png\" alt=\"Dynamically Loaded External Templates\" title=\"Dynamically Loaded External Templates\" \/><\/p>\n<h3>Externalizing The Views Of Our Savings Goal Simulator<\/h3>\n<h5>Intro<\/h5>\n<p>We can now apply the new approach to our <a href=\"#sgs-site\">Savings Goal Simulator<\/a> web app since it currently contains 3 views:<\/p>\n<ol>\n<li>savings-goal-view<\/li>\n<li>consumption-scenarios-view<\/li>\n<li>savings-forecast-view<\/li>\n<\/ol>\n<p>For each view, we will: <\/p>\n<ol>\n<li>Create an <strong>externalized template<\/strong> in the <strong>\/view\/index<\/strong> folder based on the view markup<\/li>\n<li>Replace the <strong>view<\/strong> in index.html by a <strong>template script<\/strong> reference and a <strong>container DIV<\/strong> data-bound to the template.<\/li>\n<\/ol>\n<p>Finally, we&#8217;ll update the main <strong>application.js<\/strong> to plugin the <a href=\"#viewldr\">jQuery ViewLoader<\/a>.<\/p>\n<p>Here is an outline of the step-by-step approach:<\/p>\n<table class=\"details_table\">\n<tr>\n<th>#<\/th>\n<th>To Do<\/th>\n<th>Area<\/th>\n<\/tr>\n<tr>\n<td><a href=\"#todo-part4-1\">1<\/a><\/td>\n<td>Create An External Template For The savings-goal-view<\/td>\n<td>View<\/td>\n<\/tr>\n<tr>\n<td><a href=\"#todo-part4-2\">2<\/a><\/td>\n<td>Refactor the savings-goal-view In Our Web Page<\/td>\n<td>View<\/td>\n<\/tr>\n<tr>\n<td><a href=\"#todo-part4-3\">3<\/a><\/td>\n<td>Hookup jQuery ViewLoader In Our Main application.js<\/td>\n<td>Application<\/td>\n<\/tr>\n<tr>\n<td><a href=\"#todo-part4-4\">4<\/a><\/td>\n<td>Refactor The Savings Goal Mediator<\/td>\n<td>View Mediator<\/td>\n<\/tr>\n<\/table>\n<p><a id='todo-part4-1'><\/a><\/p>\n<h5>1. Create An External Template For The savings-goal-view<\/h5>\n<p>Our first step will be to create a new folder named <strong>view<\/strong> under <strong>scripts<\/strong> to organize our external views. Similarly to frameworks like Ruby On Rails, or ASP.NET MVC, we&#8217;ll create a subfolder named <strong>shared<\/strong>, for all views reusable across pages, then we&#8217;ll create a subfolder named <strong>index<\/strong> for views appearing on our <strong>index.html<\/strong> web page.<\/p>\n<p>In the <strong>scripts\/view\/index<\/strong> folder, let&#8217;s create a file named <strong>_savings-goal.view.html<\/strong>. I used an <strong>underscore prefix<\/strong> to reflect the Rails convention of &#8220;<strong>partial views<\/strong>&#8221; being prefixed that way.<\/p>\n<p>Then we can copy the <strong>savings-goal-view markup<\/strong> from <strong>index.html<\/strong> page and paste it in our new <strong>_savings-goal.view.html<\/strong> file.<\/p>\n<pre class=\"brush: javascript\">&lt;section id='savings-goal-view' &gt;\r\n    &lt;label for=\"savings-goal-amount\"&gt;Savings Goal Amount:&lt;\/label&gt;\r\n    &lt;input id=\"savings-goal-amount\"  \/&gt;&lt;br\/&gt;\r\n\r\n    &lt;label for=\"savings-max-duration\"&gt;Savings Max Duration (In Months):&lt;\/label&gt;\r\n    &lt;input id=\"savings-max-duration\" maxlength=\"3\" \/&gt;&lt;br\/&gt;\r\n\r\n    &lt;label for=\"savings-target-per-month\"&gt;Savings Target Per Month:&lt;\/label&gt;\r\n    &lt;span id=\"savings-target-per-month\"  \/&gt;&lt;br\/&gt;\r\n&lt;\/section&gt;  \r\n<\/pre>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-todo1.png\" alt=\"Externalizing savings-goal-view\" title=\"Externalizing savings-goal-view\" \/><\/p>\n<p>Now we can refactor index.html.<\/p>\n<p><a id='todo-part4-2'><\/a><\/p>\n<h5>2. Refactor the savings-goal-view In Our Web Page<\/h5>\n<p>In place of our <strong>savings-goal-view<\/strong> markup, let&#8217;s first add a script reference to the view we just created, and give it an id of savings-goal-view<strong>-template<\/strong>:<\/p>\n<pre class=\"brush: javascript\">&lt;script id='savings-goal-view-template'\r\n        type='text\/html'\r\n        src='scripts\/view\/index\/_savings-goal.view.html' &gt;\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>Second, let&#8217;s add a <strong>div<\/strong> acting as a <strong>container<\/strong> for our external view. We&#8217;ll give it an id of savings-goal-view<strong>-container<\/strong>, and declare our KnockoutJS data-binding with the <strong>savings-goal-view-template<\/strong>:<\/p>\n<pre class=\"brush: javascript\">&lt;div id='savings-goal-view-container'\r\n     data-bind='template: { name: \"savings-goal-view-template\" } ' &gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>Let&#8217;s download:<\/p>\n<ol>\n<li>the latest version of jQuery Templates from https:\/\/github.com\/jquery\/jquery-tmpl<\/li>\n<li>the latest version of KnockoutJS from https:\/\/github.com\/SteveSanderson\/knockout<\/li>\n<li>the <a href=\"#viewldr\">jQuery ViewLoader<\/a> plugin and place it in the <strong>\/scripts\/vendor<\/strong> folder.<\/li>\n<\/ol>\n<p>In the index.html page, in the LAB loader section, let&#8217;s:<\/p>\n<ol>\n<li>Replace the call to load jQuery Template from our downloaded version (instead of the version from the CDN which is older)<\/li>\n<li>Replace the call to load KnockoutJS from our downloaded version<\/li>\n<li>\n<p>Add a call to load the <a href=\"#viewldr\">jQuery ViewLoader<\/a> plugin:<\/p>\n<pre class=\"brush: javascript\">\r\n&lt;script type=\"text\/javascript\"&gt;\r\n$LAB\r\n    .script(\"http:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.6.4\/jquery.min.js\").wait()\r\n    \/\/ ...\r\n    .script(\"scripts\/vendor\/jquery.tmpl.min.js\").wait()\r\n    .script(\"scripts\/vendor\/knockout-latest.debug.js\").wait()\r\n    \/\/ ...\r\n    .script(\"scripts\/vendor\/jquery.viewloader.js\").wait()\r\n    \/\/ ...\r\n&lt;\/script&gt; \r\n<\/pre>\n<\/li>\n<\/ol>\n<p>Here is how all the piece parts will fit together:<\/p>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-todo2.png\" alt=\"Dynamic loading of the savings-goal-view\" title=\"Dynamic loading of the savings-goal-view\" \/><\/p>\n<p>Ok, now it&#8217;s time to plug in code to get the ViewLoader to load our view.<\/p>\n<p><a id='todo-part4-3'><\/a><\/p>\n<h5>3. Hookup jQuery ViewLoader In Our Main application.js<\/h5>\n<p>First let&#8217;s create 2 new utility functions in application.js:<\/p>\n<ol>\n<li>GetPageSettings &#8211; to retrieve our page settings from the DOM<\/li>\n<li>\n<p>SetPageSettings &#8211; to store our page settings in the DOM<\/p>\n<pre class=\"brush: javascript\">function GetPageSettings() {\r\n    return $(document).data(\"sgs.pagesettings\");\r\n}\r\n\r\n\r\nfunction SetPageSettings(pageSettings) {\r\n    $(document).data(\"sgs.pagesettings\", pageSettings);\r\n}\r\n<\/pre>\n<\/li>\n<\/ol>\n<p>Let&#8217;s review the <strong>InitializeApplication<\/strong> function of our main <strong>application.js<\/strong> module. The core code consists of initializing a pageSettings dictionary and invoking our view mediators.<\/p>\n<p>Let&#8217;s extract that part of the code into a new function named <strong>InitializeViewMediators<\/strong>:<\/p>\n<pre class=\"brush: javascript\">function InitializeViewMediators() {\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) \r\n        console.info(\"InitializeViewMediators starting ...\");\r\n\r\n    \/\/ Initialize our page-wide settings\r\n    var pageSettings = { defaultSavingsGoal: 500,\r\n                         defaultSavingsMaxDuration: 6\r\n    }\r\n\r\n    \/\/ Save the page-wide settings\r\n    SetPageSettings(pageSettings);\r\n\r\n    \/\/ Create \/ launch our view mediator(s)\r\n    sgs.mediator.savingsgoal.createViewMediator(pageSettings);\r\n    sgs.mediator.coffeepricing.createViewMediator(pageSettings);\r\n    sgs.mediator.consumptionscenarios.createViewMediator(pageSettings);\r\n    sgs.mediator.savingsforecast.createViewMediator(pageSettings);\r\n\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) \r\n        console.info(\"InitializeViewMediators done ...\");   \r\n}\r\n<\/pre>\n<p>Let&#8217;s add the code to <strong>InitializeApplication<\/strong> to <strong>attach<\/strong> our ViewLoader plugin to the <strong>document<\/strong> object and invoke <strong>InitializeViewMediators<\/strong> upon success (i.e. once all views have been loaded):<\/p>\n<pre class=\"brush: javascript\">function InitializeApplication() {\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) \r\n        console.info(\"InitializeApplication starting ...\");\r\n\r\n    $(document).viewloader({\r\n        logLevel: \"debug\",\r\n        success: function (successfulResolution) {\r\n            InitializeViewMediators();\r\n        }\r\n    );\r\n\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) \r\n        console.info(\"InitializeApplication done ...\"); \r\n}\r\n<\/pre>\n<p>And let&#8217;s add some <strong>logging<\/strong> code in the <strong>error function<\/strong> to know when the ViewLoader is failing to load a given view.<\/p>\n<pre class=\"brush: javascript\">function InitializeApplication() {\r\n    \/\/ ...\r\n\r\n    $(document).viewloader({\r\n        \/\/ ...\r\n        success: function (successfulResolution) {\r\n            InitializeViewMediators();\r\n        },          \r\n        error: function (failedResolution) {\r\n            if (typeof(console) != 'undefined' &amp;&amp; console) {\r\n                console.error(\"index.html page failed to load\");    \r\n            }\r\n        }\r\n    });\r\n\r\n    \/\/ ...\r\n}\r\n<\/pre>\n<p>Here is the visual depiction of how application.js coordinates with the ViewLoader:<\/p>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-todo3.png\" alt=\"Hooking up jQuery ViewLoader with application.js\" title=\"Hooking up jQuery ViewLoader with application.js\" \/><\/p>\n<p>Not so fast &#8230; if we run the app, we&#8217;ll get an <em>error<\/em>. This is due to the fact that the code from the <strong>createViewMediator<\/strong> function of our <strong>sgs.mediator.savingsgoal<\/strong> module is <em>expecting the view to be available<\/em>. But at this point in the execution the view as <em>not yet been rendered<\/em>. This leads us to one more refactoring.<\/p>\n<p><a id='todo-part4-4'><\/a><\/p>\n<h5>4. Refactor The Savings Goal Mediator<\/h5>\n<p>The current implementation of the <strong>createViewMediator<\/strong> function of our <strong>sgs.mediator.savingsgoal<\/strong> module assumes that our view is in the DOM, but at the moment the ViewLoader plugin kicked off the <strong>InitializeViewMediators<\/strong> function, KnockoutJS <em>has not been requested to apply bindings yet<\/em> nor <em>render any view templates<\/em>. <\/p>\n<p>So let&#8217;s refactor the code related to setting up the various data-bindings and invoking KnockoutJS into a new function named <strong>setupViewDataBindings<\/strong>:<\/p>\n<pre class=\"brush: javascript\">sgs.mediator.savingsgoal.setupViewDataBindings = function() {\r\n    \/\/ Declare the HTML element-level data bindings\r\n    $(\"#savings-goal-amount\").attr(\"data-bind\",\"value: savingsGoalAmount\");\r\n    $(\"#savings-max-duration\").attr(\"data-bind\",\"value: savingsMaxDuration\");\r\n    $(\"#savings-target-per-month\").attr(\"data-bind\",\"text: savingsTargetPerMonthFormatted()\");\r\n\r\n    \/\/ Ask KnockoutJS to data-bind the view model to the view\r\n    var viewNode = $('#savings-goal-view')[0];\r\n    var viewModel = sgs.mediator.savingsgoal.getViewModel();            \r\n    ko.applyBindings(viewModel, viewNode);\r\n\r\n    \/\/ Apply masking to the savings goal amount and max duration input fields \r\n    viewModel.savingsGoalAmountMask.attach($(\"#savings-goal-amount\")[0]);\r\n    viewModel.savingsMaxDurationMask.attach($(\"#savings-max-duration\")[0]); \r\n\r\n    \/\/ Initialize default for value models linked to masked fields \r\n    var pageSettings = GetPageSettings();\r\n    viewModel.savingsGoalAmount(pageSettings.defaultSavingsGoal || 0);\r\n    viewModel.savingsMaxDuration(pageSettings.defaultSavingsMaxDuration || 0);\r\n\r\n    \/\/ Subscribe to interesting value model changes\r\n    viewModel.savingsTargetPerMonthFormatted.subscribe(function() {\r\n        $(\"#savings-target-per-month\")\r\n            .effect('highlight', { color: 'LightGreen' }, 3000); \/\/ for 3 seconds\r\n    });\r\n\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) \r\n        console.info(\"sgs.mediator.setupViewDataBindings done!\");\r\n}\r\n<\/pre>\n<p>Note: We had to add a new line to <em>access<\/em> the <strong>viewModel<\/strong> since it is now available in the DOM and accessible using the sgs.mediator.savingsgoal.<strong>getViewModel<\/strong> function. We also add to add a line to get the <strong>pageSettings<\/strong> using our new <strong>GetPageSettings<\/strong> function.<\/p>\n<p>After having extracted some of the code the <strong>createViewMediator<\/strong> function consist of the following:<\/p>\n<pre class=\"brush: javascript\">sgs.mediator.savingsgoal.createViewMediator = function (pageSettings, pageViewModel) {\r\n    \/\/ Create the view Savings Goal view-specific view model\r\n    var viewModel = sgs.model.savingsgoal.initializeViewModel(pageSettings);\r\n\r\n    \/\/ Save the view model\r\n    sgs.mediator.savingsgoal.setViewModel(viewModel);   \r\n\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) console.info(\"sgs.mediator.savingsgoal ready!\");\r\n}\r\n<\/pre>\n<p>But since we added the <strong>savings-goal-view-container<\/strong> <strong>div<\/strong> to the page, we need to handle its <strong>data binding<\/strong> here. So let&#8217;s do that:<\/p>\n<pre class=\"brush: javascript\">sgs.mediator.savingsgoal.createViewMediator = function (pageSettings, pageViewModel) {\r\n    \/\/ Create the view Savings Goal view-specific view model\r\n    var viewModel = sgs.model.savingsgoal.initializeViewModel(pageSettings);\r\n\r\n    \/\/ Save the view model\r\n    sgs.mediator.savingsgoal.setViewModel(viewModel);   \r\n\r\n    \/\/ Ask KnockoutJS to data-bind the view model to the view\r\n    var viewNode = $('#savings-goal-view-container')[0];\r\n    ko.applyBindings(viewModel, viewNode);\r\n\r\n    if (typeof(console) != 'undefined' &amp;&amp; console) console.info (\"sgs.mediator.savingsgoal ready!\");\r\n}\r\n<\/pre>\n<p>You probably noticed that there is <strong><em>no call<\/em><\/strong> yet to invoke our new <strong>setupViewDataBindings<\/strong> function! So where will it be invoked then? Well do you remember the comment about KnockoutJS exposing an <strong>afterRender<\/strong> callback function? (See back in <a href=\"#introToAfterRender\" title=\"Intro to afterRender\">KnockoutJS Databinding Support For Inline Templates<\/a>.)<\/p>\n<p>We&#8217;ll update the data-binding of <strong>savings-goal-view-container<\/strong> in our <strong>index.html<\/strong>, by assigning our new <strong>sgs.mediator.savingsgoal.setupViewDataBindings<\/strong> function to the <strong>afterRender<\/strong> attribute:<\/p>\n<pre class=\"brush: javascript\">&lt;div id='savings-goal-view-container'\r\n     data-bind='template: { name: \"savings-goal-view-template\", \r\n                            afterRender: sgs.mediator.savingsgoal.setupViewDataBindings } ' &gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>And now if we re-run our application, we&#8217;ll see in the console that <strong>setupViewDataBindings<\/strong>  is being called while the <strong>savings-goal-view<\/strong> is being rendered, after the loading is successfully completed. <\/p>\n<p>Here is an excerpt of the console:<\/p>\n<pre class=\"brush: javascript\">InitializeApplication starting ...\r\nviewloader.loadSourceForPartialView loading source for view: id=savings-goal-view-template src=scripts\/view\/index\/_savings-goal.view.html\r\nInitializeApplication done ...\r\nviewloader.loadSourceForPartialView saving source in savings-goal-view-template\r\nviewloader.loadAllPartialViews executing 'success' function\r\nInitializeViewMediators starting ...\r\nsgs.mediator.setupViewDataBindings done!\r\nsgs.mediator.savingsgoal ready!\r\n...\r\nInitializeViewMediators done ...\r\n<\/pre>\n<p>We have successfully externalized the markup for the savings-goal-view!!!<\/p>\n<p>In summary here is a diagram illustrating the page load processing flow:<\/p>\n<p><img decoding=\"async\" src=\".\/wp-content\/media\/knockoutjs\/savings-goal-simulator-part4-todo4.png\" alt=\"Page Load Processing Flow Recap\" title=\"Page Load Processing Flow Recap\" \/><\/p>\n<p><a id='todo-part4-5'><\/a><\/p>\n<h5>5. Recap<\/h5>\n<p>Here is a quick recap of the steps we followed:<\/p>\n<table class=\"details_table\" style=\"border:1px solid #DDD;border-collapse:collapse;background-color:#FFF;\">\n<tr>\n<th style=\"border:1px solid #DDD;background-color:#DDD;\">#<\/th>\n<th style=\"border:1px solid #DDD;background-color:#DDD;text-align:left;\">To Do<\/th>\n<th style=\"border:1px solid #DDD;background-color:#DDD;text-align:left;\">Area<\/th>\n<\/tr>\n<tr>\n<td style=\"border:1px solid #DDD;vertical-align:top;\"><a href=\"#todo-part4-1\">1<\/a><\/td>\n<td style=\"border:1px solid #DDD\">Create An External Template For The savings-goal-view<\/p>\n<ul>\n<li>Create a _your.view.html file<\/li>\n<li>Cut the view markup from your .html and paste it in the .view.html<\/li>\n<\/ul>\n<\/td>\n<td style=\"border:1px solid #DDD;vertical-align:top;\">View<\/td>\n<\/tr>\n<tr>\n<td style=\"border:1px solid #DDD;vertical-align:top;\"><a href=\"#todo-part4-2\">2<\/a><\/td>\n<td style=\"border:1px solid #DDD\">Refactor the savings-goal-view In Our Web Page<\/p>\n<ul>\n<li>Add a script tag with an id, a text\/html type and point the source to the new .view.html<\/li>\n<li>Create a DIV container and add a data-bind with the template name (id)<\/li>\n<\/ul>\n<\/td>\n<td style=\"border:1px solid #DDD;vertical-align:top;\">View<\/td>\n<\/tr>\n<tr>\n<td style=\"border:1px solid #DDD;vertical-align:top;\"><a href=\"#todo-part4-3\">3<\/a><\/td>\n<td style=\"border:1px solid #DDD\">Hookup jQuery ViewLoader In Our Main application.js<\/p>\n<ul>\n<li>Split the view mediators initialization code into a separate InitializeViewMeditors function<\/li>\n<li>Add $(document).viewloader({ \/\/ &#8230; }) to InitializeApplication<\/li>\n<li>Call InitializeViewMeditors from the success callback of viewloader<\/li>\n<\/ul>\n<\/td>\n<td style=\"border:1px solid #DDD;vertical-align:top;\">Application<\/td>\n<\/tr>\n<tr>\n<td style=\"border:1px solid #DDD;vertical-align:top;\"><a href=\"#todo-part4-4\">4<\/a><\/td>\n<td style=\"border:1px solid #DDD\">Refactor The Savings Goal Mediator<\/p>\n<ul>\n<li>Create a new setupViewDataBindings function to create and apply data bindings inside the view<\/li>\n<li>Trim down createViewMediators to focus only on initializing and storing the view model and asking KnockoutJS to apply the bindings to the view container.<\/li>\n<li>Add an afterRender parameter to the template data-binding to instruct the template engine to invoke the setupViewDataBindings<\/li>\n<\/ul>\n<\/td>\n<td style=\"border:1px solid #DDD;vertical-align:top;\">View Mediator<\/td>\n<\/tr>\n<\/table>\n<p><a id='todo-part4-6'><\/a><\/p>\n<h5>6. Externalizing The Remaining Views<\/h5>\n<p>Now we just need to repeat the process on our remaining two views:<\/p>\n<ul>\n<li>consumption-scenarios-view<\/li>\n<li>savings-forecast-view<\/li>\n<\/ul>\n<p>If you want to follow along with the source code changes, just get code for the <strong>tag<\/strong> corresponding to any particular step on the <a href=\"https:\/\/github.com\/techarch\/savings-goal-simulator\/tags\">GitHub repository<\/a> for the Savings Goal Simulator.<\/p>\n<h3>So What? <a id='part4-sowhat'><\/a><\/h3>\n<p><a href=\"#jqtpl\">jQuery Template<\/a> and <a href=\"#jqvl\">jQuery ViewLoader<\/a> allow you to structure and load views within a web page.<\/p>\n<p>Externalizing your views makes your web pages more <strong>modular<\/strong> and <strong>easier to maintain<\/strong>, especially if you are working within a team as this allows you to assign different views (markup + code) to different individuals.<\/p>\n<p>In the context of a &#8220;single page application&#8221; where you may have many views, these benefits are crucial to help you manage the <strong>complexity<\/strong> and allow you to <strong>grow<\/strong> the application <strong>organically<\/strong> \/ incrementally.<\/p>\n<p>Another benefit of modularizing your views and view mediators will be that it will be easier to adapt and create different versions of the application for other channels, like a mobile web site or a mobile version of the application (using for example jQuery Mobile and PhoneGap).<\/p>\n<h3>References And Resources<\/h3>\n<h5>jQuery Plugins<\/h5>\n<ul>\n<li><a id='jqtpl'><\/a> <a href=\"http:\/\/api.jquery.com\/category\/plugins\/templates\/\" title=\"jQuery Template\">jQuery Template<\/a> : http:\/\/api.jquery.com\/category\/plugins\/templates\/<\/li>\n<li><a id='jqvl'><\/a> <a href=\"http:\/\/github.com\/techarch\/jquery-viewloader\" title=\"jQuery ViewLoader\">jQuery ViewLoader<\/a> : http:\/\/github.com\/techarch\/jquery-viewloader<\/li>\n<li><a id='jsrv'><\/a> <a href=\"https:\/\/github.com\/BorisMoore\/jsviews\">jsRender + jsViews<\/a> rendering engine : https:\/\/github.com\/BorisMoore\/jsviews<\/li>\n<li><a id='musta'><\/a> <a href=\"http:\/\/mustache.github.com\/\">Mustache<\/a> rendering engine : http:\/\/mustache.github.com\/<\/li>\n<li><a id='hdbars'><\/a> <a href=\"http:\/\/www.handlebarsjs.com\/\">Handlebars<\/a> rendering engine : http:\/\/www.handlebarsjs.com\/<\/li>\n<li><a id='viewldr'><\/a> <a href=\"https:\/\/github.com\/techarch\/jquery-viewloader\">jQuery ViewLoader<\/a> rendering engine : https:\/\/github.com\/techarch\/jquery-viewloader<\/li>\n<\/ul>\n<h5>Miscellaneous<\/h5>\n<ul>\n<li><a id='jqget'><\/a> <a href=\"http:\/\/api.jquery.com\/jQuery.get\/\" title=\"jQuery $.get\">jQuery $.get<\/a> : http:\/\/api.jquery.com\/jQuery.get\/<\/li>\n<li><a id='jqdfd'><\/a> <a href=\"http:\/\/api.jquery.com\/category\/deferred-object\/\" title=\"jQuery Deferred\">jQuery Deferred<\/a> : http:\/\/api.jquery.com\/category\/deferred-object\/<\/li>\n<li><a id='koafterrender'><\/a> <a href=\"http:\/\/knockoutjs.com\/documentation\/template-binding.html#note_4_using_the__option\" title=\"KnockoutJS afterRender\">KnockoutJS afterRender<\/a> : http:\/\/knockoutjs.com\/documentation\/template-binding.html#note<em>4<\/em>using<em>the<\/em>_option<\/li>\n<li><a id='sgs-site'><\/a> <a href=\"http:\/\/savings-goal-simulator.heroku.com\/\" title=\"Savings Goal Simulator\">Savings Goal Simulator<\/a> : http:\/\/savings-goal-simulator.heroku.com\/<\/li>\n<\/ul>\n<h5>My Other Related Posts:<\/h5>\n<ul name=\"myotherrelatedposts\">\n<li><a name='ko-part1' href='https:\/\/blog.monnet-usa.com\/?p=354'>Creating Rich Interactive Web Apps With KnockOut.js &#8211; Part 1<\/a><\/li>\n<li><a name='ko-part2' href='https:\/\/blog.monnet-usa.com\/?p=368'>Creating Rich Interactive Web Apps With KnockOut.js &#8211; Part 2<\/a><\/li>\n<li><a name='ko-part3' href='https:\/\/blog.monnet-usa.com\/?p=404'>Creating Rich Interactive Web Apps With KnockOut.js &#8211; Part 3<\/a><\/li>\n<\/ul>\n<p><a name='kodemosrc'><\/a><\/p>\n<h5>Full Source Of The Savings Goal Simulator (KnockoutJS Demo)<\/h5>\n<p>The whole application is available on Github under <a href='https:\/\/github.com\/techarch\/savings-goal-simulator' target='_blank'>techarch \/ savings-goal-simulator<\/a>.<\/p>\n<div class=\"blog-msm-ad\">\n<div class=\"blog-msm-ad1\">\n\t\tIf you enjoyed this post, I would love it if you could check out <a href=\"http:\/\/bit.ly\/myskillsmap\">mySkillsMap<\/a>, my skills management app.\n\t<\/div>\n<div class=\"blog-msm-ad2\">\n\t\t\t<a href=\"http:\/\/www.myskillsmap.com\/take-charge-of-your-skills-development\"><br \/>\n\t\t\t\t<img src='.\/wp-content\/media\/msm\/start-your-free-trial-now.png'  \/><br \/>\n\t\t\t<\/a>\n\t<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Intro In part 3 we built a complete working version of the Savings Goal Simulator where each view model and view mediator is nicely separated in its own module and corresponding source file. But what about the view? Well the goal of part 4 is to modularize and extract each view component. Synopsis Of The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15,59,30,48,46],"tags":[],"class_list":["post-411","post","type-post","status-publish","format-standard","hentry","category-ajax","category-javascript","category-jquery","category-knockoutjs","category-rich-web-apps"],"_links":{"self":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/411","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=411"}],"version-history":[{"count":7,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/411\/revisions"}],"predecessor-version":[{"id":419,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=\/wp\/v2\/posts\/411\/revisions\/419"}],"wp:attachment":[{"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.monnet-usa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}