Addressing the reactivity issue when incorporating basic markdown directive into vuejs

In an effort to reduce dependency on vue-i18n formatting, I decided to create a simple Markdown formatter directive that only implements bold, emphasize, and strike-through styles. The current implementation of the directive is as follows:

    import _Vue from 'vue';
    
    const emphasize = (str: string) => {
      const matched = /(\*|_)(.*?)(\*|_)/gm;
      return str.replace(matched, '<em>$2</em>');
    };
    
    const strong = (str: string) => {
      const matched = /(\*\*|__)(.*?)(\*\*|__)/gm;
      return str.replace(matched, '<strong>$2</strong>');
    };
    
    const strikeThrough = (str: string) => {
      const matched = /~~(.*?)~~/gm;
      return str.replace(matched, '<s>$2</s>');
    };
    
    const fromMd = (str: string) => strikeThrough(emphasize(strong(str)));
    
    export default {
      install: (Vue: typeof _Vue): void => {
        /* eslint-disable no-param-reassign */
        Vue.directive('tmd', {
          bind(el: HTMLElement) {
            el.innerHTML = fromMd(el.innerHTML);
          },
          inserted(el: HTMLElement) {
            el.innerHTML = fromMd(el.innerHTML);
          },
          update(el: HTMLElement) {
            el.innerHTML = fromMd(el.innerHTML);
          },
        });
      },
    };

I have been using it like this:

<p v-tmd >{{ $t('path-to-translation', ) }}</p>

While it has been working well so far, I encountered an issue where the directive does not update when changing the language. It listens for the updated event, but the el.innerHTML does not get updated, causing it to render the old content. What is the recommended approach to address this problem?

Answer №1

It is unclear why the el.innerHTML parsing method is not working, but an alternative is to parse the text in the vnode instead:

export default {
  install: Vue => {
    const childrenTextToMd = (el, binding, vnode) => {
      if (vnode.children) {
        el.innerHTML = vnode.children
          .map(child => fromMd(child.text))
          .join('')
      }
    }

    Vue.directive('tmd', {
      inserted: childrenTextToMd,
      update: childrenTextToMd
    })
  }
}

Note: The strikeThrough() function has a replacement for $2, even though there is only one capture group, it should be $1.

See demo

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is the return type determined by the parameter type?

I need to create an interface that can handle different types of parameters from a third-party library, which will determine the return type. The return types could also be complex types or basic types like void or null. Here is a simple example demonstra ...

Unsupported Media Type: 415 Error during MultipartFile Upload

When trying to upload a file using spring boot and vue, I encountered an error '415 : Unsupported MediaType'. This is the snippet of my spring boot controller. @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}, produces = {MediaType. ...

Encountering an error in a map operation does not hinder the subsequent map operation from being carried out

Within my angular application, I have implemented a Login method that performs the following tasks: login(username, password): Observable<User> { let data = new URLSearchParams(); data.append('username', username); data.append(' ...

Ionic 4's http.get.subscribe method fails to retain the retrieved value

I'm aware this might be a repeated question, but I haven't come across a straightforward answer yet, so here it goes. Below is the code snippet in question: fetchData() { let dataArray: Array<any> = [, , ,]; this.prepareDataReque ...

The component is failing to store its value within the database

I'm encountering an problem when attempting to save an option in the database. To address this issue, I created a component in Svelte called StatePicker that is responsible for saving US States. However, when I try to save it in the database using a ...

NextJS: Error - Unable to locate module 'fs'

Attempting to load Markdown files stored in the /legal directory, I am utilizing this code. Since loading these files requires server-side processing, I have implemented getStaticProps. Based on my research, this is where I should be able to utilize fs. Ho ...

Asserting types for promises with more than one possible return value

Struggling with type assertions when dealing with multiple promise return types? Check out this simplified code snippet: interface SimpleResponseType { key1: string }; interface SimpleResponseType2 { property1: string property2: number }; inter ...

Using LitElement: What is the best way to call functions when the Template is defined as a const?

When the template is defined in a separate file, it's not possible to call a function in the component. However, if the template is defined directly as returning rendered HTML with this.func, it works. How can one call a function when the template is ...

Warning: Typescript is unable to locate the specified module, which may result

When it comes to importing an Icon, the following code is what I am currently using: import Icon from "!svg-react-loader?name=Icon!../images/svg/item-thumbnail.svg" When working in Visual Studio Code 1.25.1, a warning from tslint appears: [ts] Cannot ...

Result received from Firebase authentication sign-in

I am working on two Vue projects integrated with Firebase. The first project was set up using webpack-simple, while the second one used just webpack. I have noticed that when I call signInWithEmailAndPassword in the simple project, it only returns: {"uid" ...

What is the correct way to utilize Array.reduce with Typescript?

My current approach looks something like this: [].reduce<GenericType>( (acc, { value, status, time }) => { if (time) { return { ...acc, bestValue: valu ...

Issue with Vue.js webpack encountering problems when importing a CSS file from an external library

I'm in the process of integrating the aos animation library into my testing app. I installed it using yarn add aos, and in my Vue application, I've included the following code: <script> .... import AOS from 'aos/dist/aos.js' imp ...

The reCAPTCHA feature in Next.js form is returning an undefined window error, possibly due to an issue with

Trying to incorporate reCAPTCHA using react-hook-form along with react-hook-recaptcha is posing some challenges as an error related to 'window' being undefined keeps popping up: ReferenceError: window is not defined > 33 | const { recaptchaL ...

Verify if the date chosen falls on the current date or any upcoming date within vuejs validation

I am working on a Vue.js component that includes a form where the user needs to select a start date from a date picker. The user should only be able to choose a date that is either today's date or a future date. <div class="w-1/2 mr-2"&g ...

Ensuring type signatures are maintained when wrapping Vue computed properties and methods within the Vue.extend constructor

Currently, I am trying to encapsulate all of my defined methods and computed properties within a function that tracks their execution time. I aim to keep the IntelliSense predictions intact, which are based on the type signature of Vue.extend({... Howeve ...

An automatic conversion cannot handle spaces and prohibited characters in Object keys

The AlphaVantage API uses spaces and periods in the keys. Their API documentation is not formal, but you can find it in their demo URL. In my Typescript application, I have created data structures for this purpose (feel free to use them once we solve the ...

Unable to modify the active property of the specified object as it is read-only

Presented here is the interface: export interface ProductCommand extends ProductDetailsCommand { } This is the ProductDetailsCommand interface: export interface ProductDetailsCommand { id: string; active: boolean; archive: boolean; title: ...

Problem with z-index in VueJS: Child div z-index not functioning within v-dialog

I am facing an issue where I have brought a span to display a loading image inside the v-Dialog of a vuejs screen. The problem is that the v-dialog has a z-index of 220 set as inline style, causing my new span (loading image) to appear below the v-dialog. ...

Adding a total row to a Vuetify datatable

Struggling to incorporate a totals row using this framework, but it doesn't seem to be supported out of the box. The workaround I've come up with doesn't quite hit the mark... <v-data-table :headers="headers" :items="desserts" ...

Creating a custom theme in MUI v5 by modifying ColorPartial members

I am seeking a solution to override certain members within PaletteOptions. My goal is to switch the type of grey from ColorPartial to PaletteColorOptions in order to include additional members. This was my attempt at implementing the necessary code: decl ...