Mark Gibbons
Published on

Using the Vue Router on Sitecore Rich Text fields

Authors

In my Sitecore Headless (JSS) travels, I see that there is no OOTB example of how to have Sitecore RichText fields use the Vue router for internal links.

There is an example of how to do exactly this if you are using React / NextJS.

So I have here adapted that code for Vue. Please contact me if you notice any issues with it!

RouteLinkedRichText.js
export const RouteLinkedRichText = {
  props: {
    field: { type: Object, required: true },
    tag: { type: String, default: 'div' },
    editable: { type: Boolean, default: true },
  },
  render(createElement) {
    if (!this.$props.field || (!this.$props.field.editable && !this.$props.field.value)) {
      return null;
    }
    const data = {
      ...this.$data,
      domProps: { innerHTML: this.$props.field.editable && this.$props.editable ? this.$props.field.editable : this.$props.field.value },
    };

    return createElement(this.$props.tag || 'div', data);
  },
  mounted() {
    this.bindRouteLinks();
  },
  methods: {
    // handler function called on click of route links
    // pushes the click into the router thus changing the route
    routeHandler(event) {
      event.preventDefault();
      // Sometimes the event.target is an element wrapped in an anchor.
      // In those cases, the previous code would not work, as `pathname` might be undefined.
      // To fix, establish proper target.
      const target = event.target.pathname ? event.target : event.target.parentElement;

      const hash = target.hash;

      let destination = hash ? `${target.pathname}${hash}` : target.pathname;

      this.$router.push(destination);
    },
    bindRouteLinks() {
      const hasText = this.$props.field && this.$props.field.value;
      const isEditing = this.$props.editable && this.$props.field.editable;

      if (hasText && !isEditing) {
        // selects all links that start with '/' - this logic may be inappropriate for some advanced uses
        const internalLinks = this.$el.querySelectorAll('a[href^="/"]');

        internalLinks.forEach((link) => {
          // the component can be updated multiple times during its lifespan,
          // and we don't want to bind the same event handler several times so unbind first
          link.removeEventListener('click', this.routeHandler, false);
          link.addEventListener('click', this.routeHandler, false);
        });
      }
    },
  },
};

Source: gist

Usage and params are exactly like the official RichText component you get OOTB.