Full Calendar Vue JS Component - Adding Events - vue.js

I'm using Full Calendar with Vue JS: https://fullcalendar.io/docs/vue
I can't seem to find a way to add events using the Full Calendar Vue JS component. The only way I see the examples doing it is by getting ahold of the calendar's API and creating events through it. This seems a little anti-vue.
Demo from docs:
handleDateSelect(selectInfo) {
let title = prompt('Please enter a new title for your event')
let calendarApi = selectInfo.view.calendar
calendarApi.unselect() // clear date selection
if (title) {
calendarApi.addEvent({
id: createEventId(),
title,
start: selectInfo.startStr,
end: selectInfo.endStr,
allDay: selectInfo.allDay
})
}
}
I'm wondering, is the only way to create an event on the Vue JS Full Calendar by tapping into the calendars native API as shown above? Are there no means of sending an event of sorts into the component?

You don't really have to fallback to using imperative instance API. The Vue FullCalendar components exposes the events as part of the options which you can use. For example:
<template>
<FullCalendar :options="opts" />
<button #click="addNewEvent"></button>
</template>
In the component definition, you can use the events key to set list of events declaratively. Every time, you need to add/remove the events just modify the events key which is part of your options object.
export default {
data() {
return {
opts: {
plugins: [ /* Any addition plugins you need */ ],
initialView: 'dayGridMonth',
events: [
{ title: 'First Event', date: '2021-05-12' },
/* Few more initial events */
]
}
}
},
methods: {
addNewEvent() {
this.opts.events = [
...this.opts.events,
{ title: 'Another Event', date: '2021-05-13' }
];
}
}
}

Related

How to use (getEventById) with Vue FullCalendar

I want to remove element with Event id in vue fullcalnder but i dont know how i can do it.
with jquery it is easy but i dont know how to use it, it have in documentation but i dont know how i can use it with vuejs (https://fullcalendar.io/docs/Calendar-getEventById).
i try much thing but same result!
this.$refs.calendar.$emit('getEventById',4).remove()
this.$refs.calendar.fireMethod().getEventById(4).remove()
thanks for help.
If you look at the section called "Accessing FullCalendar’s API" in the documentation at https://fullcalendar.io/docs/vue it shows how to get an instance of the calendar object from which you can call methods.
The example it shows is:
let calendarApi = this.$refs.fullCalendar.getApi()
calendarApi.next()
You can just swap next() for the method you want to call. So in your case it might be something like:
let calendarApi = this.$refs.fullCalendar.getApi()
let event = calendarApi.getEventById(4)
event.remove();
events is managed with data model and events is manipulated to update view.
It is not necessary to use the api of FullCalendar.
Try this.
<button #click="removeId">Remove</button>
<FullCalendar
ref="calendar"
defaultView="dayGridMonth"
:plugins="calendarPlugins"
:events="eventsData"
/>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
export default {
components: {
FullCalendar
},
data () {
return {
eventsData : [
{ id: 1, title: 'event 1', date: '2019-04-01' },
{ id: 2, title: 'event 2', date: '2019-04-02' }
],
calendarPlugins: [ dayGridPlugin ]
}
},
methods: {
removeId () {
let id = 1
let index = this.eventsData.findIndex(e => e.id === id)
this.eventsData.splice(index, 1)
}
}
}

Get id of item clicked and use it for creating dynamic url in vuejs

I have a vue bootstrap table displaying, in each row, few properties of objects of an array (got through an api call with axios).
Every row has a button that should redirect me to a detail page, with more properties of that object, plus a map.
I was thinking to make a function to get the property id of the object contained in the clicked row, but I'm not sure on how to do it. I need the id to use it in the last part of the api call.
The store is structured so that I have a module for the user and another one for these objects (activities). In these modules I deal with state, actions and mutations. A separate file handles the getters. As these activities will be modified, I need to save their state too.
I will also need to be able to easily access all the properties of the single object (not only the ones shown in the table row) from other components.
I'm getting very confused.
Here the code:
Table with all the activities:
<b-table
responsive
:fields="fields"
:items="activity"
>
<template
slot="actions"
>
<b-button
v-b-tooltip.hover
title="Mostra dettagli"
variant="info"
class="px-3"
#click="goToActivityDetail"
>
<span class="svg-container">
<svg-icon icon-class="search"/>
</span>
</b-button>
</template>
</b-table>
In the script:
export default {
name: 'AllActivities',
data() {
return {
fields: [
{ key: 'activity.activityName', label: 'Activity', _showDetails: true},
{ key: 'related_activity', label: 'Related activity', _showDetails: true},
{ key: 'start', label: 'Start', _showDetails: true },
{ key: 'end', label: 'End', _showDetails: true },
{ key: 'travel_mode', label: 'Travel mode', _showDetails: true },
{ key: 'actions', label: '' }
],
activity: [],
methods: {
getIdActivity(){
**?? how to get it ??**
},
goToActivityDetail() {
this.$router.push({
name: 'activityDetail'
})
}
}
goToActivityDetail()
obviously does not work, in the console:
- [vue-router] missing param for named route "activityDetail": Expected "activityId" to be defined
- [vue-router] missing param for redirect route with path "/see-all-activities/:activityId": Expected "activityId" to be defined)
In the getters file I have:
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token
}
export default getters
So here I will need to have something like:
activityId: state => state.activity.activityId
Which is coming from activity.js, which is:
import {
getActivityId
} from '#/components/AllActivities'
const state = {
activityId: getActivityId()
}
const mutations = {
SET_ACTIVITY_ID: (state, activityId) => {
state.activityId = activityId
}
}
const actions = {
setActivityId({
commit
}) {
return new Promise(resolve => {
commit('SET_ACTIVITY_ID', '')
resolve()
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
IF this is right, what is left is the function to get the id of the object contained in the table row clicked.
Also, how to write that activity id in the api call (axios)?
Now I have:
export function getSingleActivity() {
return request({
url: 'http://localhost:8000/api/user_activity/:activityId',
method: 'get'
})
}
But I am not sure if that's correct.
Also, how to access the other properties (to be displayed in the detailActivity page)?
This will be made of a list of some properties (probably a stacked table component) and a map component, so I will need to access the properties in both these components.
I hope I've been clear enough,
thank you.
It was dead simple. I post how to solve it in case someone else get stuck on this too.
I added a slot scope to the template that contains the button:
<template
slot="actions"
slot-scope="data"
>
Then I added the single activity (following the vue bootstrap markup data.item) as parameter to the button click
#click="goToDetailActivity(data.item)"
And the function called by the click became:
goToDetailActivity(activity) {
this.$router.push({
name: 'DettaglioAttivita',
params: { activityId: activity.id }
})
}
That's it.
Worth mentioning is you're using vuex. If I understand correctly you want to get the property read from vuex?
To read a property from vuex you can eather use this.$store.getters.activity
Or use mapGetter.
Read the following page https://vuex.vuejs.org/guide/getters.html
Also you have to set the param when you do a router.push
router.push({ name: 'activity', params: { id: activityId } })

Vue: same component multiple times in the same template, with same props and event handlers

I have a Vue component that receives a bunch of props through v-bind and has multiple event handlers attached using v-on.
<SomeComponent
v-for="object in objects"
v-bind:prop1="prop1"
v-bind:prop2="prop2"
v-bind:prop3="prop3"
v-bind:key="object.created_at"
v-on:event-one="eventOne"
v-on:event-two="eventTwo"
v-on:event-three="eventThree"
/>
All works fine.
The problem is that this component can appear on different parts of the interface depending on some conditionals. It's the exact same component with the exact same props and event handlers.
Our current approach is a simple copy and paste of all the above lines, but it seems error prone and verbose, since if tomorrow we need to add another event handler (say v-on:event-four="eventFour"), it requires it to be added manually to every instance of SomeComponent in the template. The same goes for any prop change and so on.
In React we would probably wrap that component in a function and just invoke it like {renderSomeComponent()} as needed.
What would the approach be using Vue?
One approach would be to use a method to create JavaScript objects for props and events. (You could get away with computed properties except that one of your bindings depends on the object of the v-for loop.)
<SomeComponent
v-for="object in objects"
v-bind="getProps(object)"
v-on="getHandlers()"
/>
computed: {
getHandlers() {
return {
"event-one": this.eventOne,
"event-two": this.eventTwo,
"event-three": this.eventThree
};
}
},
methods: {
getProps(object) {
return {
"prop1": this.prop1,
"prop2": this.prop2,
"prop3": this.prop3,
"key": object.created_at
}
},
eventOne(). { /* ... */ },
eventTwo() { /* ... */ },
eventThree() { /* ... */ }
},
data() {
return {
prop1: /* ... */,
prop2: /* ... */,
prop3: /* ... */
}
}

How to access data from the SVG map with Vue.js

I use SVG map of Austria. Each province has "title" attribute which contains a name of the province.
[full example available in the snippet below]
Outside the map in my HTML I have a paragraph, where I want to display the name of the province that was clicked by the user.
{{ province }}
How can I achieve that?
Here is my snippet with my code:
https://mdbootstrap.com/snippets/jquery/marektchas/500840?view=project
If you can change the svg part you can add a click event on each path:
<path #click="setProvince('Burgenland')" id="AT-1" title="Burgenland" class="land" d="..." />
And add a method in your script:
methods: {
setProvince (title) {
this.province = title
}
}
Updated answer
If you have a lot of provinces, you can add the click event on mounted by selecting all the <path> selectors (or class name or any selector you find relevant for your case):
new Vue({
el: '#app',
data: {
province: null
},
mounted () {
this.addClickHandler()
},
methods: {
setProvince (title) {
this.province = title
},
addClickHandler () {
let paths = this.$el.querySelectorAll('path')
paths.forEach(el => {
let title = el.attributes.title.value
el.addEventListener('click', () => {
this.setProvince(title)
})
})
}
}
});
There's no need of #click in template anymore this way.
Live example here
You need to learn about event delegation. You should be able to attach an event handler to the svg root and get events for any element inside the svg
https://recursive.codes/blog/post/34
https://jqfundamentals.com/chapter/events

How to change the value of a prop (or data) of a component, from OUTSIDE the component?

As the title says, I'm trying to change the value of a prop/data in a component, but the trigger is being fired from outside the component, from something that has nothing to do with Vuejs.
Currently I trying to use a Simple State Manager, based on the docs from here, like so:
var store = {
debug: true,
state: {
progress: 23
},
setProgress (uff) {
if (this.debug) console.log(uff)
this.state.progress = uff
}
}
The documentation leads me to believe that if the value of progress is mutated, the value of my Vue instance would also change if I link them accordingly. But this doesn't work in a component (my guess would be it's cause it's a function).
This is part of my component:
Vue.component('transcoding', {
data () {
return {
progress: store.state.progress
}
},
template: `
<v-progress-circular
:size="130"
:width="25"
:value="progress"
color="teal"
>
{{progress}}
</v-progress-circular>
`
})
So, when I trigger a store.setProgress(value), nothing happens. The log messages do happen, but the state isn't updated in the component.
This is the script that's currently triggering the state change:
App.cable.subscriptions.create(
{ channel: "ProgressChannel", room: "2" },
{ received: function() {
store.setProgress(arguments[0])
}}
)
It's an ActionCable websocket in Ruby on Rails. The trigger works perfectly, but I just cannot make the connection between the state change and the component.
I tried loading this script in the mounted() event for the component, thinking I could reference the value like this:
Vue.component('transcoding', {
data () {
return {
progress: 0
}
},
template: `
<v-progress-circular
:size="130"
:width="25"
:value="progress"
color="teal"
>
{{progress}}
</v-progress-circular>
`,
methods: {
setProgress: function(uff) {
this.progress = uff
}
},
mounted() {
App.cable.subscriptions.create(
{ channel: "ProgressChannel", room: "2" },
{ received: function() {
this.setProgress(arguments[0])
}}
)
}
})
But this gives me an error saying that this.setProgress is not a function, which is obvious since I'm calling it within the create method of App.cable.subscriptions.
How can I make this work? I realize I'm mixing things with my question, but I wanted to illustrate what my goal is. I simply want to know how to make the component's progress data to update, either from the outside, or from the component itself if I can make it find the function.
You are initializing your data item to the value from the store:
data () {
return {
progress: store.state.progress
}
}
Changes to the store will not propagate to your data item. You could eliminate the data item and just use store.state.progress where you need it, or you could create an computed that returns its value if you want a local single-name handle for it.