Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom link component in Vue.js?

This seems like your run-of-the-mill master/detail use case, but the examples in the Vue docs stop short of examples for this. I have a Mail Folder page (route /:mailbox_id) that displays a table of emails by Date, Subject, etc., and I want a nested route (/:message_id) that shows the email's text when the user clicks on a row.

I was able to do this in Ember (recreating this) because Ember makes a JavaScript onClick function to handle the routing and lets you set the HTML element to render, and then you just pass whatever objects to the child route.

But I'm new to Vue.js, and I've been going through the docs but can't grok how to accomplish the same thing. I can't figure out how to either create a custom link component, or how to use the built-in Vue <router-link>component (because I need it to be a <tr> instead of <a>) to both go to the child route, and pass along the contents of the message to it so it can be shown.

If it helps, here's some code:

The Router

export default new Router({
  routes: [
    {
      path: '/:id',
      name: 'mailbox',
      component: Mailbox,
      props: true,
      children: [
        {
          path: 'mail/:id',
          name: 'mail',
          component: Mail,
          props: true
        }
      ]
    }
  ]
})

Component: Mailbox.vue

<template>
  <div>
    <table>
      <tr>
        <th>Date</th>
        <th>Subject</th>
        <th>From</th>
        <th>To</th>
      </tr>
      <Mail-List-Item v-for="message in messages" :key="message.id" v-bind:message="message"/>
    </table>
    <router-view></router-view>
  </div>
</template>

<script>
  import MailListItem from './Mail-List-Item'

  export default {
    components: { 'Mail-List-Item': MailListItem },
    name: 'Mailbox',
    props: ['messages']
  }
</script>

Component: Mail.vue

<template>
  <div class="mail">
    <dl>
      <dt>From</dt>
      <dd>{{mail.from}}</dd>
      <dt>To</dt>
      <dd>{{mail.to}}</dd>
      <dt>Date</dt>
      <dd>{{messageDate}}</dd>
    </dl>
    <h4>{{mail.subject}}</h4>
    <p>{{mail.body}}</p>
  </div>
</template>

<script>
export default {
  props: ['message', 'messageDate']
}
</script>

Component: Mail-List-Item.vue

<template>
    <V-Row-Link href="mail" mailid="message.id" message="message">
      <td>{{messageDate}}</td>
      <td>{{message.subject}}</td>
      <td>{{message.from}}</td>
      <td>{{message.to}}</td>
    </V-Row-Link>
</template>

<script>
  var moment = require('moment')
  import VRowLink from './V-Row-Link'

  export default {
    name: 'Mail-List-Item',
    props: ['message'],
    components: { VRowLink },
    data: function () {
      return {messageDate: moment(this.message.date).format('MMM Do')}
    }
  }
</script>

Component: V-Row-Link.vue (much of this copied from this repo)

<template lang="html">
  <tr
    v-bind:href="href"
    v-on:click="go"
    >
      <slot></slot>
  </tr>
</template>

<script>
import routes from '../Router'

export default {
  props: ['href', 'mailid', 'message'],
  methods: {
    go (event) {
      this.$root.currentRoute = this.href
      window.history.pushState(
        null,
        routes[this.href],
        this.href
      )
    }
  }
}
</script>
like image 652
redOctober13 Avatar asked Dec 23 '22 18:12

redOctober13


1 Answers

Router link takes a tag attribute, that you can use to turn it into any element you like. An example would be...

<router-link tag="tr" :to="'/messages/' + MAIL_ID">{{ MAIL_TITLE }}</router-link>
like image 59
NotABlueWhale Avatar answered Dec 29 '22 06:12

NotABlueWhale