Categories
Vue Answers

How to Pass Down Vue Component Slots Inside Wrapper Component?

Sometimes, we want to pass down Vue component slots in a wrapper component.

In this article, we’ll look at how to pass down Vue component slots in a wrapper component.

How to Pass Down Vue Component Slots Inside Wrapper Component

To pass down slots in a wrapper component, we can loop through all the slots and pass them down to the child.

For instance, we can write:

<wrapper>
  <parent-table v-bind="$attrs" v-on="$listeners">

    <slot v-for="slot in Object.keys($slots)" :name="slot" :slot="slot"/>

    <template v-for="slot in Object.keys($scopedSlots)" :slot="slot" slot-scope="scope">
      <slot :name="slot" v-bind="scope"/>
    </template>

  </parent-table>
</wrapper>

We get the slots with the $slots variable.

Then we use Object.keys to get names of the slots so that we can loop through all of them and pass the name down.

Likewise, we can loop through the scoped slots with the $scopedSlots variables.

We get the keys the same way and loop through them with v-for the same way.

With Vue 2.6, the v-slot= directive is introduced to let is pass the slots down.

For instance, we can write:

<wrapper>
  <parent-table v-bind="$attrs" v-on="$listeners">
    <template v-for="(_, slot) of $scopedSlots" v-slot:[slot]="scope">
      <slot :name="slot" v-bind="scope"/>
    </template>
  </parent-table>
</wrapper>

We loop through the slot with v-for .

We get the scoped slots with the $scopedSlots variable.

slot is the slot name again.

This time, we pass it to the v-slot directive as a modifier to pass down the named slot.

scope has the scope from the scoped slot.

We use v-bind to get the scope.

And we

Alternatively, we can use render function to pass down the slots.

For instance, we can write:

render(h) {
  const children = Object.keys(this.$slots)
    .map(slot => h('template', { slot }, this.$slots[slot]))

  return h('wrapper', [
    h('parent-table', {
      attrs: this.$attrs,
      on: this.$listeners,
      scopedSlots: this.$scopedSlots,
    }, children)
  ])
}

We get the slots with the this.$slots property.

We call Object.keys to get the slot names.

And we call map on it to map the slot names to the template components.

And we pass in the slots name and the scope down,.

Then we return a wrapper component with the parent-table component with the listeners, attributes, and scoped slots and children as the children.

Conclusion

To pass down slots in a wrapper component, we can loop through all the slots and pass them down to the child.

Categories
Vue Answers

How to Redirect to Requested Page After Login Using Vue Router?

Sometimes, we want to redirect to a request page after login with Vue Router.

In this article, we’ll look at how to a request page after login with Vue Router.

Redirect to Requested Page After Login Using Vue Router

We can add a redirect path to the query parameter when redirecting to the login page.

For instance, we can write:

onClick() {
  if (!isAuthenticated) {
    this.$router.push({ name: 'login', query: { redirect: '/profile' } });
  }
}

We check for authentication credentials.

If they aren’t present, then we call this.$router.push to redirect to the route for the login page.

The query property has the path to redirect to when login is successful.

We have a query string with the redirect key and the /profile value.

Then in our login form component, we can write:

submitForm() {
  login(this.credentials)
    .then(() => this.$router.push(this.$route.query.redirect || '/'))
    .catch(error => {
       //...
    })
}

in the methods property.

We call login which returns a promise.

So we can call then with a callback to redirect to the path in the query string.

We get that path with the this.$route.query.redirect property.

Then we call this.$router.push to do the redirect.

In case it’s not defined, we redirect to the / route.

Conclusion

We can add a redirect path to the query parameter when redirecting to the login page.

Categories
Vue Answers

How to Fire an Event When v-model Changes?

Sometimes, we want to fire an event when the v-model value changes.

In this article, we’ll look at how to fire an event when the v-model value changes.

Fire an Event When v-model Changes

We can add a change event listener to our input to listen for input value changes.

For instance, we can write:

<input
  type="radio"
  name="option"
  value=""
  v-model="status"
  v-on:change="onChange"
>

onChange is the name of the change event handler.

We can also replace v-on: with @ for short:

<input
  type="radio"
  name="option"
  value=""
  v-model="status"
  @change="onChange"
>

Also, we can add a watcher for our model property instead of attach a change event listener.

For instance, we can write:

new Vue({
  el: "#app",
  data: {
    status: ''
  },
  watch: {
    status(val, oldVal) {
      console.log(val, oldVal)
    }
  }
});

With the watch property, we added a watcher for the status variable as indicated by the name.

val has the current value and oldVal has the old value.

Conclusion

We can add a change event listener to our input to listen for input value changes.

Categories
Vue Answers

How to Force Download with GET Request using Axios?

Sometimes, we want to download files from responses made with GET requests.

In this article, we’ll look at how to download files from responses made with GET requests.

Force Download with GET Request using Axios

We can make the response always download by passing our response data into the Blob constructor.

For instance, we can write:

axios
  .get(`download-pdf`, {
    responseType: 'arraybuffer'
  })
  .then(response => {
    const blob = new Blob(
      [response.data],
      { type: 'application/pdf' }
    ),
    const url = window.URL.createObjectURL(blob);
    window.open(url) ;
  })

We make a GET request to the download-pdf endpoint to download our PDF.

We make sure that we specify that the responseType is 'arraybuffer' to indicate that it’s a binary file.

Then in the then callback, we get the response parameter, which has the data we want in the data property.

We pass that into the Blob constructor in an array.

And we specify the MIME type of the response data.

Then we create the URL that lets us download the file with createObjectURL .

Finally, we call window.open with the url to download the file.

We can also specify the file name of the downloaded file by making a small change in the then callback.

To do that, we write:

axios
  .get(`download-pdf`, {
    responseType: 'arraybuffer'
  })
  .then(response => {
    const blob = new Blob(
      [response.data],
      { type: 'application/pdf' }
    ),
    const link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = "file.pdf";
    link.click();
  })

Instead of creating an object URL directly, we create an invisible link first and set the file name as the download property of it.

Then we call click to download it.

Conclusion

We can make the response always download by passing our response data into the Blob constructor.

Categories
Vue Answers

How to Share a Method Between Components in Vue?

Sometimes, we want to share methods between components in our Vue project.

In this article, we’ll look at how to share methods between components in our Vue project.

Share a Method Between Components in Vue

To share a method between components in Vue, we can create a module that exports the method.

For instance, we can write:

src/shared.js

export default {
  bar() {
    alert("bar")
  }
}

Then we can use it in our component by writing:

src/App.js

<template>...</template>

<script>
import shared from './shared'

export default {
  created() {
    shared.bar();
  }
}
</script>

We imported the shared module and called the bar method inside it.

Alternatively, we can create a mixin, which is a piece of code that can be merged into our component.

For instance, we can write:

const cartMixin = {
  methods: {
    addToCart(product) {
      this.cart.push(product);
    }
  }
};

Then we can use it in our component by writing:

const Store = Vue.extend({
  template: '#app',
  mixins: [cartMixin],
  data(){
    return {
      cart: []
    }
  }
})

We call Vue.extend to create a subclass of the Vue constructor.

We can then make a new instance of Store and render that in our app.

Conclusion

To share a method between components in Vue, we can create a module that exports the method.