John-Philip Johansson
Oct 31, 2018
  7334
(10 votes)

Tips and tricks for a great On-Page Editing experience in SPAs and other client side rendered sites

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. Beta features

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 series of blog posts. Don't be discouraged that the SPA is written in Vue.js if you're using React, Angular, or something else, as these concepts will work in any client side framework.

Introducing a new SPA template site: MusicFestival

When creating a SPA, you are no longer bound by certain limitations on a server side rendered site, but it'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.

A more in-depth look at what you need to think about when doing client side routing is available in this blog: Routing in a SPA with a working On-Page Editing experience (CMS UI 11.11.0).

This blog will instead focus on examples on what you can do with your site to improve the editors On-Page Editing (OPE) experience.

In CMS UI 11.11.0, we introduce some useful properties on the injected epi.beta property. In the template, we make them available to all components as $epi, which is a Vue.js instance property. You'll see it used throughout the examples.

Routing links vs edit links

As is mentioned in the routing blog, you will want to render different HTML depending on if you're in edit mode or view mode. To simplify this, we created a Link component that does this.

<template>
    <!-- Editmode -->
    <a v-if="$epi.inEditMode" :href="url">
        <slot></slot>
    </a>

    <!-- Viewmode -->
    <router-link v-else :to="url">
        <slot></slot>
    </router-link>
</template>

<slot> allows child components to be passed by the parent component. See Vue.js docs

See the full source for the EpiLink.vue component [here]( https://github.com/episerver/musicfestival-vue-template/blob/master/src/MusicFestival.Vue.Template/Assets/Scripts/components/widgets/EpiLink.vue).

Disabling links in OPE

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 ViewModeLink 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't interactive or clickable.

Disabling links in OPE

<template>
    <router-link :class="{ 'edit-mode': $epi.inEditMode }" :to="url">
        <slot></slot>
    </router-link>
</template>

<style lang="less" scoped>
    .edit-mode {
        pointer-events: none;
    }
</style>

See the full source for the EpiViewModeLink.vue component here.

Editing a visible property

To make an element editable in OPE, you can add certain attributes to the HTML, such as <span data-epi-property-name="Name">. Information regarding those attributes can be found in our Developer guides.

As with @Html.EditAttributes(), available in ASP.NET Razor views, these attributes should not be rendered for the site visitor in view or preview modes.

To make this more convenient, we created a custom Vue.js directive (an element property) called v-epi-edit that will add all required attributes to any element using that directive. It's also possible for a component to disable the editing features by having the property epiDisableEditing set to false. We will show a useful scenario in the section "Hiding overlays when they interfere with new overlays due to user interactions".

Edit visible property

Using it is straightforward:

<!-- This Vue.js code: -->
<h1 v-epi-edit="'ArtistName'">{{model.artistName}}</h1>

<!-- Becomes ths HTML code: -->
<h1 data-epi-property-name="ArtistName" data-epi-property-render="none" data-epi-property-edittype="floating">...</h1>

Its implementation is quite simple too:

function toggleEditAttributes(el, binding, vnode) {
    const siteIsEditable = vnode.context.$epi.isEditable;
    const componentIsEditable = !vnode.context.epiDisableEditing;

    if (siteIsEditable && componentIsEditable) {
        setEditAttributes(el, binding);
    } else {
        removeEditAttributes(el);
    }
}

You can see the implementation in epiEdit.js.

Editing a non-visible or hard to click property

Edit non-visible property

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 <button> when the page is editable.

These elements should not be rendered for the site visitor, in view or preview modes.

<template>
    <button v-if="$epi.isEditable" v-epi-edit="propertyName">Edit property: {{propertyName}}</button>
</template>

Note that it uses the EpiEdit directive to be editable.

See the full source for the EpiProperty.vue component here.

Hiding overlays when they interfere with new overlays due to user interactions

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's editable properties have their editing features disabled in those cases, so the overlays don't fight for the user's attention.

Hiding selected overlays

If you recall the v-epi-edit directive (the custom attribute) introduced in the section "Editing a visible property", it allows the element it's on to disable editing by setting the property epiDisableEditing to true. You can see it used indirectly on the Title in the Hero component:

<template>
    <h1 v-epi-edit="'Title'" v-html="title"></h1>
</template>

<script>
export default {
    computed: {
        epiDisableEditing() {
            return this.$app.modalShowing;
        }
    }
};
</script>

See the full source for the Hero.vue component here.

The v-epi-edit directive will read the epiDisableEditing value set by Hero and disable the overlays when the site's modal is showing.

Set minimum size for editing overlays

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 data-epi-property-render="none".

Setting minimum size on empty overlay

You can set your own minimum size by overriding the selector [data-epi-property-name]. The injected CSS is:

[data-epi-property-name] {
    min-height: 14px;
    min-width: 18px;
}

Related links

Template site using the techniques discussed in this blog: https://github.com/episerver/musicfestival-vue-template/

Documentation on client side rendering in Episerver: https://world.episerver.com/documentation/developer-guides/CMS/editing/on-page-editing-with-client-side-rendering/

Oct 31, 2018

Comments

Please login to comment.
Latest blogs
ExcludeDeleted(): Prevent Trashed Content from Appearing in Search Results

Introduction In Optimizely CMS, content that is moved to the trash can still appear in search results if it’s not explicitly excluded using the...

Ashish Rasal | Nov 7, 2024

CMS + CMP + Graph integration

We have just released a new package https://nuget.optimizely.com/package/?id=EPiServer.Cms.WelcomeIntegration.Graph which changes the way CMS fetch...

Bartosz Sekula | Nov 5, 2024

Block type selection doesn't work

Imagine you're trying to create a new block in a specific content area. You click the "Create" link, expecting to see a CMS modal with a list of...

Damian Smutek | Nov 4, 2024 | Syndicated blog

.NET 8 FAQ

I have previously written about .NET compatibility in general and .NET 8 in particular, see blog posts here , here and here . With the end of suppo...

Magnus Rahl | Nov 4, 2024

Dynamic packages in Commerce Connect

In Optimizely Commerce Connect, you can group different items using packages and bundles. Package: A package has one or more versions of a product...

K Khan | Nov 1, 2024

Efficient Catalog Metadata Management and Product Updates Using DTOs in Optimizely Commerce

This post explores ways to manage and update catalog metadata in Optimizely Commerce by utilizing Data Transfer Objects (DTOs). DTOs provide a...

Sujit Senapati | Oct 31, 2024