<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by John-Philip Johansson</title><link href="http://world.optimizely.com" /><updated>2020-05-26T14:51:25.0000000Z</updated><id>https://world.optimizely.com/blogs/john-philip-johansson/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Another step for Episerver CMS Labs - User Telemetry in more add-ons</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2020/5/another-step-for-episerver-cms-labs---user-telemetry-in-more-add-ons/" /><id>&lt;p class=&quot;informationBox&quot;&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; When you upgrade BlockEnhancements or install our Labs in the future, you will see a new NuGet dependency called&amp;nbsp;EPiServer.Telemetry.UI. It&#39;s the telemetry code from BlockEnhancements that we extracted and made available to our other experiments.&lt;/p&gt;
&lt;p&gt;Previously,&amp;nbsp;&lt;a href=&quot;/link/f136e054d84149fd810de14ea328234b.aspx&quot;&gt;we blogged about adding User Telemetry&lt;/a&gt; in our first Labs add-on, BlockEnhancements, to learn more about what is used and what isn&#39;t. As noted in the &lt;a href=&quot;/link/487e09260da244f69c5a0ad6fbdaa75d.aspx&quot;&gt;Introducing Episerver CMS Labs&lt;/a&gt;&amp;nbsp;blog post, this will be key for us to uncover what is truly useful for our users when we create various experimental Labs add-ons.&lt;/p&gt;
&lt;p&gt;We &lt;a href=&quot;/link/dc1ef494ed2547f58cef226182d205a4.aspx&quot;&gt;noticed in our initial data set&lt;/a&gt;&amp;nbsp;that there is still a lot to learn about what our users really enjoy with BlockEnhancements, and we&#39;re working on that. In the meantime, we have also released some other really interesting Labs where we explore other parts of the CMS that we would like to change:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx&quot;&gt;EPiServer.Labs.ContentManager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.GridView&quot;&gt;EPiServer.Labs.GridView&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/link/66a8407520064afe9ebcddfe4f6aab9b.aspx&quot;&gt;EPiServer.Labs.ConfigurationManager&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To be able to understand the users of these new Labs add-ons, we had to make the telemetry functionality from BlockEnhancements available to the other Labs add-ons as well. To do this, we extracted the telemetry functionality into its own &lt;a href=&quot;https://github.com/episerver/EPiServer.Telemetry.UI&quot;&gt;open-source&lt;/a&gt; &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Telemetry.UI&quot;&gt;NuGet package&lt;/a&gt;. We will continue to maintain a public list of what we track (on the &lt;a href=&quot;https://github.com/episerver/EPiServer.Telemetry.UI&quot;&gt;EPiServer.Telemetry.UI Github repository&lt;/a&gt;), and we will continue to report our findings through blog posts.&lt;/p&gt;
&lt;p&gt;We are looking at ways on how to make this functionality more useful for other teams across Episerver, and eventually to you, our partners and community. For now, anyone can take a dependency on that package to start tracking but unless they&#39;re part of the CMS UI team, or at least within Episerver, the data won&#39;t be available.&lt;/p&gt;
&lt;p&gt;To help us out, remember to opt in to the telemetry collection if you&#39;re using any of our Labs and are happy with it (or even if you&#39;re not!).&amp;nbsp;&lt;span&gt;We will enable this on DXP environments, but if you&#39;re self hosted, you can enable Telemetry with this configuration:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureContainer(ServiceConfigurationContext context)
{
    context.Services.Configure&amp;lt;TelemetryOptions&amp;gt;(options =&amp;gt; options.OptedIn = true);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything we collect is anonymized and we only collect what we need. One question we&#39;ve had internally is how &quot;responsive&quot; our design needs to be, especially if you&#39;ve had the chance to look at &lt;a href=&quot;/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx&quot;&gt;our cool new Content Manager Labs&lt;/a&gt;&amp;nbsp;that &lt;em&gt;works on a mobile phone&lt;/em&gt;. Cool right? Is it used? How often do editors edit on the phone? Should we invest more in that, or was it one of those ideas that are cooler on paper than in reality? Now we can find out. The Telemetry add-on will be added to ContentManager and that will help us answer those questions. For now, these are the screen sizes we collected from BlockEnhancement:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/19fb919874e94dd4ab66203fc092f624.aspx&quot; alt=&quot;imageo8oe.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That&#39;s not a lot of clients or users, so please enable the Telemetry and use our Labs, so we all can learn and build more things our users love. &#128640;&lt;/p&gt;</id><updated>2020-05-26T14:51:25.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>The Next Step for Episerver CMS Labs - User Telemetry in BlockEnhancements</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2020/2/the-next-step-for-episerver-cms-labs/" /><id>&lt;p&gt;As of &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.BlockEnhancements&amp;amp;amp;v=0.7.1&quot;&gt;EPiServer.Labs.BlockEnhancements 0.7.0&lt;/a&gt;&amp;nbsp;it will support sending some telemetry data to help the CMS UI team determine which of the many great improvements should be fully supported, with all the complicated combinations of Languages, Content Approval, Project Mode, and more. This telemetry technology and how we work with it in CMS UI will move into the main CMS UI package in the near future. Opting-in on self-hosted instances is optional. DXP hosted instances will have this enabled.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Help us do this right. &lt;/em&gt;We want to learn about how the CMS UI is used, while respecting our users privacy. See the &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements/blob/master/README.md#telemetry-information&quot;&gt;Telemetry Information section&lt;/a&gt;&amp;nbsp;and the&amp;nbsp;&lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements/pull/44/files&quot;&gt;code on Github&lt;/a&gt;. Create issues there with your concerns or post here on this blog post. If you prefer to write in private you can reach me at jp.johansson@episerver.com&lt;/p&gt;
&lt;p&gt;As you might have read in &lt;a href=&quot;/link/487e09260da244f69c5a0ad6fbdaa75d.aspx&quot;&gt;Introducing Episerver CMS Labs&lt;/a&gt;&amp;nbsp;there are certain improvements that are just too big to do right away without knowing if we&#39;re going to hit the mark. We introduced Labs to validate potential features before implementing them fully and we&#39;re very happy with the feedback we&#39;ve received from our first Labs: &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements&quot;&gt;BlockEnhancements&lt;/a&gt;. I have personally heard from many Sales Architects, Trainers, PMs, and EMVP&#39;s; how it has completely changed the experience of working with blocks. That&#39;s wonderful!&lt;/p&gt;
&lt;p&gt;You might also notice that I didn&#39;t mention Editors or Marketers; the ones that work all day in our UI, the ones we build all of this for. Which of the six main features are making them happy? All of them? One of them? None of them? Does the inline publish from the &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements#inline-block-editing&quot;&gt;Inline Block Edit&lt;/a&gt;&amp;nbsp;(&lt;a href=&quot;/link/182680364c024f7094b9610881370e6f.aspx&quot;&gt;v0.5.0&lt;/a&gt;) fit into a workflow of &quot;edit, then publish&quot; in such a way that the &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements#inline-publish&quot;&gt;Inline Publish from the Assets Pane&lt;/a&gt; (&lt;a href=&quot;/link/c256bf3bdc2743f0aa6179e8c9c76fb9.aspx&quot;&gt;v0.1.0&lt;/a&gt;) is no longer needed? Does &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements#smart-publish&quot;&gt;Smart Publish&lt;/a&gt;&amp;nbsp;(&lt;a href=&quot;/link/7b4798fad30047b3b8ad90098b4569a9.aspx&quot;&gt;v0.2.0&lt;/a&gt;) work so well that &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements#inline-publish&quot;&gt;Inline Publish from the Content Area&lt;/a&gt;&amp;nbsp;(&lt;a href=&quot;/link/c256bf3bdc2743f0aa6179e8c9c76fb9.aspx&quot;&gt;v0.1.0&lt;/a&gt;) is no longer used? And does anyone ever try to publish anything less than &quot;everything&quot; when the Smart Publish dialog shows up for configuration? It&#39;s really hard to tell.&lt;/p&gt;
&lt;p&gt;Until now. With &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.BlockEnhancements&amp;amp;amp;v=0.7.1&quot;&gt;EPiServer.Labs.BlockEnhancements 0.7.0&lt;/a&gt; we will finally get some of those answers. It will enable us to use AppInsights to track feature usage and give a high level answer to some of our questions, as you can see here:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;prd-w-img&quot;&gt;&lt;img src=&quot;/link/f5a33bf6ad0e4441abae58c22e4cc13a.aspx&quot; alt=&quot;image3ls4.png&quot; /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class=&quot;prd-w-img&quot;&gt;(This is how the data looks after CMS UI and QA has verified the UI functionality for this release)&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We plan to fully support one of the main publishing paths from BlockEnhancements, and we need some data to see which one. Perhaps we learn that despite the positive remarks neither really hit the mark and we need to do more Labs.&lt;/p&gt;
&lt;h2&gt;Privacy&lt;/h2&gt;
&lt;p&gt;The CMS UI team is very interested in what our users use and do not use. What should we improve, what should we remove, what ... So many questions. &#128516; But just gathering data and then trying to find questions that can be answered with the data is perhaps more fun than useful. Instead, we will start with a question and only add the &lt;em&gt;minimum&lt;/em&gt;&amp;nbsp;of tracking events to answer that question in a reasonable way.&lt;/p&gt;
&lt;p&gt;We know from meeting users that they can have different preferences due to previous experiences. We also know from experience that sometimes a feature is used very differently from what we intended due to modifications on the partner/client end. To be able to filter data to determine outliers we will use &lt;strong&gt;anonymized id&#39;s&lt;/strong&gt; for users and clients.&lt;/p&gt;
&lt;p&gt;We are mainly interested in aggregated data, which you can see in our dashboard above. We will enable this on DXP environments, but if you&#39;re self hosted you can enable Telemetry with the configuration:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureContainer(ServiceConfigurationContext context)
{
    context.Services.Configure&amp;lt;TelemetryOptions&amp;gt;(options =&amp;gt; options.OptedIn = true);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;re trying to be as transparent as possible so please take a look at in the &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements/blob/master/README.md#telemetry-information&quot;&gt;Telemetry Information section&lt;/a&gt; where all the tracked events are carefully detailed.&lt;/p&gt;
&lt;p&gt;We&#39;re looking at how we can share this data with you and how it can be useful for add-ons, both 1st and 3rd party ones. We&#39;re taking it slow to make sure we do this right and respect everyone&#39;s concerns around privacy. We will start with something simpler, perhaps some blog posts from the team with what we learned - would that be of interest to you?&lt;/p&gt;
&lt;p&gt;This is just a first step into being a bit more data-driven in our UX decisions. We plan to include this technology in the main CMS UI product. While this is in BlockEnhancements you can see every tracked event detailed in the Readme, and see it in the code as well. What we track in CMS UI will be of the same level of detail, but won&#39;t be as easy to be as transparent with. Help us do it right in BlockEnhancements so that we&#39;re all happy and confident with this in CMS UI. We tried to make it as clear as possible for you to review the code in this &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements/pull/44/files&quot;&gt;Github pull request&lt;/a&gt;&lt;span&gt;. Create issues there with your concerns or post here on this blog post. If you prefer to write in private you can reach me at jp.johansson@episerver.com&lt;/span&gt;&lt;/p&gt;</id><updated>2020-02-25T14:01:22.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing Episerver CMS Labs</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2019/8/introducing-episerver-cms-labs/" /><id>&lt;p class=&quot;informationBox&quot;&gt;Episerver CMS Labs are CMS add-ons that solve a big problem in a small way, where the &quot;happy paths&quot; of a user flow are tested and fixed, while other paths and scenarios are left aside. The Labs are open sourced on Episerver&#39;s GitHub account so that you can contribute fixes to the scenarios that block your use cases. The main purpose of Labs is to validate potential features before implementing them fully and supporting all of Episerver CMS&#39; complex features.&lt;/p&gt;
&lt;p&gt;Episerver CMS is a complex application. Any feature added needs to work together with all existing features. This creates a lot of moving parts that must be taken into consideration when designing a new feature; it has to work from a user experience point of view as well as a technical architecture one.&amp;nbsp;Supporting language management, content approvals, and projects, are the three most time-consuming aspects of CMS to support in any new feature.&lt;/p&gt;
&lt;p&gt;The release method, by publishing a NuGet package that needs to be installed, means that clients tend to be some minor version away from the latest. This means some feedback on anything new can be very quick from our engaged community, especially EMVPs, which is great, but the main work in form of bugs and support cases, which might show us how a feature &lt;em&gt;should have&lt;/em&gt; been arrive very late - often when we&#39;ve moved on to another feature. This also means that we need to release without any known bugs, as users will have to live with them until their installation is upgraded.&lt;/p&gt;
&lt;p&gt;Those two aspects mean that when we need to tackle a very big problem, it is hard for us to validate our ideas &quot;in the wild&quot; without doing a fully fleshed-out and working solution. To counter this, the Episerver CMS UI team is experimenting with &quot;Labs&quot; add-ons. These are open sourced add-ons released on the Episerver NuGet feed, and the main user paths are verified with QA, but leaving out most complex scenarios and edge cases. They will focus on a complex usage area each, and can include one or more proposed solutions. We encourage the use of these add-ons, and appreciate feedback. Ultimately, we will gather usage data from them to properly validate which solution will make it into the main CMS UI product, or released as a fully-supported CMS add-on.&lt;/p&gt;
&lt;p&gt;Our first Labs is Block Enhancements (&lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.BlockEnhancements&quot;&gt;NuGet&lt;/a&gt;, &lt;a href=&quot;/link/c256bf3bdc2743f0aa6179e8c9c76fb9.aspx&quot;&gt;blog post on v0.1.0&lt;/a&gt;) and has been well received, from what we currently can gather. The download numbers are respectable for such a new package. :) Each release has been well met in the comments section (blog posts on&amp;nbsp;&lt;a href=&quot;/link/7b4798fad30047b3b8ad90098b4569a9.aspx&quot;&gt;v0.2.0,&lt;/a&gt;&amp;nbsp;&lt;a href=&quot;/link/fbee8ede4f184b169b48d22e26f641be.aspx&quot;&gt;v0.3.0&lt;/a&gt;, &lt;a href=&quot;https://bartoszsekula.com/post/2019/10/13/nice-improvement-for-the-inline-editing-feature&quot;&gt;v0.4.0&lt;/a&gt;, and&amp;nbsp;&lt;a href=&quot;/link/182680364c024f7094b9610881370e6f.aspx&quot;&gt;v.0.5.0&lt;/a&gt;). It focuses on simplifying block publishing, and shows seven (!) ways to tackle that complex usage. Without supporting Content Approval sequences and Projects... Now we&#39;re reaching a point where we need to understand which of these seven ways should be supported fully, as supporting all of them would take a &lt;em&gt;very&lt;/em&gt; long time and potentially bloat the user experience, as we do not know how they overlap or replace each other in a user&#39;s regular work day. We are still considering the different ways we can get this understanding. Either way, it&#39;s an exciting time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For Labs to be a succesful way for us to validate solutions, they need to be used. So &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.BlockEnhancements&quot;&gt;download&amp;nbsp;&lt;/a&gt;&lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.Labs.BlockEnhancements&quot;&gt;EPiServer.Labs.BlockEnhancements&lt;/a&gt;&amp;nbsp;now and help us out &lt;a href=&quot;https://github.com/episerver/EPiServer.Labs.BlockEnhancements&quot;&gt;in the GitHub repo&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span&gt;Legal notice&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;There are a few things you should expect from each release:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;Functionality may be added, removed, or change.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Labs projects have not been through the same quality assurance process as the versioned products and, in some cases, may show unexpected behaviour.&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;The Episerver CMS UI team notes that:&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;the scenarios in the Readme of each CMS Lab&#39;s repo will be verified and supported us&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;the Labs add-on may or may not work with other add-ons, we are not testing them&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;any such issues found, such as scenarios outside of the the Readme, can be fixed by the community by submitting a Pull Request on the Github repo&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;The software may not work on all environments.&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;em&gt;The Episerver CMS UI team notes that:&lt;/em&gt;&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Although it should work on base installations of CMS UI in Chrome and Firefox&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;There is no Episerver support; however, we will gratefully receive all feedback&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;em&gt;The Episerver CMS UI team notes that:&lt;/em&gt;&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Issues created on Github will be triaged, and if accepted, fixed by us&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Existing packages with the same name&lt;/h2&gt;
&lt;p&gt;There are some packages that have been previously released with the Labs monicker, such as &quot;EPiServer.Labs.LanguageManager&quot; and they will still be around. The CMS UI team will make it clearer by prefixing future packages with &quot;EPiServer.CMS.Labs&quot;, and consider republishing &quot;EPiServer.Labs.BlockEnhancements&quot; as &quot;EPiServer.CMS.Labs.BlockEnhancements&quot;.&lt;/p&gt;</id><updated>2019-11-19T15:35:33.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Making Blocks editable in a Content Area without Razor</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2019/1/making-blocks-editable-in-a-content-area-without-razor/" /><id>&lt;p&gt;To get an editing overlay on On-Page Edit (OPE) for a content area is quite easy. It&#39;s like any other editable property: add the &lt;span class=&quot;classLib&quot;&gt;data-epi-edit=&quot;PropertyName&quot;&lt;/span&gt; attribute (CMS UI 11.16.0, earlier versions require three attributes, see &lt;a href=&quot;/link/34fc7f9c974e4ed4a67c93374dab565f.aspx&quot;&gt;blog post&lt;/a&gt;). Depending on your markup you might have to put the attribute on a parent element, otherwise the overlays might get shifted due to styling.&lt;/p&gt;
&lt;p&gt;Example from MusicFestival&#39;s &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/pages/LandingPage.vue&quot;&gt;LandingPage.vue&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;div v-epi-edit=&quot;&#39;MainContentArea&#39;&quot;&amp;gt;
	&amp;lt;ContentArea :model=&quot;model.mainContentArea&quot;&amp;gt;&amp;lt;/ContentArea&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This enables the content area overlay, but not for the contents in it. You can still work with it using the content area menu that shows up when clicking the content area. It allows re-ordering, dragging and dropping content, and creating new blocks.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/64e3c7a8050d4cc1a59c5714cb7d13df.aspx&quot; alt=&quot;blobid0.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you want a nicer experience, similar to when using the &lt;span class=&quot;classLib&quot;&gt;@Html.PropertyFor()&lt;/span&gt; helper in Razor, then you just need to add the block id to each block as a HTML attribute: &lt;span class=&quot;classLib&quot;&gt;data-epi-block-id=&quot;TheContentLink&quot;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Example from MusicFestival&#39;s &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/ContentArea.vue&quot;&gt;ContentArea.vue&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;div :key=&quot;index&quot; v-for=&quot;(block, index) in model&quot; class=&quot;Grid-cell&quot; :class=&quot;getDisplayOption(block.displayOption)&quot;&amp;gt;
	&amp;lt;BlockComponentSelector :data-epi-block-id=&quot;isEditable ? block.contentLink.id : null&quot; :model=&quot;block&quot;&amp;gt;&amp;lt;/BlockComponentSelector&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/link/fa0c51ce4f194ad1bca2e310f350ac8c.aspx&quot; alt=&quot;imagen31q.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re using the &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.ContentDeliveryApi&quot;&gt;ContentDeliveryAPI&lt;/a&gt; add-on then the block id is available on the block&#39;s &lt;strong&gt;contentLink.id&lt;/strong&gt;. As you can see above, the blocks are rendered by a ContentArea Vue.js component by iterating over the blocks given by the page&#39;s &lt;strong&gt;model.mainContentArea&lt;/strong&gt;. The block overlay is only used when rendered in a content area, so it&#39;s not necessary to always set it (which would have been the case if we added the id in &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/BlockComponentSelector.vue&quot;&gt;BlockComponentSelector.vue&lt;/a&gt; instead).&lt;/p&gt;
&lt;p&gt;One non-obvious detail might be the conditional to only render the &lt;span class=&quot;classLib&quot;&gt;data-epi-block-id&lt;/span&gt; when the variable &lt;span class=&quot;classLib&quot;&gt;isEditable&lt;/span&gt; is true. This is to avoid rendering the property in View mode. It&#39;s a good idea to avoid leaking details about your CMS or server to your site visitors. :)&lt;/p&gt;
&lt;h2&gt;Read more&lt;/h2&gt;
&lt;p&gt;Developer Guides:&lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx#editingdataattributes&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx#editingdataattributes&quot;&gt;https://world.episerver.com/documentation/developer-guides/CMS/editing/#editingdataattributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/link/f80257067ca542288c0b74d4db6ae0c5.aspx&quot;&gt;https://world.episerver.com/documentation/developer-guides/CMS/editing/on-page-editing-with-client-side-rendering/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MusicFestival has been updated: &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/ContentArea.vue&quot;&gt;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/ContentArea.vue&lt;/a&gt;&lt;/p&gt;</id><updated>2019-02-04T12:04:24.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>One OPE attribute to rule them all: data-epi-edit (CMS UI 11.16.0)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2019/1/one-ope-attribute-to-rule-them-all-data-epi-edit-cms-ui-11-16-0/" /><id>&lt;p&gt;In &lt;a href=&quot;https://nuget.episerver.com/package/?id=EPiServer.CMS.UI&amp;amp;v=11.16.0&quot;&gt;CMS UI 11.16.0&lt;/a&gt;, we&#39;re making it easier for everyone doing client-side rendered websites to mark up their HTML.&lt;/p&gt;
&lt;h2&gt;Before 11.16.0&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;/link/4552b6ecd7504771b9f3aae5832cb3a6.aspx&quot;&gt;a previous post&lt;/a&gt;, I explained how to make an element editable in On-Page Edit when rendered by a client-side framework (e.g. React, Angular, Vue, etc). It was necessary to add three attributes:&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;span data-epi-property-name=&quot;YourProperty&quot; data-epi-property-render=&quot;none&quot; data-epi-property-edittype=&quot;floating&quot;&amp;gt;{your JS framework decides how the value is actually rendered}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is slightly verbose. Although you &lt;em&gt;could&lt;/em&gt; wrap it in some helper method in your JavaScript framework of choice (like we did in the &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/4a0815f1a020d17d548479c6b058e5f4a6e1a152/src/MusicFestival.Vue.Template/Assets/Scripts/directives/epiEdit.js#L27-L29&quot;&gt;MusicFestival sample site&lt;/a&gt;), it would require less &quot;magic&quot; or less reading of our &lt;a href=&quot;/link/f80257067ca542288c0b74d4db6ae0c5.aspx&quot;&gt;documentation&lt;/a&gt;&amp;nbsp;if there was only one attribute for frontend developers to remember. That&#39;s why we&#39;re introducing &lt;span class=&quot;classLib&quot;&gt;data-epi-edit&lt;/span&gt;. It does not have any specific behavior to learn about. It&#39;s equivalent to setting the properties above, and setting any of those properties as well will simply be ignored.&lt;/p&gt;
&lt;h2&gt;With 11.16.0&lt;/h2&gt;
&lt;p&gt;It&#39;s now enough with one simple attribute:&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;span data-epi-edit=&quot;YourProperty&quot;&amp;gt;{your JS framework decides how the value is actually rendered}&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;One note&lt;/h2&gt;
&lt;p&gt;We recommend that you don&#39;t render any &lt;span class=&quot;classLib&quot;&gt;data-epi-*&lt;/span&gt; attributes in View mode, as to not give too many details about the internal workings of your site. That&#39;s what @Html.PropertyFor() and @Html.EditAttributes() do when using Razor views. When taking over the rendering on the client-side, this responsibility moves over as well. One way is to use the global &lt;span class=&quot;classLib&quot;&gt;epi.beta.isEditable&lt;/span&gt; property (CMS UI 11.11.0, see &lt;a href=&quot;/link/fab5b0bbe59547c98c873b041c2696fb.aspx&quot;&gt;blog&lt;/a&gt;&amp;nbsp;or &lt;a href=&quot;/link/f80257067ca542288c0b74d4db6ae0c5.aspx&quot;&gt;documentation&lt;/a&gt;) to toggle the rendering off and on, as we&#39;ve done in MusicFestival (see &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/4a0815f1a020d17d548479c6b058e5f4a6e1a152/src/MusicFestival.Vue.Template/Assets/Scripts/epiMessages.js#L40-L49&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/4a0815f1a020d17d548479c6b058e5f4a6e1a152/src/MusicFestival.Vue.Template/Assets/Scripts/directives/epiEdit.js#L32-L41&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Learn more&lt;/h2&gt;
&lt;p&gt;Documentation: &lt;a href=&quot;/link/f80257067ca542288c0b74d4db6ae0c5.aspx&quot;&gt;https://world.episerver.com/documentation/developer-guides/CMS/editing/on-page-editing-with-client-side-rendering/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MusicFestival has been updated to use this in the Vue directive v-epi-edit: &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/129be15ae4a/src/MusicFestival.Vue.Template/Assets/Scripts/directives/epiEdit.js&quot;&gt;https://github.com/episerver/musicfestival-vue-template/blob/129be15ae4a/src/MusicFestival.Vue.Template/Assets/Scripts/directives/epiEdit.js&lt;/a&gt;&lt;/p&gt;</id><updated>2019-01-29T08:27:38.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Tips and tricks for a great On-Page Editing experience in SPAs and other client side rendered sites</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2018/10/tips-and-tricks-for-a-great-on-page-editing-experience-in-spas-and-other-client-side-rendered-sites/" /><id>&lt;p&gt;To get access to the new features explained in this blog post, you will need to enable beta features. This is done by following the following documentation. &lt;a href=&quot;/link/cb1c889682ca4002870a5dfb6482d674.aspx&quot;&gt;Beta features&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To demonstrate some concepts useful when creating a SPA with working OPE, we are releasing a new SPA template site on Github, called MusicFestival, together with a &lt;strong&gt;series of blog posts&lt;/strong&gt;. Don&#39;t be discouraged that the SPA is written in &lt;a href=&quot;https://vuejs.org/&quot;&gt;Vue.js&lt;/a&gt; if you&#39;re using React, Angular, or something else, as these concepts will work in any client side framework.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/link/5ccbe4dbd38c4d76a6dc81e838c70f9d.aspx&quot;&gt;Introducing a new SPA template site: MusicFestival&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When creating a SPA, you are no longer bound by certain limitations on a server side rendered site, but it&#39;s important to remember that the site still lives in a Content Management System (CMS) and that there is a human editor whose job it is to edit the site. These editors learn the concepts in the CMS user interface and feel happier when they are able to feel productive. By following these tips and tricks, you can allow your editors to have a nice editing experience, while keeping all the productive niceness of writing a site by focusing mostly on the frontend without having to focus too much on what CMS is being used behind the API.&lt;/p&gt;
&lt;p&gt;A more in-depth look at what you need to think about when doing client side routing is available in this blog: &lt;a href=&quot;/link/fab5b0bbe59547c98c873b041c2696fb.aspx&quot;&gt;Routing in a SPA with a working On-Page Editing experience (CMS UI 11.11.0)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This blog will instead focus on examples on what you can do with your site to improve the editors On-Page Editing (OPE) experience.&lt;/p&gt;
&lt;p&gt;In CMS UI 11.11.0, we introduce some useful properties on the injected &lt;code&gt;epi.beta&lt;/code&gt; property. In the template, we &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/epiContext.js&quot;&gt;make them available to all components as &lt;code&gt;$epi&lt;/code&gt;&lt;/a&gt;, which is &lt;a href=&quot;https://vuejs.org/v2/cookbook/adding-instance-properties.html&quot;&gt;a Vue.js instance property&lt;/a&gt;. You&#39;ll see it used throughout the examples.&lt;/p&gt;
&lt;h2&gt;Routing links vs edit links&lt;/h2&gt;
&lt;p&gt;As is mentioned in &lt;a href=&quot;/link/fab5b0bbe59547c98c873b041c2696fb.aspx&quot;&gt;the routing blog&lt;/a&gt;, you will want to render different HTML depending on if you&#39;re in edit mode or view mode. To simplify this, we created a Link component that does this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;!-- Editmode --&amp;gt;
    &amp;lt;a v-if=&quot;$epi.inEditMode&quot; :href=&quot;url&quot;&amp;gt;
        &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/a&amp;gt;

    &amp;lt;!-- Viewmode --&amp;gt;
    &amp;lt;router-link v-else :to=&quot;url&quot;&amp;gt;
        &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/router-link&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; allows child components to be passed by the parent component. &lt;a href=&quot;https://vuejs.org/v2/guide/components-slots.html&quot;&gt;See Vue.js docs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See the full source for the &lt;code&gt;EpiLink.vue&lt;/code&gt; component [here]( https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/widgets/EpiLink.vue).&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Disabling links in OPE&lt;/h3&gt;
&lt;p&gt;Certain links, such as a language selector in MusicFestival, are disabled when in OPE, because when switching languages it is more appropriate to use the CMS UI. There can be other use cases, so we created a &lt;code&gt;ViewModeLink&lt;/code&gt; component. We do not change the HTML in OPE as to not affect the styling, and instead simply disable the pointer events so they aren&#39;t interactive or clickable.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/f7109fce529e4cf6af4c0f5eb0ce5e00.aspx&quot; width=&quot;866&quot; alt=&quot;Disabling links in OPE&quot; height=&quot;1036&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;router-link :class=&quot;{ &#39;edit-mode&#39;: $epi.inEditMode }&quot; :to=&quot;url&quot;&amp;gt;
        &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;
    &amp;lt;/router-link&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style lang=&quot;less&quot; scoped&amp;gt;
    .edit-mode {
        pointer-events: none;
    }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;See the full source for the &lt;code&gt;EpiViewModeLink.vue&lt;/code&gt; component &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/widgets/EpiViewModeLink.vue&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Editing a visible property&lt;/h2&gt;
&lt;p&gt;To make an element editable in OPE, you can add certain attributes to the HTML, such as &lt;code&gt;&amp;lt;span data-epi-property-name=&quot;Name&quot;&amp;gt;&lt;/code&gt;. Information regarding those attributes can be found in our &lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx&quot;&gt;Developer guides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As with &lt;code&gt;@Html.EditAttributes()&lt;/code&gt;, available in ASP.NET Razor views, these attributes should &lt;em&gt;not&lt;/em&gt; be rendered for the site visitor in view or preview modes.&lt;/p&gt;
&lt;p&gt;To make this more convenient, we created a &lt;a href=&quot;https://vuejs.org/v2/guide/custom-directive.html&quot;&gt;custom Vue.js directive&lt;/a&gt; (an element property) called &lt;code&gt;v-epi-edit&lt;/code&gt; that will add all required attributes to any element using that directive. It&#39;s also possible for a component to disable the editing features by having the property &lt;code&gt;epiDisableEditing&lt;/code&gt; set to false. We will show a useful scenario in the section &lt;strong&gt;&quot;Hiding overlays when they interfere with new overlays due to user interactions&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/a5c5481b66984ba0ad2c3f51a1196760.aspx&quot; width=&quot;869&quot; alt=&quot;Edit visible property&quot; height=&quot;1036&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Using it is straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- This Vue.js code: --&amp;gt;
&amp;lt;h1 v-epi-edit=&quot;&#39;ArtistName&#39;&quot;&amp;gt;{{model.artistName}}&amp;lt;/h1&amp;gt;

&amp;lt;!-- Becomes ths HTML code: --&amp;gt;
&amp;lt;h1 data-epi-property-name=&quot;ArtistName&quot; data-epi-property-render=&quot;none&quot; data-epi-property-edittype=&quot;floating&quot;&amp;gt;...&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its implementation is quite simple too:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function toggleEditAttributes(el, binding, vnode) {
    const siteIsEditable = vnode.context.$epi.isEditable;
    const componentIsEditable = !vnode.context.epiDisableEditing;

    if (siteIsEditable &amp;amp;&amp;amp; componentIsEditable) {
        setEditAttributes(el, binding);
    } else {
        removeEditAttributes(el);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;You can see the implementation in &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/directives/epiEdit.js&quot;&gt;&lt;code&gt;epiEdit.js&lt;/code&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Editing a non-visible or hard to click property&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/link/13d8b50b62984e1595c202e5c9740cdd.aspx&quot; width=&quot;869&quot; alt=&quot;Edit non-visible property&quot; height=&quot;1036&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We also created the EpiProperty component to have a way to edit properties that might be hard to edit using the normal editing overlays, such as the background image of the ArtistDetailsPage component. It renders a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; when the page is editable.&lt;/p&gt;
&lt;p&gt;These elements should &lt;em&gt;not&lt;/em&gt; be rendered for the site visitor, in view or preview modes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;button v-if=&quot;$epi.isEditable&quot; v-epi-edit=&quot;propertyName&quot;&amp;gt;Edit property: {{propertyName}}&amp;lt;/button&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note that it uses the &lt;code&gt;EpiEdit&lt;/code&gt; directive to be editable.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See the full source for the &lt;code&gt;EpiProperty.vue&lt;/code&gt; component &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/EpiProperty.vue&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Hiding overlays when they interfere with new overlays due to user interactions&lt;/h2&gt;
&lt;p&gt;There are situations when one editable property is rendered on top of another. In the MusicFestival site, this happens when the BuyTicketBlock modal is shown on top of the Hero image on the LandingPage. To help the editor, the Hero&#39;s editable properties have their editing features disabled in those cases, so the overlays don&#39;t fight for the user&#39;s attention.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/dd2990fdd05049909dcca88a629929c7.aspx&quot; width=&quot;869&quot; alt=&quot;Hiding selected overlays&quot; height=&quot;1036&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If you recall the &lt;code&gt;v-epi-edit&lt;/code&gt; directive (the custom attribute) introduced in the section &quot;Editing a visible property&quot;, it allows the element it&#39;s on to disable editing by setting the property &lt;code&gt;epiDisableEditing&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;. You can see it used &lt;em&gt;indirectly&lt;/em&gt; on the Title in the Hero component:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
    &amp;lt;h1 v-epi-edit=&quot;&#39;Title&#39;&quot; v-html=&quot;title&quot;&amp;gt;&amp;lt;/h1&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
    computed: {
        epiDisableEditing() {
            return this.$app.modalShowing;
        }
    }
};
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;See the full source for the &lt;code&gt;Hero.vue&lt;/code&gt; component &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/widgets/Hero.vue&quot;&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;v-epi-edit&lt;/code&gt; directive will read the &lt;code&gt;epiDisableEditing&lt;/code&gt; value set by &lt;code&gt;Hero&lt;/code&gt; and disable the overlays when the site&#39;s modal is showing.&lt;/p&gt;
&lt;h2&gt;Set minimum size for editing overlays&lt;/h2&gt;
&lt;p&gt;Since CMS UI 11.11.0, there is a CSS injected to set the min-size so that properties with empty values can still be edited in OPE mode. This is otherwise set on the server side rendered HTML when not using &lt;code&gt;data-epi-property-render=&quot;none&quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/45456364743b46c0bf94ef4ec737a900.aspx&quot; width=&quot;869&quot; alt=&quot;Setting minimum size on empty overlay&quot; height=&quot;1036&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can set your own minimum size by overriding the selector &lt;code&gt;[data-epi-property-name]&lt;/code&gt;. The injected CSS is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[data-epi-property-name] {
    min-height: 14px;
    min-width: 18px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Related links&lt;/h2&gt;
&lt;p&gt;Template site using the techniques discussed in this blog: &lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template/&quot;&gt;https://github.com/episerver/musicfestival-vue-template/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Documentation on client side rendering in Episerver: &lt;a href=&quot;/link/f80257067ca542288c0b74d4db6ae0c5.aspx&quot;&gt;https://world.episerver.com/documentation/developer-guides/CMS/editing/on-page-editing-with-client-side-rendering/&lt;/a&gt;&lt;/p&gt;</id><updated>2018-10-31T13:10:09.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing a new SPA template site: MusicFestival</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2018/10/introducing-a-new-template-site-for-spas-musicfestival/" /><id>&lt;p&gt;To demonstrate some concepts that are useful when creating a SPA with working OPE, we have released a new SPA template site on Github, called MusicFestival, together with a series of blog posts that will be available in the coming days (a complete list is at the bottom).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; src=&quot;/link/9ce66625e95948c8ace78f80a2e3239f.aspx&quot; height=&quot;691&quot; width=&quot;1200&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You might have seen the site at recent Episerver Ascend events.&amp;nbsp;It was built as a showcase demo for the new Episerver &lt;a href=&quot;/link/6ffa5cb8173a414eac25740deeafdbc8.aspx&quot;&gt;Content Delivery API&lt;/a&gt;, and has since then been modified to a smaller Single-Page Application (SPA) site that is intended to show how to work with On-Page Editing (OPE). It also uses the Content Delivery API&amp;nbsp;with some customizations for friendly URLs and flatter JSON results. The site also uses CMS UI 11.11.0 which introduces some improvements and bugfixes for SPA scenarios.&lt;/p&gt;
&lt;p&gt;The default installation contains some example bands generated by a random band name generator, so it&amp;rsquo;s possible to demo straight away.&lt;/p&gt;
&lt;h2&gt;We will dig deeper in other blog posts, but you can already enjoy it on Github&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template&quot;&gt;https://github.com/episerver/musicfestival-vue-template&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We are not expert Vue.js developers, so there are probably improvements you can contribute.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;&lt;span class=&quot;informationBox&quot;&gt;&lt;strong&gt;Important:&lt;/strong&gt; The template uses Vue.js but the concepts shown would be the same in React, Angular, or other client-side framework.&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Blog series&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a title=&quot;Routing in a SPA with a working On-Page Editing experience (CMS UI 11.11.0)&quot; href=&quot;/link/fab5b0bbe59547c98c873b041c2696fb.aspx&quot;&gt;Routing in a SPA with a working On-Page Editing experience (CMS UI 11.11.0)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/link/800a3dfa129f416590fab542c257e7dc.aspx&quot; title=&quot;Tips and tricks for a great On-Page Editing experience in SPAs and other client side rendered sites&quot;&gt;&lt;span&gt;Tips and tricks for a great On-Page Editing experience in SPAs and other client side rendered sites&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;/link/4a91824ea19e4f3a8fbfb7a953115f1e.aspx&quot; title=&quot;Represent the concept of &amp;quot;pages&amp;quot; and &amp;quot;blocks&amp;quot; with matching client side components in a SPA&quot;&gt;Represent the concept of &quot;pages&quot; and &quot;blocks&quot; with matching client side components in a SPA&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span&gt;Other blog posts&lt;/span&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;/link/cc160458b8794b4eb1730db013dcf1c0.aspx&quot; title=&quot;Using Vuex in the MusicFestival template site&quot;&gt;Using Vuex in the MusicFestival template site&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;/link/34fc7f9c974e4ed4a67c93374dab565f.aspx&quot; title=&quot;One OPE attribute to rule them all: data-epi-edit (CMS UI 11.16.0)&quot;&gt;One OPE attribute to rule them all: data-epi-edit (CMS UI 11.16.0)&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</id><updated>2018-10-30T13:38:01.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Designing frontends for OPE without wrapping elements</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2018/4/designing-frontends-for-ope-without-wrapping-elements/" /><id>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;A common scenario I have seen is that a frontend developer or designer implements a design in HTML, CSS, and maybe JS, without worrying about which CMS is used to render it. The code is then copied or moved into Episerver, most often into a Razor view, by an Episerver developer. Then everyone sees the page in On-Page Edit (OPE) and gets a little sad as some of that lovely design is broken. That makes the developers get even sadder as they have to re-do some of the design to work with the extra div elements added by OPE, but at least it will look lovely again.&lt;/p&gt;
&lt;p&gt;We would like you to use the HTML structure you want. If you are rendering and handling updates purely in your client-side framework of choice, you should already be able to do this. If you are using Razor, then let us discuss two common design implementations that break, and what we can do with them. But first, let us talk about our two HTML helpers &lt;strong&gt;@Html.PropertyFor&lt;/strong&gt; and &lt;strong&gt;@Html.EditAttributes&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;HTML-helpers&lt;/h2&gt;
&lt;p&gt;These are helpers you can use in Razor views, but they are not required if you just want to do on-page editing. See the previous blog posts for more info.&lt;/p&gt;
&lt;p&gt;The way &lt;strong&gt;@Html.EditAttributes &lt;/strong&gt;works is that it adds the properties &lt;strong&gt;data-epi-property-name&lt;/strong&gt; and &lt;strong&gt;data-epi-use-mvc=&quot;True&quot;&lt;/strong&gt; to the element where it is used, but only in edit mode. It can add more properties if given more parameters. The first attribute enables editing overlays and can be added by yourself to HTML outside Razor. That second attribute tells OPE to use Episerver&amp;rsquo;s property render controller&lt;strong&gt;,&lt;/strong&gt; that in turn uses .NET&amp;rsquo;s DisplayFor, to render the property when its data has changed. That partial render replaces the innerHTML of the element with the &lt;strong&gt;data-epi-property-name&lt;/strong&gt; attribute. This becomes an issue for &amp;lt;img&amp;gt; as we will see below.&lt;/p&gt;
&lt;p&gt;Similarly, &lt;strong&gt;@Html.PropertyFor&lt;/strong&gt; adds a wrapping element with the same attributes. It uses display templates for the rendered property. The element type can be configured as we will see below.&lt;/p&gt;
&lt;h2&gt;Scenario 1 &amp;ndash; Inline elements&lt;/h2&gt;
&lt;p&gt;Here we will put a &lt;strong&gt;@Html.PropertyFor&lt;/strong&gt; inside a &amp;lt;p&amp;gt; because we want to edit some strings and the CMS UI needs something to attach to. When previewing it looks fine, but when editing, it drops out to its own line and looses the styling (see the font).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/abf3b189e56d48ac87af9a6f500df401.aspx&quot; alt=&quot;Image example1.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;That is because &lt;strong&gt;@Html.PropertyFor&lt;/strong&gt; defaults to wrapping the editable property in a &amp;lt;div&amp;gt;, and that is not a valid child element to a &amp;lt;p&amp;gt;. So, the browser splits the texts into multiple &amp;lt;p&amp;gt;, losing track of any classes or inline styling added to the original &amp;lt;p&amp;gt;. You can see how the font changes in the animation. You can set a custom element type with an anonymous object setting &lt;strong&gt;CustomTag &lt;/strong&gt;or replacing it with &lt;strong&gt;@Html.EditAttributes&lt;/strong&gt; with a suitable element. We will show both ways below:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- scenario 1 markup --&amp;gt;
&amp;lt;p class=&quot;article-about scenario&quot;&amp;gt;
    This article originated in @Html.PropertyFor(x =&amp;gt; x.CurrentPage.CountryOfOrigin) and was written by @Html.PropertyFor(x =&amp;gt; x.CurrentPage.Author).
&amp;lt;/p&amp;gt;

&amp;lt;!-- scenario 1 rendered in OPE --&amp;gt;
&amp;lt;p class=&quot;article-about scenario&quot;&amp;gt;
    This article originated in &amp;lt;/p&amp;gt;
&amp;lt;div class=&quot;epi-editContainer&quot; data-epi-property-name=&quot;CountryOfOrigin&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;Sweden&amp;lt;/div&amp;gt; and was written by
&amp;lt;div class=&quot;author&quot; data-epi-property-name=&quot;Author&quot; data-epi-use-mvc=&quot;True&quot; data-epi-property-rendersettings=&quot;{&quot;cssClass&quot;:&quot;author&quot;}&quot;&amp;gt;JP&amp;lt;/div&amp;gt;.
&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;!-- scenario 1 rendered in Preview --&amp;gt;
&amp;lt;p class=&quot;article-about scenario&quot;&amp;gt;
    This article originated in Sweden and was written by JP.
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- solution A markup --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in @Html.PropertyFor(x =&amp;gt; x.CurrentPage.CountryOfOrigin, new { CustomTag = &quot;span&quot;}) and was written by &amp;lt;span class=&quot;author&quot; @Html.EditAttributes(x =&amp;gt; x.CurrentPage.Author)&amp;gt;@Model.CurrentPage.Author&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;

&amp;lt;!-- solution A rendered in OPE --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in &amp;lt;span class=&quot;epi-editContainer&quot; data-epi-property-name=&quot;CountryOfOrigin&quot; data-epi-use-mvc=&quot;True&quot; data-epi-property-rendersettings=&quot;{&quot;customTag&quot;:&quot;span&quot;}&quot; style=&quot;min-height: auto;&quot;&amp;gt;Sweden&amp;lt;/span&amp;gt; and was written by &amp;lt;span class=&quot;author&quot; data-epi-property-name=&quot;Author&quot; data-epi-use-mvc=&quot;True&quot; style=&quot;min-height: 14px; min-width: 18px; display: inline-block;&quot;&amp;gt;JP&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;

&amp;lt;!-- solution A rendered in Preview --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in Sweden and was written by &amp;lt;span class=&quot;author&quot;&amp;gt;JP&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main markup difference between the two solutions is that the first span (from &lt;strong&gt;PropertyFor&lt;/strong&gt;) will only be rendered in OPE. Also note that all the editing attributes are only rendered in OPE. For styling with a consistent markup, the second option might be preferred.&lt;/p&gt;
&lt;p&gt;You can also use the HTML attributes directly, without the &lt;strong&gt;@Html &lt;/strong&gt;helpers:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- solution B markup --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in &amp;lt;span data-epi-property-name=&quot;CountryOfOrigin&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;@Model.CurrentPage.CountryOfOrigin&amp;lt;/span&amp;gt; and was written by &amp;lt;span class=&quot;author&quot; data-epi-property-name=&quot;Author&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;@Model.CurrentPage.Author&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;

&amp;lt;!-- solution B rendered in OPE --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in &amp;lt;span data-epi-property-name=&quot;CountryOfOrigin&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;Sweden&amp;lt;/span&amp;gt; and was written by &amp;lt;span class=&quot;author&quot; data-epi-property-name=&quot;Author&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;JP&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;

&amp;lt;!-- solution B rendered in Preview --&amp;gt;
&amp;lt;p class=&quot;article-about solution&quot;&amp;gt;
    This article originated in &amp;lt;span data-epi-property-name=&quot;CountryOfOrigin&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;Sweden&amp;lt;/span&amp;gt; and was written by &amp;lt;span class=&quot;author&quot; data-epi-property-name=&quot;Author&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;JP&amp;lt;/span&amp;gt;.
&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that there is no difference between what was rendered in OPE and in Preview. If you are rendering the HTML with a client-side framework you could toggle those attributes yourself. One way to detect that you are in OPE is to render a custom flag when &lt;strong&gt;@PageEditing.PageIsInEditMode&lt;/strong&gt; is &lt;strong&gt;true&lt;/strong&gt;. You can see one example in our &lt;a href=&quot;https://github.com/episerver/AlloyReact/&quot;&gt;Alloy React example repository&lt;/a&gt;, where we set a custom data-attribute on the &amp;lt;body&amp;gt; in our &lt;a href=&quot;https://github.com/episerver/AlloyReact/blob/8eb4c53e47523fc3fd8ec43980d507d21a18404d/AlloyReact/Views/Shared/Layouts/_Root.cshtml#L6&quot;&gt;_Root.cshtml&lt;/a&gt;&amp;nbsp;that we can check for in our React components.&lt;/p&gt;
&lt;p&gt;Adding a &amp;lt;span&amp;gt; inside a &amp;lt;p&amp;gt; should not cause any issues, but &amp;lt;img&amp;gt; are trickier...&lt;/p&gt;
&lt;h2&gt;Scenario 2 &amp;ndash; Inline elements and images&lt;/h2&gt;
&lt;p&gt;This is specific to images, or rather, the &amp;lt;img&amp;gt;. It also not tied to Razor views or HTML helpers, so using the data-epi-property-name (without handling the rendering yourself with data-epi-property-render=&amp;rdquo;none&amp;rdquo;, &lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx#editingdataattributes&quot;&gt;see the documentation&lt;/a&gt;) is also affected by this.&lt;/p&gt;
&lt;p&gt;In the animation below, we show three different attempts demonstrating what happens with &lt;strong&gt;@Html.PropertyFor&lt;/strong&gt;, &lt;strong&gt;@Html.EditAttributes&lt;/strong&gt;, and because we want to show that it can be worked around, the final polar bear is written with wrapping elements in mind.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/775cac7881814f76ba61b23fe55f3eda.aspx&quot; alt=&quot;Image example2-2-resized.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Setting the innerHTML when updating a property works for all elements except images. For example, &amp;lt;p&amp;gt; and &amp;lt;span&amp;gt; have text as the innerHTML so when the property has been updated, then setting the innerHTML with the new text will work. When it comes to &amp;lt;img&amp;gt;, there is no valid innerHTML so when it is set it creates invalid markup. Because PropertyFor always adds a wrapping element it will re-render the &amp;lt;img&amp;gt; properly, but the design breaks.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- scenario 2 A markup --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    @Html.PropertyFor(x =&amp;gt; x.CurrentPage.SummaryImage)
    &amp;lt;p&amp;gt;@Html.PropertyFor(x =&amp;gt; x.CurrentPage.SummaryText)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- scenario 2 A rendered in OPE --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    &amp;lt;div class=&quot;epi-editContainer&quot; data-epi-property-name=&quot;SummaryImage&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;
        &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&amp;amp;visitorgroupsByID=undefined&quot; alt=&quot;&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;div class=&quot;epi-editContainer&quot; data-epi-property-name=&quot;SummaryText&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;To the left you can see a &quot;Polar Bear&quot;.&amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- scenario 2 A rendered in Preview --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&quot; alt=&quot;&quot;&amp;gt;
    &amp;lt;p&amp;gt;To the left you can see a &quot;Polar Bear&quot;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can try to use &lt;strong&gt;EditAttributes&lt;/strong&gt; instead of &lt;strong&gt;PropertyFor&lt;/strong&gt;, and at first it might seem to work but as can be seen in the second polar bear in the animation, the image does not seem to be replaced when the user updates that property.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- scenario 2 B markup --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    &amp;lt;img @Html.EditAttributes(x =&amp;gt; x.CurrentPage.SummaryImage) src=&quot;@Url.ContentUrl(Model.CurrentPage.SummaryImage)&quot; class=&quot;image&quot; /&amp;gt;
    &amp;lt;p @Html.EditAttributes(x =&amp;gt; x.CurrentPage.SummaryText)&amp;gt;@Model.CurrentPage.SummaryText&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- scenario 2 B rendered in OPE --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    &amp;lt;img data-epi-property-name=&quot;SummaryImage&quot; data-epi-use-mvc=&quot;True&quot; src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/polarbearonice.png,,81?epieditmode=False&quot; class=&quot;image&quot;&amp;gt;
        &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&amp;amp;visitorgroupsByID=undefined&quot; alt=&quot;&quot;&amp;gt;
    &amp;lt;/img&amp;gt;
    &amp;lt;p data-epi-property-name=&quot;SummaryText&quot; data-epi-use-mvc=&quot;True&quot;&amp;gt;To the left you can see a &quot;Polar Bear&quot;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- scenario 2 B rendered in Preview --&amp;gt;
&amp;lt;div class=&quot;article-summary scenario&quot;&amp;gt;
    &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&quot; class=&quot;image&quot;&amp;gt;
    &amp;lt;p&amp;gt;To the left you can see a &quot;Polar Bear&quot;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The child &amp;lt;img&amp;gt; in the OPE view is not valid HTML and is not displayed by the browser, causing some confusion for a user as the property did in fact update when it did not look like it.&lt;/p&gt;
&lt;p&gt;To be able to change this, we need to make changes to our property renderers and their use of custom display templates. However, it does not seem possible without a breaking change, needing a new major release. If this is an important issue for you that you would like us to focus on, please vote on the bug &lt;a href=&quot;/link/1933ba72787346df9003b7a4c7d1cff8.aspx?epsremainingpath=bug/CMS-9506&quot;&gt;CMS-9506&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For now, you need to use a wrapping element and write the markup and stylesheet with that in mind. In our example we decided to use a CSS grid, but your solution may vary.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;!-- solution markup --&amp;gt;
&amp;lt;div class=&quot;article-summary-grid solution&quot;&amp;gt;
    &amp;lt;div @Html.EditAttributes(x =&amp;gt; x.CurrentPage.SummaryImage) class=&quot;left&quot;&amp;gt;
        &amp;lt;img src=&quot;@Url.ContentUrl(Model.CurrentPage.SummaryImage)&quot;/&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p @Html.EditAttributes(x =&amp;gt; x.CurrentPage.SummaryText) class=&quot;right&quot;&amp;gt;
        @Model.CurrentPage.SummaryText
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- solution rendered in OPE --&amp;gt;
&amp;lt;div class=&quot;article-summary-grid solution&quot;&amp;gt;
    &amp;lt;div data-epi-property-name=&quot;SummaryImage&quot; data-epi-use-mvc=&quot;True&quot; class=&quot;left&quot;&amp;gt;
        &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&amp;amp;visitorgroupsByID=undefined&quot; alt=&quot;&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p data-epi-property-name=&quot;SummaryText&quot; data-epi-use-mvc=&quot;True&quot; class=&quot;right&quot;&amp;gt;
        To the left you can see a &quot;Polar Bear&quot;.
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- solution rendered in Preview --&amp;gt;
&amp;lt;div class=&quot;article-summary-grid solution&quot;&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;
        &amp;lt;img src=&quot;/EPiServer/CMS/Content/contentassets/en/21cd8489b66d40a9b9711df5158be324/spotless-panda.png,,113?epieditmode=False&quot;&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p class=&quot;right&quot;&amp;gt;
        To the left you can see a &quot;Polar Bear&quot;.
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the code on our Github (in the branch blog/designing-without-wrapping-elements): &amp;nbsp;&lt;a href=&quot;https://github.com/episerver/alloy-mvc-template/compare/blog/designing-without-wrapping-elements&quot;&gt;https://github.com/episerver/alloy-mvc-template/compare/blog/designing-without-wrapping-elements&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We hope this helps you along.&amp;nbsp;&lt;img src=&quot;/Scripts/tinymce/plugins/emoticons/img/smiley-smile.gif&quot; alt=&quot;smile&quot; /&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2018-05-04T14:33:05.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>&quot;domUpdated&quot; is no longer needed (BETA) (CMS UI 11.4.0)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2018/3/domupdated-is-no-longer-needed-beta-cms-ui-11-4-0/" /><id>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;You can read more about how you enable Beta features in &lt;a href=&quot;/link/cb1c889682ca4002870a5dfb6482d674.aspx&quot;&gt;the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In CMS UI 11.2.0 we introduced &lt;a href=&quot;/link/bea7c9750d854be69972f1b705b29d07.aspx&quot;&gt;the &quot;beta/domUpdated&quot; message&lt;/a&gt;&amp;nbsp;that refreshes the On-Page Editing (OPE) overlays.&amp;nbsp;Based on feedback we received at presentations and &lt;a href=&quot;https://github.com/episerver/AlloyReact/issues/2&quot;&gt;on Github&lt;/a&gt;, we are now watching the view for changes to DOM elements with the &quot;data-epi-property-name&quot; property. You no longer need to do this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;epi.publish(&quot;beta/domUpdated&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the DOM changes so that there are new elements with data-epi-property-name, or existing elements change their value to another property name, then the overlays automatically gets updated.&lt;/p&gt;
&lt;h2&gt;Previous considerations&lt;/h2&gt;
&lt;p&gt;As mentioned in the previous post, there were two reasons to introduce a message instead of automatically refreshing:&lt;/p&gt;
&lt;p&gt;1. UI becomes unresponsive as the spamming is ongoing&lt;br /&gt;2. Memory usage increases&lt;/p&gt;
&lt;p&gt;There was also a third reason:&lt;/p&gt;
&lt;p&gt;3. Giving you control of when to refresh, as to minimize 1 and 2.&lt;/p&gt;
&lt;p&gt;But reason 3. seems like it just lead to boilerplate code that many would rather avoid, and we had already made changes to minimize the impact of 1. and 2., so when we got the question &quot;can&#39;t it just &#39;work&#39;?&quot; we decided to make this change. The overlays will update by themselves now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/8a23abb703094bf2b0c581dca1cb7f89.aspx&quot; alt=&quot;Image after.gif&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Benefits&lt;/h2&gt;
&lt;p&gt;The main benefit is that it&#39;s now easier for a partner to make great client-side rendered UI&#39;s that still work nicely in OPE.&amp;nbsp;That also makes our communication around features like this easier, because you don&#39;t have to do anything.&amp;nbsp;&lt;img src=&quot;/Scripts/tinymce/plugins/emoticons/img/smiley-cool.gif&quot; alt=&quot;cool&quot; /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Code on Github&lt;/h2&gt;
&lt;p&gt;Please contribute to these repos to help each other with how to work with OPE and your favourite JavaScript framework!&lt;/p&gt;
&lt;p&gt;The example in our React sample repo has been updated to remove the &quot;beta/domUpdated&quot; code:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/episerver/AlloyReact&quot;&gt;https://github.com/episerver/AlloyReact&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please contribute an example to the AngularJS repo:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/episerver/AlloyAngularJS&quot;&gt;https://github.com/episerver/AlloyAngularJS&lt;/a&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2018-03-13T08:04:42.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Taking more control of client-side rendering in OPE (Beta) (CMS UI 11.2.0)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2017/12/taking-more-control-of-client-side-rendering-in-ope-beta2/" /><id>&lt;p class=&quot;informationBox&quot;&gt;This feature has changed in CMS UI 11.4.0! The event is no longer needed. Read &lt;a title=&quot;&amp;quot;domUpdated&amp;quot; is no longer needed&quot; href=&quot;/link/8d015a9266d54bb78a849ea0603aeb79.aspx&quot;&gt;the blog post&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;You can read more about how you enable Beta features in &lt;a href=&quot;/link/cb1c889682ca4002870a5dfb6482d674.aspx&quot;&gt;the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Earlier, in &lt;a href=&quot;/link/4552b6ecd7504771b9f3aae5832cb3a6.aspx&quot;&gt;CMS UI 10.12.0, we introduced some features&lt;/a&gt;&amp;nbsp;that let you take some control over the client-side rendering in On-Page Edit (OPE). One of those tools was the &quot;beta/contentSaved&quot; topic that you could subscribe to to know when to update the DOM. With &lt;strong&gt;CMS UI 11.2.0,&lt;/strong&gt; we address the other side of that coin, which is letting us subscribe to know when you updated the DOM and that we need to remap the OPE overlays.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Here we’ll go through&amp;nbsp;one new topic that you can use to further improve the OPE experience while using Angular, React, or any other JavaScript framework. You can read more in the&amp;nbsp;&lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx&quot;&gt;Editing documentation&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The global JavaScript object (see &quot;Telling OPE that you need new overlays&quot;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;epi.publish(&quot;beta/domUpdated&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Knowing when to remap the OPE overlays&lt;/h2&gt;
&lt;p&gt;One common scenario is when you have an element with the property &quot;data-epi-property-name&quot; that will enable the OPE overlay, but since this element is not present when the OPE overlays are created, you don&#39;t see an OPE overlay for the element. This makes editing that property slightly challenging in OPE and once again you have to direct your editors to the All properties view. The &lt;a href=&quot;/link/4675a24d3e164719a4a5cdbc58c94172.aspx&quot;&gt;Sticky View Mode&lt;/a&gt; can keep your editors from switching views all the time, but it would be nicer if OPE just works, right?&lt;/p&gt;
&lt;p&gt;&lt;span&gt;There are several situations where the OPE overlay doesn&#39;t match the DOM:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;Element is conditionally rendered by the client-side framework&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;Example: A text that&#39;s only shown when the user reaches the last page in a pagination&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Element is replaced by another similar element but using another &quot;data-epi-property-name&quot; value&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;Example: When loading the value was &quot;fact1&quot;, and after user interaction the value is &quot;fact2&quot;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Element is rendered after the page has loaded&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;Example: Data is fetched through an API and only renders once it&#39;s done&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&#39;ll&amp;nbsp;focus on&amp;nbsp;the first two examples because&amp;nbsp;they&#39;re easier to demo. For the user, it can look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Image before.gif&quot; src=&quot;/link/43c4a317465c4ef5a00e3d57ed0d0409.aspx&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Telling OPE that you need new overlays&lt;/h2&gt;
&lt;p&gt;We felt that using a message to communicate, like with &quot;beta/contentSaved&quot;, was a nice solution so we decided to create a new topic: &lt;strong&gt;&quot;beta/domUpdated&quot;&lt;/strong&gt;. To tell the OPE view to remap all the overlays on the page, simply&amp;nbsp;&lt;strong&gt;publish&amp;nbsp;&lt;/strong&gt;to that topic using the global &quot;&lt;strong&gt;epi&lt;/strong&gt;&quot; object:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;epi.publish(&quot;beta/domUpdated&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; You cannot subscribe to this&amp;nbsp;topic&amp;nbsp;from the view because the communication only goes from and to the iframe where the page view lives. A gadget or other code on the CMS UI side would be able to subscribe though.&lt;/p&gt;
&lt;h2&gt;Considerations when using an over-powered feature&lt;/h2&gt;
&lt;p&gt;With the new topic, it&#39;s possible to accidentally spam messages, prefering to publish one too many than one too few. This causes a few problems.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UI becomes unresponsive as the spamming is ongoing&lt;/li&gt;
&lt;li&gt;Memory usage increases&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To solve problem 1, we added a&amp;nbsp;debounce&amp;nbsp;period of 100 milliseconds where each new message resets the cool down period. This causes a small (100ms) lag before the OPE overlays are remapped.&lt;/p&gt;
&lt;p&gt;To solve problem 2, we had to do several performance improvements, that also improve memory usage in other scenarios, such as changing pages (context change). All in all, we&#39;ve made dozen&amp;nbsp;small fixes, but as we say in Sweden: &quot;&lt;a href=&quot;https://sv.wiktionary.org/wiki/M&#229;nga_b&#228;ckar_sm&#229;_g&#246;r_en_stor_&#229;.&quot;&gt;Many small streams make a big river.&lt;/a&gt;&quot;&lt;/p&gt;
&lt;p&gt;In one scenario we tried, we made a Higher-Order Component in React that would publish a message on the &quot;beta/domUpdated&quot; topic on componentDidMount and componentDidUpdate. The problem was that we created a new wrapped component in the render method, and that lead to an exponential growth of messages every time something rendered. The lesson is that it&#39;s very easy to accidentally publish too many messages. :) As the &lt;a href=&quot;http://marvel.wikia.com/wiki/Benjamin_Parker_(Earth-616)&quot;&gt;great American poet Ben Parker&lt;/a&gt; once said: &quot;With great power, there must also come great responsibility&quot;. So try to consolidate your DOM changes to as few messages as you can.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: inherit; font-family: inherit; font-size: 22px;&quot;&gt;A simple example in React&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The message in &quot;domUpdated&quot; is simpler than the &quot;contentSaved&quot; because there is no message object involved. To demonstrate this we&#39;re just going to publish the message in our ThreeKeyFacts&#39; componentDidUpdate method, but you should try to consolidate the messages so each component doesn&#39;t live its own life and spam &quot;domUpdated&quot; messages.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;

export default class ThreeKeyFacts extends React.Component {

    constructor(props) { ... }

    render() { ... }

    next() { ... }

    previous() { ... }

    componentDidMount() {
        // Here we do some epi.subscribe(&quot;beta/contentSaved&quot;, ...)
    }

    componentDidUpdate() {
        if (window.epi &amp;amp;&amp;amp; window.epi.publish) {
            // Publishing a message on the &quot;beta/domUpdated&quot; topic will tell episerver UI that the DOM has changed 
            // and that it needs to remap its overlays.
            window.epi.publish(&quot;beta/domUpdated&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By publishing a message on the &quot;beta/domUpdated&quot; topic in componentDidUpdate the overlays now match the elements being shown:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Image after.gif&quot; src=&quot;/link/a91cab64f4fb43e19d32ea7e782bbb05.aspx&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2&gt;Code on Github&lt;/h2&gt;
&lt;p&gt;Please contribute to these repos to help each other with how to work with OPE and your favourite JavaScript framework!&lt;/p&gt;
&lt;p&gt;The example above is in our React sample repo:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/episerver/AlloyReact&quot;&gt;https://github.com/episerver/AlloyReact&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please contribute an example to the AngularJS repo:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/episerver/AlloyAngularJS&quot;&gt;https://github.com/episerver/AlloyAngularJS&lt;/a&gt;&lt;/p&gt;</id><updated>2017-12-19T12:59:55.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Taking control of client-side rendering in OPE (Beta) (CMS UI 10.12.0)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2017/10/taking-control-of-client-side-rendering-in-ope-beta/" /><id>
&lt;p&gt;You can read more about how you enable Beta features in&amp;nbsp;&lt;a href=&quot;/link/8b4432703e44486ea1af6ddec232a8c5.aspx&quot;&gt;Fredrik Tj&amp;auml;rnberg&amp;rsquo;s blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With CMS UI 10.12.0 we&amp;rsquo;re including some options to better support the On-Page Editing (OPE) experience for websites that want to handle the view on the client-side. This could be using a JavaScript framework such as React or Angular. The main issue is about controlling the DOM and Ted Nyberg explains it well &lt;a href=&quot;https://tedgustaf.com/blog/2017/episerver-on-page-edit-with-angular-react-and-other-js-frameworks/&quot;&gt;in his blog&lt;/a&gt;.&amp;nbsp;Many projects work around it by simply asking the editors to use the Properties Mode instead, which is why we previously released &lt;a href=&quot;/link/4675a24d3e164719a4a5cdbc58c94172.aspx&quot;&gt;&quot;Sticky View Mode&quot; in CMS UI 10.11.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here we&amp;rsquo;ll go through four things you can use to improve the OPE experience while using Angular, React, or any other JavaScript framework. You can read more in the &lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx&quot;&gt;Editing documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three HTML attributes for editing&lt;/strong&gt; (see&amp;nbsp;&quot;Telling OPE that you&amp;rsquo;ll take over the rendering&quot;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;classLib&quot;&gt;data-epi-property-name=&quot;YourProperty&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;classLib&quot;&gt;data-epi-property-render=&quot;none&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;classLib&quot;&gt;data-epi-property-edittype=&quot;floating&quot;&lt;/span&gt; (usually default, but needed for string properties)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;And the global JavaScript object&lt;/strong&gt; (see &quot;Knowing when to re-render&quot;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;classLib&quot;&gt;epi.subscribe(&quot;beta/contentSaved&quot;, callback)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Telling OPE that you&amp;rsquo;ll take over the rendering&lt;/h2&gt;
&lt;p&gt;To stop the CMS UI from replacing the DOM when an editor changes the value of a property, add the HTML attribute data-epi-property-render=&quot;none&quot; to the DOM element that&#39;s marked for editing with &lt;strong&gt;@Html.EditAttributes(m =&amp;gt; m.YourProperty)&lt;/strong&gt; or &lt;strong&gt;data-epi-property-name=&quot;YourProperty&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re editing a string-type you can add the &lt;strong&gt;data-epi-property-edittype=&quot;floating&quot;&lt;/strong&gt; to get a dialog with the text, instead of contenteditable replacing the DOM as the user types.&lt;/p&gt;
&lt;h2&gt;Knowing when to re-render&lt;/h2&gt;
&lt;p&gt;Now that OPE won&#39;t replace the DOM as the user changes property values you&amp;rsquo;ll need to do this yourself. But how do you know when when or what to change?&lt;/p&gt;
&lt;p&gt;For this we&amp;rsquo;ll use the little known &quot;epi&quot; object that allows us to communicate between the CMS UI context and the view. Whenever a save happens we will publish the details on a topic called &lt;strong&gt;&quot;beta/contentSaved&quot;&lt;/strong&gt;. You can subscribe to this topic to know when and what to change in your view.&lt;/p&gt;
&lt;p&gt;If you based your site on Alloy you probably have this object already. To get it you need have the attribute &lt;strong&gt;[RequireClientResources]&lt;/strong&gt; on your controller, or just inherit from &lt;strong&gt;PageController&lt;/strong&gt; or &lt;strong&gt;ContentController&lt;/strong&gt; as they&#39;ll include it.&amp;nbsp;Then you&amp;rsquo;ll need to require the resources in your razor view where you include any other scripts, probably in _Root.cshtml, using: &lt;strong&gt;@Html.RequiredClientResources(&quot;Footer&quot;)&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;A simple string example (without JS)&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s see how things look without JavaScript. When it comes to string property types they&amp;rsquo;re changing the DOM as you type. Besides the problems for client-side frameworks, it makes editing awkward in certain scenarios such as the placeholder text in input-elements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/7811d7e4be024ed997ff3cdcab2abd2b.aspx&quot; alt=&quot;Image nojs-sample.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To achieve this we&amp;rsquo;ll add a property to the model. I&amp;rsquo;m using Alloy and the Search page, so in Models/Pages/SearchPage.cs I&amp;rsquo;m adding:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public virtual string SearchPlaceholderText { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in its Razor-view,&amp;nbsp;which for me is&amp;nbsp;Views/SearchPage/Index.cshtml, add this to force a reload:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;@Html.FullRefreshPropertiesMetaData(new[] { &quot;SearchPlaceholderText&quot; })&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And change the input element from this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; tabindex=&quot;1&quot; name=&quot;q&quot; value=&quot;@Model.SearchedQuery&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;input type=&quot;text&quot; tabindex=&quot;1&quot; name=&quot;q&quot; value=&quot;@Model.SearchedQuery&quot; placeholder=&quot;@Model.CurrentPage.SearchPlaceholderText&quot; data-epi-property-name=&quot;SearchPlaceholderText&quot; data-epi-property-edittype=&quot;floating&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the code in the links below.&lt;/p&gt;
&lt;h2&gt;A simple example in AngularJS&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s use Alloy, but change the page image for Product pages so that we&#39;re showing the editor some extra info about the image. This could be useful for sites that have more image metadata or other data that depend on the selected image.&lt;/p&gt;
&lt;p&gt;This is what we&#39;re going for:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/7bf8fc60b9424a5c9ced5909a9df7c49.aspx&quot; alt=&quot;Image angular-sample.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Originally, the view looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;div @Html.EditAttributes(x =&amp;gt; x.CurrentPage.PageImage)&amp;gt;
    &amp;lt;img src=&quot;@Url.ContentUrl(Model.CurrentPage.PageImage)&quot;/&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;re changing it to this:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;div data-epi-property-name=&quot;PageImage&quot; data-epi-property-render=&quot;none&quot;&amp;gt;
    &amp;lt;img ng-src=&quot;{{ctrl.pageImageUrl}}&quot; alt=&quot;{{ctrl.pageImageName}}&quot;/&amp;gt;
    @if (PageEditing.PageIsInEditMode)
    {
        &amp;lt;pre&amp;gt;Drag an image here to test OPE with Angular!&amp;lt;br/&amp;gt;Image name: {{ctrl.pageImageName}}&amp;lt;/pre&amp;gt;
    }
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;strong&gt;@Html.EditAttributes()&lt;/strong&gt; is replaced with &lt;strong&gt;data-epi-property-name&lt;/strong&gt;. This enables the content overlay and allows the editor to change the value of that property.&lt;/p&gt;
&lt;p&gt;Also note the &lt;strong&gt;data-epi-property-render&lt;/strong&gt;&amp;nbsp;that&#39;s telling the renderer that we&#39;ll be handling things for this element!&lt;/p&gt;
&lt;p&gt;To get some start values, we&#39;re copying parts of the model to a global object that our Angular controller can initialize with.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    window.pageModel = {
        contentLink: &quot;@Model.CurrentPage.ContentLink&quot;,
        pageImage: &quot;@Model.CurrentPage.PageImage&quot;
    };
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code on Github has more functionality and comments explaining them, so here I&amp;rsquo;ll just outline the important part: how to update the values when the page is being edited.&lt;/p&gt;
&lt;p&gt;You could work against a service and/or have this code in the Razor view, but it&amp;rsquo;s tricky to communicate between the global scope and Angular. So I chose to have this inside the controller as it&#39;s easier to demonstrate.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var vm = this;
vm.model = $window.pageModel || {};

// Helper method to get image URL and name through XHR and update pageImage properties.
function updatePageImage(contentLink) { &amp;hellip; }

// Wait until the window has loaded, and then hook up our property update logic.
$window.addEventListener(&quot;load&quot;, function () {
    // Subscribe to the contentSaved topic. Now the fun starts!
    $window.epi.subscribe(&quot;beta/contentSaved&quot;, function (details) {
        // Go through all the saved properties. Usually it&#39;s only one.
        details.properties.forEach(function (property) {
            switch (property.name) {
                // Handle the page image property differently, because we only get the content reference but need more data for the page.
                case &quot;pageImage&quot;:
                    updatePageImage(property.value);
                    break;

                // Otherwise just update the value on the model.
                default:
                    vm.model[property.name] = property.value;
                    break;
            }
        });
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;/link/60371278b0b348a4a2b95c1bccc16ed9.aspx&quot;&gt;The documentation&lt;/a&gt; has an example of the object you might get from the event, but below is the interesting part:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{  
   &quot;contentLink&quot;:&quot;6_164&quot;, // The content reference to this page
   &quot;properties&quot;:[  
      {  
         &quot;name&quot;:&quot;pageImage&quot;, // The property that changed
         &quot;value&quot;:&quot;59&quot; // The new value. Content references will need an extra lookup to get what you want, but string and other properties can be usable directly.
      }
   ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the code in the links below.&lt;/p&gt;
&lt;h2&gt;A complex example in React&lt;/h2&gt;
&lt;p&gt;We have an example of how to rewrite the PageListBlock in React but it&#39;s a little big for this blog post. The basic usage of the data-attributes and listening to the &amp;ldquo;beta/contentSaved&amp;rdquo; message is the same as in the Angular example above. See the code in the links below.&lt;/p&gt;
&lt;h2&gt;Code on Github&lt;/h2&gt;
&lt;p&gt;Please contribute to these repo&#39;s to help each other how to work with OPE and your favourite JavaScript framework!&lt;/p&gt;
&lt;p&gt;A simple string example (without JS): &lt;a href=&quot;https://github.com/seriema/AlloyNoJS&quot;&gt;https://github.com/seriema/AlloyNoJS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A simple example in AngularJS: &lt;a href=&quot;https://github.com/seriema/AlloyAngularJS&quot;&gt;https://github.com/seriema/AlloyAngularJS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A complex example in React: &lt;a href=&quot;https://github.com/seriema/AlloyReact&quot;&gt;https://github.com/seriema/AlloyReact&lt;/a&gt;&lt;/p&gt;</id><updated>2017-10-03T14:12:30.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing Group/Role support in Content Approvals</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2017/5/introducing-grouprole-support-in-content-approvals/" /><id>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;This feature was released in CMS UI 10.10.0.&lt;/p&gt;
&lt;h2&gt;What are Groups/Roles?&lt;/h2&gt;
&lt;p&gt;Groups, or Roles, are already commonly used in the CMS to manage access rights and other settings that should apply to a group of users instead of setting them individually. A commonly mentioned use case for Content Approvals is to add a group of users to a step instead of individual users. For example,&amp;nbsp;adding the &quot;Legal Department&quot; group as a reviewer. This makes setting up content approval sequences easier as well as allowing the members of a group to change without having to change the sequence. So if there&#39;s a new hire in the &quot;Legal Department&quot; or someone leaves for another position, you just have to update the group and the new hire is included in the reviews (both ongoing and future reviews) and the removed user can no longer review content.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;/link/b917986b857b4c8aa02eecf287d2cb9a.aspx&quot; alt=&quot;Image blog-role-reviewer.gif&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;What about Notifications in large groups?&lt;/h2&gt;
&lt;p&gt;Adding a very large group will result in notifications being sent out to all the current members of the group on every step in a content approval sequence. This can have negative effects on the performance of the server, as well as probably annoy users. Therefore, we have added &lt;a href=&quot;/link/234ad865e8d24900b49f5afa830343c9.aspx&quot;&gt;a new configuration setting&lt;/a&gt;, &quot;ApprovalStepRoleUserLimit&quot;, that defaults to 100 users per group. Adding a group larger than this setting to a content approval sequence, triggers a validation warning, and it also limits the amount of notifications per group.&lt;/p&gt;
&lt;h2&gt;What are known limitations?&lt;/h2&gt;
&lt;p&gt;There can be limitations depending on the role provider used. &lt;a href=&quot;/link/c620e944deea45d5a43e1237acec2848.aspx&quot;&gt;See the SDK for more information.&lt;/a&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2017-06-13T15:22:19.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing Tasks in Content Approvals (Beta)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2017/2/introducing-tasks-in-content-approvals-beta/" /><id>&lt;p&gt;This feature is released as a Beta feature in CMS UI 10.5.0 and is still under development.&lt;/p&gt;
&lt;p&gt;You can read more about how you enable Beta features in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;/link/8b4432703e44486ea1af6ddec232a8c5.aspx&quot;&gt;Fredrik Tj&amp;auml;rnberg&amp;rsquo;s blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What are Tasks?&lt;/h2&gt;
&lt;p&gt;The Tasks pane is a useful tool for editors to monitor content creation. You can filter out content depending on their status, &amp;nbsp;for example, select Drafts in the Tasks drop-down to get a list with content items in status Draft only.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/35ea64f12b124f6f99e0776962c007f0.aspx&quot; alt=&quot;Image blog-tasks-tasks-menu-original.PNG&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Tasks with Content Approvals&lt;/h2&gt;
&lt;p&gt;The Tasks drop-down list can now be used to display content in a certain stage of an approval sequence,&lt;span&gt;&amp;nbsp;&lt;/span&gt;in a way that helps the editor to know what to focus on.&lt;/p&gt;
&lt;p&gt;For example, Alfred has sent two pages for review, and the approval sequence is set up to allow either Lina or Emil to approve.&amp;nbsp;Lina uses the Tasks pane and &lt;strong&gt;Received Review Requests&lt;/strong&gt; &amp;gt; &lt;strong&gt;Awaiting Your Review&lt;/strong&gt; to see what content she has to review and do some work:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/80f414b4a6b34c048960abdb405eb511.aspx&quot; alt=&quot;Image blog-tasks-lina--optimized.gif&quot; /&gt;&lt;/p&gt;

&lt;h2&gt;Bonus feature: Categorized Tasks Queries&lt;/h2&gt;
&lt;p&gt;As part of this release, we added grouping support to the Tasks menu. As you can see in the screenshot below that there are three main categories: &quot;Status&quot;, &quot;Sent for Review&quot;, and &quot;Received Review Requests&quot;.&lt;/p&gt;
&lt;p&gt;Any other query will end up in a category labelled &quot;Other&quot;, and you can &lt;a href=&quot;/link/4b6160d6e68849f78297fb152918c3f3.aspx&quot;&gt;easily put them in an existing or a new custom category&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b7d75460b213449eaf792fc1660bf97f.aspx&quot; alt=&quot;Image blog-tasks-tasks-menu-new--awaiting-review.png&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Bonus feature: Optional Localization Support with IContentQuery and IContentQueryCategory &amp;nbsp;&lt;/h2&gt;
&lt;p&gt;Often you might end up implementing the query&amp;rsquo;s &lt;strong&gt;DisplayName&lt;/strong&gt; using the &lt;strong&gt;LocalizationService&lt;/strong&gt;. Like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;// No need for this anymore
public override string DisplayName =&amp;gt; _localizationService.GetString(&quot;/awesomequeries/super/label&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;rsquo;s so common that we made it simpler by allowing &lt;strong&gt;DisplayName&lt;/strong&gt; to be a key and it will be used with the &lt;strong&gt;ILocalizationService&lt;/strong&gt; to return the localized display name.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;// Do this instead, if you use the LocalizationService
public override string DisplayName =&amp;gt; &quot;/awesomequeries/super/label&quot;;&lt;/code&gt;&lt;/pre&gt;</id><updated>2017-02-07T08:09:02.2370000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing Notifications in Content Approvals (Beta)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2016/12/introducing-notifications-in-content-approvals-beta/" /><id>&lt;p&gt;This feature was released as a Beta feature in CMS UI 10.3.0 and is still under development.&lt;/p&gt;
&lt;p&gt;You can read more about how you enable Beta features in &lt;a href=&quot;/link/8b4432703e44486ea1af6ddec232a8c5.aspx&quot;&gt;Fredrik Tj&amp;auml;rnbergs blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also read more about Content Approvals in &lt;a href=&quot;/link/dc12be0461b347888d55696f41729517.aspx&quot;&gt;my previous blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notifications require &lt;a href=&quot;/link/b59adfabbe504c61ad793973b05f002f.aspx&quot;&gt;WebSockets&lt;/a&gt; and &lt;a href=&quot;/link/8ead888910d54679b8952d9eeb940b6e.aspx&quot;&gt;configuring your email server&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What are Notifications?&lt;/h2&gt;
&lt;p&gt;Notifications were released as public beta in CMS 9.4.0 and is used by CMS UI 9.4.0 to show notifications related to Projects. A notification is sent instantly to the recipient and shows up in the UI in the &quot;bell icon&quot;. Any unread messages will later be emailed out to the user. In CMS 10.3.0, emails can also be sent out instantly instead of waiting for the Notification dispatcher scheduled job.&lt;/p&gt;
&lt;h2&gt;Notifications on Content Approval events&lt;/h2&gt;
&lt;p&gt;In CMS UI 10.3.0 notifications are also used to send Content Approval-related messages, and it uses the new instant emails as well.&lt;/p&gt;
&lt;p&gt;In the screenshot below, Lina has received a notification that Alfred has sent a page to be reviewed, and she is one of the approvers that should approve or decline the change.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/dbde68e43e624ff7ae23dbcbd5d44be0.aspx&quot; alt=&quot;Image blog-notifications-lina-ui.PNG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Lina also receives an email about this, as seen below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/08888dd1161f40348f2443f3a3d2a59c.aspx&quot; alt=&quot;Image blog-notifications-lina-email.PNG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Lina decides to approve the changes and since this scenario only has one step, the page is now ready to be published. In the screenshot below, Alfred is notified about this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/6a7c1c25b046453792aa9ec314e0c507.aspx&quot; alt=&quot;Image blog-notifications-alfred.PNG&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Notifications are sent when content is awaiting approval, has been approved, declined, or aborted. Those events are available on the &lt;strong&gt;ApprovalEngineEvents&lt;/strong&gt; which can be hooked into.&lt;/p&gt;</id><updated>2016-12-27T13:21:27.6330000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing Content Approvals (Beta)</title><link href="https://world.optimizely.com/blogs/john-philip-johansson/dates/2016/11/introducing-content-approvals-beta/" /><id>&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;This feature was released as a Beta feature in CMS 10.1.0 and is still under development.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;You can read more about how you enable Beta features in &lt;/span&gt;&lt;a href=&quot;/link/8b4432703e44486ea1af6ddec232a8c5.aspx&quot;&gt;Fredrik Tj&amp;auml;rnbergs&lt;/a&gt;&lt;span&gt; blog post.&lt;/span&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;What are Content Approvals?&lt;/h2&gt;
&lt;p&gt;Content approvals &lt;span&gt;is a way to make sure that content is reviewed and approved before it is published. It works as a new state (In review) between Draft and Published, which is visible in the Versions gadget. When an editor has finished working on a content item, the editor cannot publish it but has to set it as &lt;strong&gt;Ready for Review&lt;/strong&gt;. One or more appointed reviewers must then approve the content item before it can be published. The reviewers are defined by an administrator in an&lt;strong&gt; Approval Sequence&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Content approvals do not apply to blocks at this stage.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The Approval Sequence &lt;span&gt;is set up by an administrator and can have any number of approval steps and any number of approvers in each step. If the page has multiple languages there has to be at least one approver for each language in each step.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span&gt;Bonus feature: Pluggable menu items&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;The approval sequence overview is opened from the context menu in the page tree:&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/57a2dad539e94edb96ad90bcdefa2af9.aspx&quot; alt=&quot;Image Content Approval blog post - context menu.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As a part of this release, we made the context menu pluggable. So now you can &lt;a href=&quot;/link/54b2ad595a1340ada5f37300957b7934.aspx&quot;&gt;easily add items to the context menu&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;More about Content Approvals&lt;/h2&gt;
&lt;p&gt;Content Approvals work with Projects but only on a per-content basis, and not for the whole Project.&lt;/p&gt;
&lt;p&gt;The approvals can be driven through the Core API, but beware that it&#39;s also in Beta and will change a lot as we&#39;re continuing on Content Approval. Do take a look at the IApprovalEngine and IApprovalEngineEvents in the meantime. Use it to react to content moving through the sequence, or automatically reject or approve changes.&lt;/p&gt;
&lt;p&gt;You can read more about Content Approvals in the &lt;a href=&quot;http://webhelp.episerver.com/latest/cms-edit/content-approvals.htm&quot;&gt;User guide documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are more things coming with Content Approvals, but please let us know what you like or if there&#39;s anything you want us to focus on.&lt;/p&gt;</id><updated>2016-11-14T13:43:16.6600000Z</updated><summary type="html">Blog post</summary></entry></feed>