Reputation: 597
I have list of months and I want to retrieve from the API the appointments for each of those months on click. What I have now:
HTML
<div class="months">
<a v-on:click="retrieveCalendar(index + 1, currentYear, month)" v-bind:class="{active : month.isActive}" v-for='(month, index) in months'>{{ month.name }}</a>
</div>
JS
methods: {
retrieveCalendar: function(month, year, object = []) {
axios.get('api/calendar/' + year + '/' + month + '/1').then(response => (this.days = response.data));
}
}
This works, but is abysmal. I need lots of other stuff to happen in that method, like for example - change the isActive
parameter.
I am also calling this method in create()
in order to call the initial set of events - is that the right approach?
Is there a way to use computed properties to watch year
and month
and if they are changed to fire the retrieveCalendar
method? Or should I be using method
at all or should I move this somehow to a computed property? Or is there another hundreth way for this to be done properly?
Upvotes: 1
Views: 1783
Reputation: 520
By simply saving the index on click, you make all the required data available without passing arguments to the retrieveCalendar
method.
isActive
As you can see below, this also makes it so we don't even need an isActive
property. In the class binding, you can simply compare the active index against the current index.
retrieveCalendar
when year
and month
ChangeThis is what Vue watchers are for. Since you're calling the same method multiple times, and you already have the method, it's most efficient to register the watcher as a string of the method name.
$vm#create()
Is this correct? Yes. Is there a better way? Yes.
By passing an object with the property immediate: true
to a Vue watcher, you can skip the #create()
call. Vue will call it on the create hook for you.
The catch is that this is an undocumented Vue API and it might confuse someone else reading your code.
Several of the above tricks were learned here: https://www.youtube.com/watch?v=7YZ5DwlLSt8
let app = new Vue({
el: '#app',
data: _ => ({
activeMonthIndex: new Date().getMonth(),
currentYear: new Date().getYear(),
months: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
}),
methods: {
retrieveCalendar () {
let month = this.activeMonthIndex + 1;
let year = this.currentYear;
let object = this.months[this.activeMonthIndex];
return console.log(
`I don't actually have access to your API...`
);
axios.get(
'api/calendar/' +
year +
'/' +
month +
'/1'
).then(response => {
this.days = response.data
});
}
},
watch: {
activeMonthIndex: {
handler: 'retrieveCalendar',
/*
`immediate: true` ensures that this method
will run on create, as well as when the watched
property changes.
*/
immediate: true
},
currentYear: 'retrieveCalendar'
}
});
body{background:linear-gradient(135deg,#42e695 0,#3bb2b8 100%);font-family:futura,helvetica;background-repeat:no-repeat;height:100vh;width:100%;padding:2px}a{transition:all 500ms ease-out;display:inline-flex; margin: 5px;background:#FAFAFA;padding:20px;border-radius:5px;box-shadow:0 20px 50px -10px rgba(0,0,0,.2)}h1{color:#fff;text-shadow:0 2px 5px rgba(0,0,0,.2)}a:hover{transform:translateY(-2px);cursor:pointer;}a.active{filter:invert(100%)}.months{display:flex;flex-direction: column wrap;flex-wrap:wrap;justify-content:flex-start;align-items: flex-end;}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<p v-if="activeMonthIndex != -1">
Loading Calendar for {{ months[activeMonthIndex] }}...
(not really it's just a demo)
</p>
<div class="months">
<a
v-for='(month, index) in months'
@click="activeMonthIndex = index"
:class="{active : index == activeMonthIndex }"
>
{{ month }}
</a>
</div>
</div>
Upvotes: 2