Creating dynamic Vue2 router links based on server-generated data

Currently, I am working on a Vue2 Single Page Application that fetches content from the server and allows clients to edit it in a Content Management System (CMS).

The issue I'm facing is that when a user adds a relative link such as /about-us, Vue does not recognize it as a menu item with an existing link. Instead, it reloads the entire page.

I have attempted to incorporate routing into these links by modifying the backend response. For example, changing:

<a href="/about-us">Text</a>

to:

<router-link :to="{ path: '/about-us'}">Text</router-link>

I've even created a function called parseVueLinks in an attempt to automate this process, but I still haven't been successful.

If anyone has any insights or solutions on how to properly attach a router to these links without causing a full-page reload, I would greatly appreciate the help!

Answer №1

If I'm understanding correctly, the issue you're facing isn't with link parsing—it seems to be working fine. You're looking to compile the resulting HTML so that Vue router can come into play. There's a handy function called Vue.compile that can assist you:

Vue.component('my-component', {
  template: '<div></div>',
  props: {
    html: String
  },
  mounted() {
    let { render, staticRenderFns } = Vue.compile(this.html);
    new Vue({ el: this.$el, render, staticRenderFns, router })
  }
});

Using this component, you are able to input any HTML through the html prop, which will then be compiled in the mounted event and replace the component template. It's important to note the usage of router within new Vue(), as this refers to your Vue router and is necessary for resolving all <router-link> tags within your HTML.

You can now utilize this component to compile your HTML by following this syntax:

<my-component :html="content"></my-component>

where

var content = parseVueLinks('<a href="/about-us">Text</a>')
.

To see a demonstration, check out this example on CodePen: https://codepen.io/anon/pen/BmmjwV

Answer №2

Although your replacement regex seems sound, it appears to be missing a single forward slash. Upon testing it myself, I have observed the following outcome after parsing:

<a href="/about-us">Text</a>

produces:

<router-link :to="{ path: 'about-us'}">Text</router-link>

instead of the expected:

<router-link :to="{ path: '/about-us'}">Text</router-link>

(you see about-us instead of /about-us)

Would you mind giving this a try:

function updateVueLinks($value)
{
    $pattern = "/<a([^>]*) href=\\\"[^http|https|mailto|tel]([^\\\"]*)\"([^>]*)>(.*?)<(\\/a>)/";
    $replace = "<router-link$1 :to=\"{ path: '/$2'}\">$4</router-link>";

    return preg_replace($pattern, $replace, $value);
}

Answer №3

The easiest way to accomplish this task is by using the following regex pattern:

/<a href="([^>]*)">(.+)<\/a>/
.

Test example:

console.clear() 

const parseVueLinks = ($value) => {
  const re = /<a href="([^>]*)">(.+)<\/a>/g;
  const matches = re.exec($value);
  return `<router-link :to="{ path: '${matches[1]}'}">${matches[2]}</router-link>`
}

console.log(parseVueLinks('<a href="/about-us">Text</a>'))
console.log(parseVueLinks('<a href="http://google.com">Goooooogle</a>'))


I am not familiar with PHP, but I believe the equivalent PHP code might be (tested at https://www.functions-online.com/preg_match.html):
function parseVueLinks($value)
{
  $pattern = "/<a href="([^>]*)">(.+)<\/a>/";
  $matches = [];
  preg_match($pattern, $replace, $matches);
  return "<router-link :to=\"{ path: '" + $matches[1] + "'}\">" + $matches[2] + "</router-link>"; 
}

I am curious about the inclusion of http|https|mailto|tel in your regex. Are you looking to validate the link?

If that is the case, utilizing preg_match() allows for a secondary regex step on $matches[1] before output. It might be more straightforward to validate as a separate step rather than using one comprehensive regex.


Edit the comment below

The issue does not lie in the regex itself. The problem arises from Vue's inability to interpret content retrieved from the server

This may not be applicable if you are employing server-side rendering. However, this is how I implement links from content.

MyComponent.ts

<template>
  <div class="row">
    ...
      <router-link :to="'/' + measure.link" class="measure">
        <i class="measure-icon fa fa-lg" :class="measure.icon" aria-hidden="true">
          <span class="title">{{measure.title}}</span>
        </i>
      </router-link>

In this scenario, measure represents an object fetched from the server. If you retrieve the entire <router-link>, it may work well with a Dynamic Component, but it appears to be excessive since you already "know" the element will be a <router-link.

If the server responds to clicks with a 404, you can utilize hash-mode routing (default) by adding # before the link, e.g #/about-us.

Alternatively, enable history mode in the Vue router.

const router = new Router({
  routes,
  mode: 'history'
})

For this to work, the server must redirect to index.html for a 404 error. Refer to HTML History Mode.

Additionally, you need to handle 404 errors in Vue with a catch-all route,

const routes = [
  ...
  { path: '*', component: NotFoundComponent },
]

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

Tips for sending data to a server in an object format using the POST method

Could someone kindly assist me? I am attempting to post user data in an object format, but it is not submitting in the desired way. Please, can someone help as I do not want it to create a new object. Here is how I would like it to be submitted: {"birthda ...

Discovering whether a link has been clicked on in a Gmail email can be done by following these steps

I am currently creating an email for a marketing campaign. In this email, there will be a button for users to "save the date" of the upcoming event. I would like to implement a feature that can detect if the email was opened in Gmail after the button is cl ...

Struggling to display the array after adding a new item with the push method

Seeking assistance in JavaScript as a newcomer. I have written some code to print an array once a new item is added, but unfortunately, it's not displaying the array. I am puzzled as there are no errors showing up in the console either. In my code, I ...

Utilizing jQuery to invoke a function at the conclusion of another function's execution

Can someone explain how jQuery can achieve the following? $('.test').css().otherThing...... etc I'm attempting to accomplish this with prototype: var myPrototype = function () {}; myPrototype.prototype.console1 = function() { console.lo ...

The process of filtering and outputting JSON data in JavaScript or jQuery

There is JSON data available for review. var data = [{ "gender": "male", "name": { "first": "rubween", "last": "dean" } }, { "gender": "male", "name": { "first": "rubween", "last": "dean" } }, { ...

NodeJS JSONStream causing memory exhaustion issue

I've encountered an issue while trying to stream a large JSON file (94mb in size) from an HTTP request to a local file using the JSONStream library in NodeJS. Despite setting a memory flag of 256mb with node --max-old-space-size=256 .\main.js, th ...

The variable process.env.CLIENT_ID is functioning correctly within a function, but does not work when declared as a global

Trying to implement oAuth for Google API Using .env file to hide sensitive variables with .gitignore Facing an issue when trying to define the CLIENT_ID variable globally CLIENT_ID = process.env.CLIENT_ID When I run and log the variable outside of a fun ...

Utilizing Jquery to enhance slide image transitions with navigational links

As a newcomer to jQuery, I am attempting to create a slider using jQuery. Here is the script I have so far: $(function() { var bgCounter = 0, text = [ 'some html code here', 'some html code here', 'some ...

Is it possible to send data to the server in node.js before the page is loaded?

Once a user has logged in, their data is stored on the client side. There are certain pages that can be viewed without requiring a user to log in... For instance, I have created a route on node.js which generates a profile page based on a URL parameter. ...

Can a function be embedded within a React render method that includes a conditional statement to update the state using setState()?

My application randomly selects three values from an array found within defaultProps and then displays these values inside div elements in the return JSX. It also assigns these values to properties in the state object. I am facing a challenge where I need ...

The absence of a flickering flame is noticeable in the THREE.js environment

I have been working on creating a flame using THREE.js and spark.js. However, even after rendering the world, I am unable to see the flame and it seems like the world is empty. Although I checked the console for errors, there are no indications of what mig ...

Dynamically loading Ember templates with asynchronous requests

I need a way to dynamically load HTML content from another file using the code below: App.MainView = Ember.View.extend({ template:function(){ $.ajax({ url: 'views/main.html', dataType: 'text', async: false, ...

What is the best way to iterate through a JSON file?

Looking at my JSON file: { "stats": { "operators": { "recruit1": { "won": 100, "lost": 50, "timePlayed": 1000 }, "recruit2": { "won": 200, ...

The functionality of List.js is currently not optimized for use with tables

I'm currently experimenting with list.js in order to create a real-time search feature for a table. I have successfully tested it on lists (similar to the example provided at ). However, I am facing difficulty replicating this functionality for tables ...

Display/Collapse SELECT choices?

Consider this scenario : <select class="form-control" name="blah" ng-model="$ctrl.form.blah" ng-options="item.id as item.name group by item.etype | uppercase for item in $ctrl.opts"></select> My goal is to toggle the display of each GROUP b ...

Leverage AJAX to transmit a PHP array to an external JavaScript file

I have a situation where I need to transfer an array from a PHP file to an external JavaScript file. My approach involves using AJAX as it appears to be the most suitable method for achieving this. However, when I try to use echo json_encode($exif), the JS ...

Is there a simple method to add animation to a group of images displayed on click using JQuery?

Here is my JavaScript code that I'm currently using: $(document).ready(function() { $(".button-list .next").click(function() { project = $(this).parents().filter(".projektweb").eq(0); currentimg = project.find(".im ...

`Optimizing Performance using jQuery Functions and AJAX`

As someone exploring ajax for the first time, I'm eager to learn how to write jQuery code that ensures my simple functions like slideshows and overlays still work smoothly when a page is loaded via ajax. Currently, I am implementing the following met ...

The dropdown menu is erroneously showing buttons instead of the intended options

My dropdown function is causing a small issue. The desired behavior is that if the selected value is "", labeled "Please Select" in the dropdown menu (I've added a comment in the function to pinpoint the problem), then buttons A, B, and C should not b ...

Tips for saving and accessing Shopping Cart items using localstorage

As I develop a shopping cart for an e-commerce site, I aim to utilize browser localstorage to store the products. The functions that have been added to my code include: - addToCart(): triggered when the "Add to Cart" button is clicked. - addProduct(): ...