I have a vue2 component, where some methods are pretty long with a lot of callbacks and I would like to structurize it better. I try to follow the guidelines as per callbackhell.com but things don't look that easy within vue method.
Below is the sample of where I am at the moment, it works, but I am confused about the following:
Function hoisting doesn't seem to work here, I need to define my functions first before I run them otherwise, it triggers an error. Why is that, am I missing something here?
When I define inner functions like this, I lose the "this" bound to Vue component in them. I fix it by the .bind(this)
after the function definition, it works but looks rather obscure. Is there any better way to define a utility function within methods while still keeping the context of "this"?
Is this generally adding functions into method a good approach in Vue? I know I could make them sibling methods directly in methods: {}
object and that resolves most of my issues, but as they are only relevant to the saveFavourites()
method and not to anything else in the component, wrapping them within looks cleaner to me?
Thanks so much
methods: {
saveFavourites() {
var promptName = function() {
return this.$swal({
text: 'Enter name'),
content: 'input',
button: {
text: 'Save'),
closeModal: true,
},
})
}.bind(this);
var storePlan = function(name) {
if(!name || (name = name.trim()) === '' ) return;
axios.post('/api/user-store-daily-favourites', { meals: this.mealIds, name: name })
.then(response => {
if(response.data.status === 'success') {
this.$emit('dailyFavouritesUpdated');
}
});
}.bind(this);
// running it - if I move this above functions definitions, I get error
promptName()
.then( (name) => storePlan(name) );
},
For question 1, hoisting only applies to function declarations, not function expressions. Compare:
// Expression
var promptName = function() {
to:
// Declaration
function promptName() {
For further reading see:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
For question 2, using bind
is fine but you may find it easier to use arrow functions instead, which preserves the surrounding this
value.
var promptName = () => {
return this.$swal({
...
})
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
For question 3, that seems like a matter of personal preference but generally I would move them to separate Vue methods
. You have the usual trade offs to consider. Perhaps you feel the indirection is too high a price to pay and you'd rather keep all the code in one place. That's fine.
In this specific case I suggest you look into async
/await
instead of using all those extra functions. However, a word of caution, make sure you understand promises well before trying to use async
/await
as most problems with async
/await
come from not understanding the underlying mechanism used to implement it.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
The async
/await
version would look something like this:
async saveFavourites() {
const name = await this.$swal({
text: 'Enter name',
content: 'input',
button: {
text: 'Save',
closeModal: true,
},
});
if(!name || (name = name.trim()) === '' ) return;
const response = await axios.post('/api/user-store-daily-favourites', {
meals: this.mealIds,
name: name
});
if(response.data.status === 'success') {
this.$emit('dailyFavouritesUpdated');
}
}