Vue.js component for adding/removing items 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:

&lt;template&gt;
    &lt;div&gt;
        &lt;p v-if="loading"&gt;Loading&amp;hellip;&lt;/p&gt;
        &lt;div v-else&gt;
            &lt;ul class="list-inline"&gt;
                &lt;li class="list-inline-item" v-for="(wrestler, index) in wrestlersSortedByName" v-bind:key="wrestler.id"&gt;
                    &lt;button type="button" class="btn btn-outline-danger" v-on:click.prevent="removeWrestler(wrestler, index)"&gt;
                        &lt;span class="btn-text"&gt;{{ wrestler.name }}&lt;/span&gt;
                        &lt;span class="btn-icon" aria-hidden="true"&gt;&amp;times;&lt;/span&gt;
                    &lt;/button&gt;
                &lt;/li&gt;
            &lt;/ul&gt;
            &lt;div class="form-group"&gt;
                &lt;div class="input-group"&gt;
                    &lt;input type="text" class="form-control" autocomplete="name" required ref="name" v-bind:disabled="busy" v-model="name" v-on:keydown.enter.prevent="addWrestler" /&gt;
                    &lt;div class="input-group-btn"&gt;
                        &lt;button type="button" class="btn btn-primary" v-on:click.prevent="addWrestler" v-bind:disabled="busy"&gt;
                            &lt;span class="btn-text" v-html="submitText" /&gt;
                        &lt;/button&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/template&gt;


The JavaScript portion of the component:

const confirm = require('./../mixins/confirm.js');

export default {
    computed: {
        submitText() {
            return this.busy ? 'Submitting&amp;hellip;' : 'Add wrestler';
        },
        wrestlersSortedByName() {
            return this.wrestlers.sort((a, b) =&gt; {
                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) =&gt; {
                    this.wrestlers.push(response.data.data);
                })
                .catch((response) =&gt; {
                    alert('Error adding wrestler to video.');
                })
                .then(() =&gt; {
                    this.busy = false;
                    this.name = '';
                    this.$refs.name.focus();
                });
        },
        loadWrestlers() {
            axios.get(this.action).then((response) =&gt; {
                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, () =&gt; {
                axios.delete(`${this.action}/${wrestler.id}`)
                    .then((response) =&gt; {
                        this.wrestlers.splice(index, 1);
                    })
                    .catch((response) =&gt; {
                        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.
It looks like the code makes good use of basic VueJS concepts and practices- using computed properties, binding values, conditional display with v-if, etc.

I also like the application of arrow functions, promise handling, etc.

I see there is a key attribute bound to the list items (i.e. v-bind:key="wrestler.id"). Correct me if I am wrong but that doesn't appear to be an attribute of &lt;li&gt;. What is that used for? Edit: Oh yes, thanks for reminding me about the key attribute for list editing

Then in the addWrestler() method, there are two .then() callbacks. Is there a reason not to move the three lines in the second callback into the first?

axios.get(this.action, { name: this.name })
    .then((response) =&gt; {
        this.wrestlers.push(response.data.data);
        this.busy = false;
        this.name = '';
        this.$refs.name.focus();
    })
    .catch(...)


If you really wanted to shorten the code for the promise callbacks, you could abstract those into methods.