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.
<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".
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
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.
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"
.
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/
Comments