Solving Common Vue Problems — Images, Calling Child Methods, and More
By: John Au-Yeung
Tags: JavaScript, Software Development, Programming, Technology, Web Development

Photo by John Torcasio on Unsplash

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.

Dynamic Images not Working

If we add an image with require , then we can get them working with a method:

getImgUrl(pic) {

return require(`../assets/${pic}`)

}

Then we can use it in our template by writing:

<img :src="getImgUrl(pic)" :alt="pic">

We return the image we want to require in the getImgUrl method and then pass the returned object straight into the value of src .

Avoid Mutating Props Directly

We should never mutate props directly.

It’s an antipattern since props are rendered after the local changes to the props are overwritten.

Therefore, if we have props, then we either set a default value for them.

Or we can use a computed property to create new value from the props.

For instance, we can write:

Vue.component('task', {

template: '#template',

props: ['list'],

data() {

return {

mutableList: Object.assign({}, this.list);

}

}

});

or we can write:

Vue.component('task', {

template: '#template',

props: ['list'],

computed: {

newList(){

return this.list;

}

}

});

We made a copy of the list prop value with Object.assign({}, this.list); in the first example.

In the 2nd example, we created a computed property newList with:

computed: {

newList(){

return this.list;

}

}

Return Promises from Async Vuex Actions

Actions are asynchronous. Therefore, we can return promises in them.

For instance, we can write:

actions: {

async getData(context, data) {

const res = await fetch("/api/something")

const json = await res.json();

return json;

}

}

We returned a promise returned by the Fetch API to get data.

Then we can dispatch the actions with this.store.$dispatch in our component by writing:

async mounted() {

try {

const data = await this.$store.dispatch("getData")

} catch (ex) {

console.log(ex);

}

}

Detect Click Outside an Element

We can detect clicks outside an element by creating our own directive.

For instance, we can write:

Vue.directive('click-outside', {

bind () {

this.event = event => this.vm.$emit(this.expression, event)

this.el.addEventListener('click', this.stopProp)

document.body.addEventListener('click', this.event)

},

unbind() {

this.el.removeEventListener('click', this.stopProp)

document.body.removeEventListener('click', this.event)

}, stopProp(event) { event.stopPropagation() }

})

We call stopPropgation when the element is clicked to stop the click event from propagating to parent elements.

This is what’s done in the bind method.

When we unbind the directive, we remove all the listeners to stop the proportion of events.

Then we can use it by writing:

<div v-click-outside="doSomething">

...

</div

We used our directive to run doSomething when we click outside our element.

Setting Data with Axios

To set data with Axios, we have to make sure that our then callback is an arrow function.

For example, we write:

mounted() {

axios.get('api/url')

.then((response) => {

this.data = response.data;

});

}

If we use a regular function, then the value of this would be the function itself.

So we can’t use regular functions as callbacks.

Alternatively, we can use the async/await syntax by writing:

async mounted() {

consr res = await axios.get('api/url')

this.data = res.data;

}

Watch for Nested Data

We can watch for nested data in a few ways.

We can add watchers for nested properties by writing:

watch:{

'item.prop1'(newVal){

//...

},

'item.prop2'(newVal){

//...

}

}

We watch item.prop1 and item.prop2 with 2 watchers that have the property path as the keys.

Also, we can set the deep property to true to watch its value.

For example, we can write:

watch: {

item: {

handler(val){

// ...

},

deep: true

}

}

Then all nested properties are watched since deep is set to true .

handler will run when any nested property of item changes.

Call Vue Component Methods Outside a Component

To call a Vue component method outside a component, we can set a ref on it and then call the method by accessing the ref.

For instance, if we have a component called Foo , we can set a ref on it by writing:

<Foo ref="foo"></Foo>

Then we can write:

this.$refs.foo.doSomething();

if the Foo component has the doSomething method.

Photo by Jan Meeus on Unsplash

Conclusion

We should avoid mutating prop values directly.

The value of them will be overwritten on the next render.

Also, we can detect clicks from the outside by stopping the propagation of click event to the parent.

We can also call methods of a child component from the component with refs.