Home > Back-end >  Vuejs How to have many <a> tags and hashtags within <router-link> or @click function
Vuejs How to have many <a> tags and hashtags within <router-link> or @click function

Time:06-18

enter image description here

i want to have a post card like twitter post card, if clicked on any part of the post card goes to post page, but when clicked on hashtags or links goes to the hashtag or link

example below 1.

<div @click="gotoPostPage" >
    {{ feed.content }}

    <a href="https://google.com">check google</a> if you need more information then follow @benny(a tag) or follow these hashtags
    #google #finda, #checks, now when i click within this post take me to post page
 
  </div>

now this hits the gotoPostPage function even if link or a tag is clicked

using this also 2.

 <router-link :to="`/post/${ feed.id }`">
    {{ feed.content }}

    <a href="https://google.com">check google</a> if you need more information then follow @benny(a tag) or follow
    these hashtags
    #google #finda, #checks, now when i click within this post take me to post page

  </router-link>

goes to even when check google is clicked

Please how can i resolve this, your help is highly appreciated, Thanks

CodePudding user response:

Add @click.stop to your links. E.g:

<a href="https://google.com" @click.stop>check google</a>

This will stop propagation of click events to the parent DOM elements.


Note: @click.stop is shorthand for @click="e => e.stopPropagation()".

Docs here.


Update, based on data shown in comment:

I would avoid storing HTML id database. That's a really bad pattern. You're supposed to detach the data from the UI layer. You have to allow the UI layer to change, based on device and medium. I'd try to store that data as strings holding a hashtag name and, where the name is different than the hastag, as on object, containing both.

Something like this:

const { createApp, reactive, computed, onMounted, toRefs } = Vue;

createApp({
  setup() {
    const state = reactive({
      items: [],
      links: computed(() => state.items.map(
        item => ({
          name: item.name || `#${item}`,
          url: item.url || `/hashtag/${item}`
        })
      ))
    });
    
    onMounted(async() => {
      /* replace this promise with an axios call to server which returns
         an array, similar to the one i'm passing here:
         (see axios call example below)
       */
      const data = await new Promise(resolve => {
        setTimeout(() => {
          resolve([
            'one',
            'two',
            'three',
            'печаль',
            'грусть',
            { 
              name: '#mens',
              url: '/hashtag/fıstıklıbaklava'
            }, 
            'чайная',
            'джаз'
          ]);
        });
      })
      // example axios call:
      /*
         const data = await axios
           .get('http://endpoint-returning-data')
           .then(({data}) => data);
      */
      state.items = data;
      console.log('See difference betwen items (received from server) \r\n\and links (same data, mapped for template):\r\n', {...state}, '\r\nMakes sense?');
    })
    return {
      ...toRefs(state),
      log: () => console.log('You clicked on app!')
    }
  }
}).mount('#app')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

<div id="app">
  <div v-for="link in links" :key="link.url" @click="log">
    <a :href="link.url"
       v-text="link.name"
       @click.stop></a>
    </div>
</div>

As you can see, it produces the HTML from the data. The template also applies the stopPropagation(), in the v-for.

  • Related