<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Tuan Doan</title><link href="http://world.optimizely.com" /><updated>2018-10-30T09:27:05.0000000Z</updated><id>https://world.optimizely.com/blogs/Tuan-Doan/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>What news in the JavaScript API for the Episerver Perform 2.1.0 (Episerver Commerce 12.9.1)</title><link href="https://world.optimizely.com/blogs/Tuan-Doan/Dates/2018/10/what-news-in-the-javascript-api-for-the-episerver-perform/" /><id>&lt;p&gt;As you all know, the release of Episerver.Commerce 12.9.1 was included a major change in JavaScript API for Episerver Perform version 2.1.0 (&lt;a href=&quot;/link/76974ad8d2a84c1b989ad0ac453ab663.aspx?versionFilter=12.9.1&amp;amp;packageFilter=EPiServer.Commerce&quot;&gt;link to release notes&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;In this post, I will show you what are changes and how to update the existed code.&lt;/p&gt;
&lt;h3&gt;Don&#39;t need TrackingMode app setting&lt;/h3&gt;
&lt;p&gt;In Episerver.Commerce 12.9.1, there is no longer exist TrackingMode in the appsetting. Since now, we can use both server to server API and javascript API in parallel.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To use&amp;nbsp;server to server API, we need to add CommerceTracking attribute to the action of controller. Or call to tracking method in the IRecommendationService.&lt;/p&gt;
&lt;p&gt;With javascript API, we are no longer had to call tracking from the server side. Just load epiRecommendation javascript class, create a tracking data object then send it to the server via proxy endpoint.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;// In Layout.cshtml
&amp;lt;head&amp;gt;
    @Html.LoadTrackingAPI()
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    @Html.Partial(&quot;_RecommendationsTemplates&quot;)
    @RenderSection(&quot;Tracking&quot;, false)
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;// In home page index
@section Tracking{
    &amp;lt;script&amp;gt;
        $(document).ready(function () {
            var homeTrackingData = TrackingDataFactory.createHomeTrackingData();
            epiRecommendations.track(homeTrackingData, null, Recommendations.render, {
                sectionMappings: [{
                    area: &quot;homeWidget&quot;, selector: &quot;.recommendations-right&quot;, numberOfItemsToRender: 6
                }]
            })
        });
    &amp;lt;/script&amp;gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Collecting data from the client&lt;/h3&gt;
&lt;p&gt;As before, to use JavaScript tracking API, we need to set TrackingMode is &lt;strong&gt;ClientMode&lt;/strong&gt; and call to Tracking Service in the controller. The purpose is that to collect the tracking data and set it to http context. Then it returns that data to the client later.&lt;/p&gt;
&lt;p&gt;But now, there are no need to edit the controller. It means no need to build web application. Just create the tracking data directly from the View by using &lt;strong&gt;TrackingDataFactory&lt;/strong&gt; javascript class.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    $(document).ready(function () {
       var refCode = &#39;@Model.Product.Code&#39;;
       var productName = &#39;@Model.Product.Name&#39;;
       var productTrackingData = TrackingDataFactory.createProductTrackingData(refCode, productName);
    }
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With product tracking type, it supports the recommendation id for click tracking.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;var recommendationId = parseInt(isNaN(&#39;@Request.QueryString[&quot;recommendationId&quot;]&#39;) ? &#39;0&#39; : &#39;@Request.QueryString[&quot;recommendationId&quot;]&#39;);
if (recommendationId &amp;gt; 0) {
    productTrackingData[&quot;recommendationId&quot;] = recommendationId;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also setting to exclude recommendations, just tracking only.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;productTrackingData[&quot;SkipRecommendations&quot;] = true;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tracking data can be set the custom attributes, it supported types like datetime, double, long, decimal, int, bool and string.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;productTrackingData[&quot;customAttributes&quot;] = { &#39;marketId&#39;: Market.getSelectedMarketId() };&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Not calling directly to Personalization Service&#39;s end point from the client&lt;/h3&gt;
&lt;p&gt;Recently, the flows of JS tracking API works like this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Waiting the server side collecting data and rendering to the client side.&lt;/li&gt;
&lt;li&gt;When the page rendered in client side, the data will send directly to Personalization Service endpoint.&lt;/li&gt;
&lt;li&gt;Waiting response from Personalization Service and render in client with template.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The problem that if the data from server side was cached, then the JS tracking API will send the same data, include the client configuration will be cached.&lt;br /&gt;The second problem is because JS tracking API will send directly to one endpoint. So it means not all of implemented Personalization Service will be used.&lt;/p&gt;
&lt;p&gt;But now, instead of call to the end point of tracking service directly, we call to JS tracking API from the View. It will send a post request to web API with url &#39;&lt;strong&gt;/episerverapi/commercetracking/track&lt;/strong&gt;&#39; and the tracking data collected in the client.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b0e185c7708e4c14b587813e675aaee3.aspx&quot; width=&quot;640&quot; height=&quot;451&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;Handling the response from Personalization Service&lt;/h3&gt;
&lt;p&gt;The web API (proxy) works like server to server API. It handles the request from client and send the tracking data to the &lt;strong&gt;ITrackingService&lt;/strong&gt;. The response from Personalization Service will be de-serialize to the server model whereas it hasn&#39;t data for price or image information. That information from Services is either real-time or latest update, so it may not usable. &lt;br /&gt;Like server to server, we need to &lt;span style=&quot;font-weight: 400;&quot;&gt;intercept &lt;/span&gt;that response data by using &lt;strong&gt;ITrackingResponseDataInterceptor.Intercept(TrackingResponseData)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/503df5794f314ffebcee6a0366d6f863.aspx&quot; width=&quot;640&quot; /&gt;&lt;/p&gt;
&lt;p&gt;One last step, we won&#39;t forget update the recommendation template for the response. As before, it uses mustache template but the property has changes. By default, there are no longer exist functions that filter markets and currencies for display prices. If you have any custom response data, make sure to present it in this template &lt;strong&gt;_RecommendationsTemplates.cshtml&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;&amp;lt;script id=&quot;epiRecommendationListTemplate&quot; type=&quot;x-tmpl-mustache&quot;&amp;gt;
    {{#recs}}&amp;lt;div class=&quot;jsProductTile product-row__tile&quot; data-recommendation-id=&quot;{{id}}&quot;&amp;gt;{{&amp;gt; epiRecommendationItemTemplate}}&amp;lt;/div&amp;gt;{{/recs}}
&amp;lt;/script&amp;gt;
&amp;lt;script id=&quot;epiRecommendationItemTemplate&quot; type=&quot;x-tmpl-mustache&quot;&amp;gt;
    {{#hasDiscount}}&amp;lt;div class=&quot;product has-discount&quot;&amp;gt;{{/hasDiscount}}
    {{^hasDiscount}}&amp;lt;div class=&quot;product&quot;&amp;gt;{{/hasDiscount}}
        &amp;lt;a href=&quot;{{#attributes}}{{url}}{{/attributes}}&amp;amp;recommendationId={{id}}&quot; class=&quot;link--black&quot;&amp;gt;
            &amp;lt;div class=&quot;view-details&quot;&amp;gt;&amp;lt;/div&amp;gt;
            &amp;lt;img src=&quot;{{#attributes}}{{img}}{{/attributes}}&quot; alt=&quot;{{refCode}}&quot; class=&quot;img-responsive&quot; /&amp;gt;
            &amp;lt;h3 class=&quot;product-title&quot;&amp;gt;{{#attributes}}{{title}}{{/attributes}}&amp;lt;/h3&amp;gt;
            &amp;lt;div&amp;gt;
                {{#hasDiscount}}
                &amp;lt;h4 class=&quot;product-price&quot;&amp;gt;{{#attributes}}{{unitPrice}}{{/attributes}}&amp;lt;/h4&amp;gt;
                &amp;lt;h4 class=&quot;product-price product-price--discount&quot;&amp;gt;{{#attributes}}{{salePrice}}{{/attributes}}&amp;lt;/h4&amp;gt;
                {{/hasDiscount}}
                {{^hasDiscount}}
                &amp;lt;h4 class=&quot;product-price&quot;&amp;gt;{{#attributes}}{{salePrice}}{{/attributes}}&amp;lt;/h4&amp;gt;
                {{/hasDiscount}}
            &amp;lt;/div&amp;gt;
        &amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;quick-view-btn-container&quot;&amp;gt;
        &amp;lt;button type=&quot;button&quot; data-toggle=&quot;modal&quot; data-target=&quot;#ModalDialog&quot; 
                data-url=&quot;{{#attributes}}{{url}}{{/attributes}}&amp;amp;recommendationId={{id}}&quot; 
                class=&quot;btn btn-block btn-sm quickview-button&quot;&amp;gt;@Html.Translate(&quot;/Product/Quickview&quot;)&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conclusion, with the new structure of JavaScript tracking API, the tracking in the Commerce site is now much easier to implement and flexible with both server to server API and javascript API with the same result.&lt;/p&gt;</id><updated>2018-10-30T09:27:05.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Filtering on Campaign View</title><link href="https://world.optimizely.com/blogs/Tuan-Doan/Dates/20172/3/filtering-on-campaign-view/" /><id>&lt;p&gt;Commerce release 10.4.0 (available as of 5 March, 2017) introduces a feature that lets you filter the information on the Marketing Campaign List view.&lt;/p&gt;
&lt;p&gt;Prior to this change, the Campaign List showed all campaigns. Under each was a list of its discounts. While this display worked initially, as people began to use the marketing features more extensively, the number of campaigns and discounts quickly grew. So, it became difficult and time consuming to locate a particular item.&lt;/p&gt;
&lt;h2&gt;How it works&lt;/h2&gt;
&lt;p&gt;Now, a set of filters (also known as facets) appears in the left pane. If you select a campaign Status, Discount Type, or Market, it becomes bold, and the view is refreshed, showing only campaigns and discounts that include the selected items.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border: 1px solid black;&quot; alt=&quot;campaign view&quot; src=&quot;/link/597c86e639cb4a789286d7ca844f230a.aspx&quot; height=&quot;432&quot; width=&quot;731&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can choose a single status but multiple&amp;nbsp;discounts or markets.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can choose only one Campaign Status. If you choose a second&amp;nbsp;status, the current one is deselected. &lt;br /&gt;There is always&amp;nbsp;one selected option. By default, &lt;strong&gt;All&lt;/strong&gt; is selected.&lt;/li&gt;
&lt;li&gt;The other filters (Discount Types and Markets) are multiple selection, so&amp;nbsp;you can choose several options by clicking (no need for combination keys).&amp;nbsp;&lt;/li&gt;
&lt;li&gt;To reset the search criteria at any time, click &lt;strong&gt;Clear&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example, you want to see only &lt;strong&gt;Order Type&lt;/strong&gt; discounts in &lt;strong&gt;All&lt;/strong&gt; campaign statuses.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border: 1px solid black;&quot; alt=&quot;&quot; src=&quot;/link/7e0fe85cffb44615a215facf2984c1f6.aspx&quot; height=&quot;389&quot; width=&quot;603&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As another example, you only want to see &lt;strong&gt;Expired&lt;/strong&gt; campaigns.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border: 1px solid black;&quot; alt=&quot;expired campaigns&quot; src=&quot;/link/127eee1d1b0449898da83af16047e64c.aspx&quot; height=&quot;405&quot; width=&quot;592&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;The Market Facet&lt;/h3&gt;
&lt;p&gt;The market facet&amp;nbsp;displays&amp;nbsp;three markets&amp;nbsp;by default. If your site supports&amp;nbsp;more than three, use the&amp;nbsp;&lt;strong&gt;Show More&amp;nbsp;&lt;/strong&gt;button display all market options.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border: 1px solid black;&quot; title=&quot;Show more&quot; alt=&quot;Show more&quot; src=&quot;/link/8fe9460b38284410b83c4cd991afadca.aspx&quot; height=&quot;432&quot; width=&quot;731&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, the &lt;strong&gt;Show More&lt;/strong&gt; button changes to&amp;nbsp;a &lt;strong&gt;Show Less&lt;/strong&gt; button. Use it to minimize the market facet list.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border: 1px solid black;&quot; alt=&quot;show less&quot; src=&quot;/link/d1e7f09546c24781aabbf03bde435be6.aspx&quot; height=&quot;361&quot; width=&quot;207&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We are pleased to provide this functionality,&amp;nbsp;which makes it a whole lot easier to sort through campaigns and discounts.&lt;/p&gt;
&lt;h2&gt;How to customize facets on Campaign View&lt;/h2&gt;
&lt;p&gt;Refer to the document&amp;nbsp;&lt;a href=&quot;/link/90cf7447afe7461b8d03f5fe6b10958b.aspx&quot;&gt;Customizing facets in Campaign view&lt;/a&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;</id><updated>2017-03-10T15:22:23.4870000Z</updated><summary type="html">Blog post</summary></entry></feed>