Simple Vue.js component, where you can add a wrestler via an AJAX endpoint, and remove a wrestler from an AJAX endpoint.
Any notes on whether I’m doing this the “Vue.js way” or tips for improvement are greatly welcomed.
The HTML template portion of the component:
<template>
<div>
<p v-if="loading">Loading…</p>
<div v-else>
<ul class="list-inline">
<li class="list-inline-item" v-for="(wrestler, index) in wrestlersSortedByName" v-bind:key="wrestler.id">
<button type="button" class="btn btn-outline-danger" v-on:click.prevent="removeWrestler(wrestler, index)">
<span class="btn-text">{{ wrestler.name }}</span>
<span class="btn-icon" aria-hidden="true">×</span>
</button>
</li>
</ul>
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" autocomplete="name" required ref="name" v-bind:disabled="busy" v-model="name" v-on:keydown.enter.prevent="addWrestler" />
<div class="input-group-btn">
<button type="button" class="btn btn-primary" v-on:click.prevent="addWrestler" v-bind:disabled="busy">
<span class="btn-text" v-html="submitText" />
</button>
</div>
</div>
</div>
</div>
</div>
</template>
The JavaScript portion of the component:
const confirm = require('./../mixins/confirm.js');
export default {
computed: {
submitText() {
return this.busy ? 'Submitting…' : 'Add wrestler';
},
wrestlersSortedByName() {
return this.wrestlers.sort((a, b) => {
return a.name.localeCompare(b.name);
});
}
},
data() {
return {
busy: false,
loading: true,
name: '',
wrestlers: []
};
},
methods: {
addWrestler() {
this.busy = true;
axios.post(this.action, { name: this.name })
.then((response) => {
this.wrestlers.push(response.data.data);
})
.catch((response) => {
alert('Error adding wrestler to video.');
})
.then(() => {
this.busy = false;
this.name = '';
this.$refs.name.focus();
});
},
loadWrestlers() {
axios.get(this.action).then((response) => {
this.wrestlers = response.data.data;
this.loading = false;
});
},
removeWrestler(wrestler, index) {
const message = `Are you sure you wish to remove ${wrestler.name} from this video?`;
this.confirm(message, () => {
axios.delete(`${this.action}/${wrestler.id}`)
.then((response) => {
this.wrestlers.splice(index, 1);
})
.catch((response) => {
alert('Error removing wrestler.');
});
});
}
},
mixins: [
confirm
],
mounted() {
this.loadWrestlers();
},
props: {
action: {
required: true,
type: String
}
}
}
And finally, the contents of ./mixins/confirm.js:
module.exports = {
methods: {
confirm(message, callback) {
if (window.confirm(message)) {
callback();
}
}
}
};
Style notes: I’m aware of the @
shorthand for v-on:
, but prefer the longer form as it looks more HTML-y to me.
this.action
is a URL, i.e.http://example.com/videos/1/wrestlers
, so is just a string. \$\endgroup\$data
andprops
properties \$\endgroup\$data
key! \$\endgroup\$