2

The content of my Vue app is fetched from Prismic (an API CMS). I have a rich text block, some parts of which are wrapped inside span tags with a specific class. I want to get those span nodes with Vue and add to them an event listener.

With JS, this code would work:

var selectedSpanElements = document.querySelectorAll('.className');
selectedSpanElements[0].style.color = "red"

But when I use this code in Vue, I can see that it works just a fraction of a second before Vue updates the DOM. I've tried using this code on mounted, beforeupdate, updated, ready hooks... Nothing has worked.

Update: Some hours later, I found that with the HTMLSerializer I can add HTML code to the span tag. But this is regular HTML, I cannot access to Vue methods.

Bruja
  • 368
  • 2
  • 10
  • Have you found a solution? I am working on the same issue. What I've found: 1. zero Vue functionality works because the newly rendered element seems to be rendered after Vue is finished rendering. 2. And putting the other htmlSerializer in mount, or something like that, doesn't work either because again issues with Prismic's render. – tbone May 21 '20 at 19:51
  • 1
    Hi, Tom. No, I couldn't attach a Vue method using the HTML-serializer, just plain HTML. – Bruja May 29 '20 at 14:42
  • As you can see in the comments below, the solution @Johan Baajil propose should work. But I tried it and it didn't. I don't know what did I do wrong. So I found a solution for my problems just with plain HTML and CSS. – Bruja May 29 '20 at 14:48

2 Answers2

1

@Bruja I was able to find a solution using a closure. The folks at Prismic reminded/showed me.

Of note, per Phil Snow's comment above: If you are using Nuxt you won't have access to Vue's functionality and will have to go old-school JS.

Here is an example where you can pass in component-level props, data, methods, etc... to the prismic htmlSerializer:

<template>
  <div>
    <prismic-rich-text
      :field="data"
      :htmlSerializer="anotherHtmlSerializer((startNumber = list.start_number))"
    />
  </div>
</template>
import prismicDOM from 'prismic-dom';

export default {
  methods: {
    anotherHtmlSerializer(startNumber = 1) {
      const Elements = prismicDOM.RichText.Elements;
      const that = this;

      return function(type, element, content, children) {
        // To add more elements and customizations use this as a reference:
        // https://prismic.io/docs/vuejs/beyond-the-api/html-serializer

        that.testMethod(startNumber);

        switch (type) {
          case Elements.oList:
            return `<ol start=${startNumber}>${children.join('')}</ol>`;
        }

        // Return null to stick with the default behavior for everything else
        return null;
      };
    },

    testMethod(startNumber) {
      console.log('test method here');
      console.log(startNumber);
    }
  }
};
tbone
  • 892
  • 1
  • 7
  • 17
0

I believe you are on the right track looking into the HTML Serializer. If you want all your .specialClass <span> elements to trigger a click event that calls specialmethod() this should work for you:

import prismicDOM from 'prismic-dom';

const Elements = prismicDOM.RichText.Elements;

export default function (type, element, content, children) {
  // I'm not 100% sure if element.className is correct, investigate with your devTools if it doesn't work
  if (type === Elements.span && element.className === "specialClass") {
    return `<span @click="specialMethod">${content}</span>`;
  }

  // Return null to stick with the default behavior for everything else
  return null;
};
Johan Baaij
  • 584
  • 1
  • 5
  • 15
  • Thanks, @Johan but I'm afraid this doesn't work. The `@click="specialMethod"` is attached to the span tag, but it doesn't work as Vue code, so it's not triggering the Vue method. :( – Bruja Feb 07 '20 at 21:52
  • Have you tried it? Why wouldn't it work? It just generates a template for the `prismic-rich-text` component to render. https://github.com/prismicio/prismic-vue/blob/master/src/components/RichText.js#L21 – Johan Baaij Feb 07 '20 at 22:07
  • How is the `` example from the Prismic docs any different? https://prismic.io/docs/vuejs/beyond-the-api/html-serializer – Johan Baaij Feb 07 '20 at 22:08
  • Good point, if the router link works, what you suggest also should work. But I've tried it, the `@click=method` is actually inside the span when I look for it in the DOM inspector, but it is not triggering the Vue method when I click on it. If I write the same result of the serializer (as seen in the DOM) directly into the Vue component, it does work. But if I look for it in the DOM inspector, the `@click=method` is not visible. So it seems to be different what the serializer and what Vue does to the DOM. – Bruja Feb 08 '20 at 06:50
  • 2
    Like Johan said you should be able to add vue syntax here because the vue runtime compiler checks the template. Unless your are using nuxt which doesn't have access to the vue runtime compiler. – Phil Snow May 25 '20 at 10:52