Common Vue Problems — Bootstrap, Vuex Route Restrictions, and More

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Vue.js makes developing front end apps easy. However, there are still chances that we’ll run into problems.

In this article, we’ll look at some common issues and see how to solve them.

Using Bootstrap in our App

If we only want to use the CSS from Bootstrap, then we can add the plain Bootstrap package and load the SASS files from it.

To load SASS files, we can use the sass-loader and node-sass .

To install them, we run:

npm install sass-loader node-sass --save-dev
Enter fullscreen mode Exit fullscreen mode

Then we add the path to load the SASS files in the Webpack config file:

...
sassLoader: {
  includePaths: [
    path.resolve(projectRoot, 'node_modules/bootstrap/scss/'),
  ],
},
...
Enter fullscreen mode Exit fullscreen mode

Now we can import the Bootstrap SASS file in our components:

<style lang="scss">
  @import "bootstrap";
</style>
Enter fullscreen mode Exit fullscreen mode

If we want to use the JavaScript components from Bootstrap, then we should use BootstrapVue instead.

Using SASS Resource Loader

We can add the SASS preprocessor to our vue.config.js file by writing:

module.exports = {
  css: {
    loaderOptions: {
      sass: {
        data: `
          @import "@/scss/_variables.scss";
          @import "@/scss/_mixins.scss";
        `
      }
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

There’s no need for extra dependencies since they’re included with Vue CLI projects.

Call Method in Another Component in Vue

We can’t call another component’s method directly if we aren’t calling a method from a child component in the parent.

Instead, we’ve to pass events around by adding a global Vue instance that we can use to emit and listen to events.

For instance, we can write:

window.Event = new Vue();
Enter fullscreen mode Exit fullscreen mode

to create a Vue instance.

Then we can call $emit on it by writing:

Event.$emit('createImage', item, response)
Enter fullscreen mode Exit fullscreen mode

in one component.

Then in the mounted hook on another component then we can write:

mounted() {
  Event.$on('createImage', (item, response) => {
    // ...
  }
}
Enter fullscreen mode Exit fullscreen mode

We listen to the createImage event and get the arguments that are passed into $emit in the callback parameters.

Adding Web Components in Vue Component

We can add web components in a Vue component directly.

For example, we can write:

<template id="app">
  <web-component>...</web-component>
</template>
Enter fullscreen mode Exit fullscreen mode

Given that web-component is a web component, we can include it directly.

The Limits of v-html

v-html can only be used to render plain HTML code.

We can’t render Vue components with it.

For instance, if we have a component:

Vue.component('component', {
  template: '<span>component</span>',
})
Enter fullscreen mode Exit fullscreen mode

Then we can’t have code like:

new Vue({
  el: '#app',
  data(){
    return {
      comp: '<component></component>'
    }
  }
})

...
<div id="app">
  <span v-html="comp"></span>
</div>
Enter fullscreen mode Exit fullscreen mode

This will not work because component is a component.

All data bindings and Vue components are ignored.

Instead, we have to render plain HTML:

new Vue({
  el: '#app',
  data(){
    return {
      comp: '<p>foo</p>'
    }
  }
})
...
<div id="app">
  <span v-html="comp"></span>
</div>
Enter fullscreen mode Exit fullscreen mode

That will be rendered with v-html since we have a p element.

Mount Multiple Vue Instances on Multiple Elements

If we want to attach multiple Vue instances on multiple elements, we can write:

const vues = document.querySelectorAll(".app");
[...vues].forEach((el, index) => new Vue({el, data: { message: `hello ${index}`}}))
Enter fullscreen mode Exit fullscreen mode

We get all the elements with class app .

Then we use the spread operator on vues so we can use forEach on it,

In the callback, we can create new Vue instances.

Regex in Vue Router Paths

We can use regex in Vue Router paths.

For instance, we can write:

{ path: 'item/:id(d+)', name: 'itemCard', component: ItemCard }
Enter fullscreen mode Exit fullscreen mode

Then we specified that the id parameter must be digits.

Custom Select Component that Binds to v-model

If we want to create custom select component that binds to v-model , then our component has to emit the input event and takes the value prop.

v-model is shorthand for both of those things together.

For instance:

<custom-select v-bind:value="val" v-on:input="val = $event.target.value"></custom-select>
Enter fullscreen mode Exit fullscreen mode

can be rewritten as:

<custom-select v-model="val"></custom-select>
Enter fullscreen mode Exit fullscreen mode

Then we can do anything in custom-event to emit the input event and take the value prop.

Conclusion

v-model is short for emitting the input event and taking the value property.

We can add Bootstrap SASS files with the SASS loader package.

Vue Router routes can have regex to restrict the values of parameters.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .