I'm using Vue FullCalendar 5.3.1. I want to add event on doubleclick on empty date cell and edit event on doubleclick on event. How can I implement this? There are 2 methods by default: dateClick() and eventClick() and it's works fine for me.
My code:
<template>
<div>
<heading class="mb-6">Scheduler</heading>
<card class="custom-card">
<FullCalendar :options="calendarOptions"/>
</card>
</div>
</template>
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import resourceTimelineDay from '#fullcalendar/resource-timeline'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
data() {
return {
calendarOptions: {
dateClick: function(info) {
console.log(info.dateStr)
console.log(info.resource.id)
},
eventClick: function(info) {
console.log(info)
},
height: 250,
plugins: [ dayGridPlugin, interactionPlugin, resourceTimelineDay ],
headerToolbar: {
left: 'today prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek'
},
initialView: 'resourceTimelineDay',
aspectRatio: 1.5,
editable: true,
resourceAreaColumns: [
{
field: 'title',
headerContent: 'Worker'
}
],
resources: [
{
"id": "worker_a",
"title": "Worker A"
}, {
"id": "worker_b",
"title": "Worker B",
"eventColor": "green"
}, {
"id": "worker_c",
"title": "Worker C",
"eventColor": "orange"
}
],
events: [{
"resourceId": "worker_a",
"title": "Job 5",
"start": "2020-09-15T10:00:00+00:00",
"end": "2020-09-15T15:00:00+00:00"
}, {
"resourceId": "worker_b",
"title": "Job 2",
"start": "2020-09-15T09:00:00+00:00",
"end": "2020-09-15T14:00:00+00:00"
}, {
"resourceId": "worker_b",
"title": "Job 4",
"start": "2020-09-15T15:30:00+00:00",
"end": "2020-09-15T17:30:00+00:00"
},
]
}
}
}
}
</script>
BTW as I noticed that now all calendar settings are passed through :options = "". If you want to pass events like so <FullCalendar :events="events"/> or handle an event like <FullCalendar #dateClick="dateClick"/>, you cannot do this. Everything needs to be passed in the calendarOptions object (documentation)
The fullcalendar doesn't provide this option.
But you can attach the double click handler, when the event object is contructed by using an Event Render Hooks
In the version 5 we can use the funcion eventDidMount
data() {
return {
calendarOptions: {
...
eventDidMount: function(eventInfo){
// Not mandatory, but you can set an id to the object
eventInfo.el.id = eventInfo.event.id;
// Set the dbclick event
eventInfo.el.ondblclick = function(){
console.log(eventInfo.event)
};
}
}
}
}
Note: This works, only because this function is called only one time, in case that you are working in other version check how many times the function is called.
Related
I am attempting to use Vuelidate nested validations, but I am surely missing something.
I have a simple component that only contains an input, and a validation making that input required.
<template>
<input type="text" v-model="value" />
</template>
<script>
import useVuelidate from "#vuelidate/core";
import { required } from "#vuelidate/validators";
export default {
name: "MyInput",
setup() {
return { v$: useVuelidate() };
},
props: {
modelValue: String,
},
computed: {
value: {
get() {
return this.modelValue;
},
set(value) {
this.$emit("update:modelValue", value);
},
},
},
validations() {
return {
value: { required },
};
},
};
</script>
And my app just includes two instances of this component, and prints the Vuelidate object for my inspection.
<template>
<pre>{{ v$ }}</pre>
<my-input v-model="myValue1"></my-input>
<br />
<my-input v-model="myValue2"></my-input>
</template>
<script>
import useVuelidate from "#vuelidate/core";
import MyInput from "./components/my-input.vue";
export default {
name: "App",
components: {
MyInput,
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
myValue1: "",
myValue2: "",
};
},
};
</script>
<style scoped>
</style>
This is what's getting printed:
{
"$dirty": false,
"$path": "__root",
"$model": null,
"$error": false,
"$errors": [],
"$invalid": true,
"$anyDirty": false,
"$pending": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$validationGroups": {},
"_vuelidate_undefined": {
"$dirty": false,
"$path": "__root",
"$model": null,
"$error": false,
"$errors": [],
"$invalid": true,
"$anyDirty": false,
"$pending": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$validationGroups": {},
"value": {
"$dirty": false,
"$path": "value",
"required": {
"$message": "Value is required",
"$params": {
"type": "required"
},
"$pending": false,
"$invalid": true,
"$response": false
},
"$externalResults": [],
"$invalid": true,
"$pending": false,
"$error": false,
"$silentErrors": [
{
"$propertyPath": "value",
"$property": "value",
"$validator": "required",
"$uid": "value-required",
"$message": "Value is required",
"$params": {
"type": "required"
},
"$response": false,
"$pending": false
}
],
"$errors": [],
"$model": "",
"$anyDirty": false
}
}
}
Only the second input component is showing up- updating the second input makes the data update, but not the first one. Also note the property "_vuelidate_undefined" which looks like something went wrong. Is some sort of key missing on my components? Am I supposed to namespace the properties I'm validating somehow?
Sandbox with this code can be found here.
I use i18n to provide multilingual support to an application, I'd like the charts I provide with highcharts to have the same behaviour.
<i18n>
{
"fr": {
"test": "en fançais"
},
"en": {
"test": "in english"
}
}
</i18n>
<template>
<highcharts :options="options"></highcharts>
</template>
<script>
import '#/plugins/highcharts.js'
export default {
data() {
return {
options: {
chart: {
type: 'bar'
},
series: [{
name: $t('test'),
data: [1.0, 0.3, 0],
color: '#beab9d'
}],
xAxis: {
categories: ["1", "2", "3"]
}
}
}
}
}
</script>
But when building the application, I got :
'$t' is not defined
There is a way to access i18n values from the script part of a component ?
I want to use the response coming from the API in v-select. Here is a scenario i want to use the API call from component A to component B, rather than calling it again in the component B.
Component A:
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
Component B:
<template>
<div class="The V-select">
<vselect v-model="input1" :options="[{label: 'Vanilla' , value: 'vanilla'}]" :dir="$vs.rtl ? 'rtl' : 'ltr'" />
</div>
</template>
<script>
import vselect from 'vue-select'
...
input1: null,
icecream: null
...
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
</script>
As you can see my Component B i have hard coded as 'vanilla' in v-select, rather i want to use the data coming from the API, i want to know how it can be done.
Here is my Api response:
[
{
"id": 3,
"flavor": "vanilla",
"price": "150",
"taste": "super",
"cream": "high",
"investments": null,
},
{
"id": 8,
"flavor": "chocolate",
"price": "250",
"taste": "super high",
"cream": "fantastic",
"investments": "too high",
}
...
]
Please do help me. I tried just by using label: type.flavor but nothing was displayed. And in order to make code effective i want to use the response coming from API call made in component A
use just have to add a variable at the place of option as shown below:
<template>
<div class="The V-select">
<vselect v-model="input1" :options="icecream" :dir="$vs.rtl ? 'rtl' : 'ltr'" />
</div>
</template>
<script>
import vselect from 'vue-select'
...
input1: null,
icecream: null
...
methods: {
forVselect (id) {
this.$http.get(`/type/${id}`)
.then((res) => {
this.icecream = res.data})
.catch((e) => {console.log(e)})
}
},
mounted (){
this.forVselect (this.$route.params.un_id)
}
</script>
and also you need modify your api response... response like:
[
{
"id": 3,
"flavor": "vanilla",
"price": "150",
"taste": "super",
"cream": "high",
"investments": null,
"label": "Vanilla" ,
"value": "vanilla"
},
{
"id": 8,
"flavor": "chocolate",
"price": "250",
"taste": "super high",
"cream": "fantastic",
"investments": "too high",
"label": "Chocolate" ,
"value": "chocolate"
}
...
]
you need to modify response like that from server side or client side when response received...
If you don't want to modify your json response so atleat you need to add 2 additional key which is label & value key so that you can use...
I tried to use :getOptionKey="getOptionKey" so I could change the default "id" vue-select was requesting but to me the only think that worked is to consider the object attribute "value" as the default.
So since I was working with array of objects being returned from API, what I did was:
// loading from API
dataUtils.find(this.$route.params.id).then((data) => {
this.mySelectObject = {
name: data.name,
value: data.id
}
and used the following within html:
<v-select
label="name"
:options="myOptions"
v-model="mySelectObject"
#input="setSelected" //created this method to change selection
/>
I use Axios to display a JSON data and I have succeeded. But I want to show an object based on date and time, it shows now all data and I need to filter it.
So I want to look at today's date and show the object based on that, so I want to show the next upcoming event. (24/05/2020)
What I currently have:
Json:
{
"doc": [
{
"data": {
"events": {
"18807612": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "14/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name 2",
"uid": 3020
}
}
},
"18807618": {
"_dt": {
"_doc": "time",
"time": "18:45",
"date": "24/05/20",
"tz": "UTC",
"tzoffset": 0,
"uts": 1566067500
},
"week": 33,
"teams": {
"home": {
"name": "name 1",
"mediumname": "name1",
"uid": 3014
},
"away": {
"name": "name 2",
"mediumname": "name2",
"uid": 3020
}
}
}
}
}
}
]
}
Store:
async loadPosts({ commit }) {
// Define urls pages
const urlEvents = 'http://api.example.com/302020';
// Set pages
const [
responseEvents
] = await Promise.all([
// Responses pages
this.$axios.get(urlEvents)
]);
// variables pages
this.events = responseEvents.data.doc[0].data.events
// mutations pages
commit('SET_EVENTS', this.events)
}
},
mutations: {
SET_EVENTS (state, events) {
state.events = events;
}
}
And to show the data I use this:
import {mapState} from 'vuex';
export default {
name: 'NextMatch',
mounted() {
this.$store.dispatch('loadPosts')
},
computed: {
...mapState([
'events'
])
}
}
<h1>{{events}}</h1>
But this shows all data, and what I try to get is the first upcoming event for the object with the "uid": 3014.
So I want to show the date, time and names of the home and away team.
How can I get the correct data by filtering the data?
Something like this or similar to this should work:
In your Vue component's <template>:
`<h1>{{selectedEvent._dt.date}}</h1>`
In your Vue component's <script>:
props: {
eventID: {
type: Number,
default: 3014
},
},
computed: {
...mapState([
'events'
]),
eventsArr(){
if (!this.events) return {} //make sure Object.entries gets object.
return Object.entries(this.events)
},
selectedEvent(){
const selectedArr = this.eventsArr.find(([eID, e]) => e.teams.home.uid === this.eventID)
return selectedArr[1]
}
}
I have a simple API call in getFeedingsAgain. I am calling it inside "beforeMount" yet I can see via my console.logs that my data value for "catFeedingsAgain" stays empty once "mounted" is called. I am trying to populate the catFeedingsAgain array BEFORE the component's "mounted()" lifecycle hook is called so a function I have inside the "mounted()" hook can use that array data. How can I make this work?
Thank you for your time.
UPDATED: including entire component code now.
NOTE: I am basically trying to replace the initial array within Amcharts...Line Chart #2...."dataProvider" with the resultant array from the API call in getFeedingsAgain.
```
<template>
<!-- second chart group -->
<div class="chart-block" style="padding-top:50px">
{{ message }}
<div ref="line" style="vertical-align: middle; display: inline-block; width: 50%; height: 30px;"></div>
<div ref="column" style="vertical-align: middle;display: inline-block; width: 50%; height: 30px;"></div>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: ['message'],
name: 'app',
computed:{
},
created(){
this.getFeedingsAgain(this.message);
},
data() {
return {
chartCatID: this.message,
catFeedingsAgain: [],
catMedicationsAgain: [],
}
},
mounted () {
/**
* Line Chart #2
*/
// this.getFeedingsAgain(this.message);
console.log("mounted");
console.log(this.catFeedingsAgain);
// TODO: line = weight(waf) / day(created?)
AmCharts.makeChart( this.$refs.line, {
"type": "serial",
"dataProvider": [ {
"day": 1,
"weight_after_food": 120
}, {
"day": 2,
"weight_after_food": 54
}, {
"day": 3,
"weight_after_food": -18
}, {
"day": 4,
"weight_after_food": -12
}, {
"day": 5,
"weight_after_food": -51
}, {
"day": 6,
"weight_after_food": 12
}, {
"day": 7,
"weight_after_food": 56
}, {
"day": 8,
"weight_after_food": 113
}, {
"day": 9,
"weight_after_food": 142
}, {
"day": 10,
"weight_after_food": 125
} ],
"categoryField": "day",
"autoMargins": false,
"marginLeft": 0,
"marginRight": 5,
"marginTop": 0,
"marginBottom": 0,
"graphs": [ {
"valueField": "weight_after_food",
"showBalloon": false,
"lineColor": "#ffbf63",
"negativeLineColor": "#289eaf"
} ],
"valueAxes": [ {
"gridAlpha": 0,
"axisAlpha": 0,
"guides": [ {
"weight_after_food": 0,
"lineAlpha": 0.1
} ]
} ],
"categoryAxis": {
"gridAlpha": 0,
"axisAlpha": 0,
"startOnAxis": true
}
} );
/**
* Column Chart #2
*/
// TODO: column = dose(dosage) / day(created?)
AmCharts.makeChart( this.$refs.column, {
"type": "serial",
"dataProvider": [ {
"day": 1,
"value": -5
}, {
"day": 2,
"value": 3
}, {
"day": 3,
"value": 7
}, {
"day": 4,
"value": -3
}, {
"day": 5,
"value": 3
}, {
"day": 6,
"value": 4
}, {
"day": 7,
"value": 6
}, {
"day": 8,
"value": -3
}, {
"day": 9,
"value": -2
}, {
"day": 10,
"value": 6
} ],
"categoryField": "day",
"autoMargins": false,
"marginLeft": 0,
"marginRight": 0,
"marginTop": 0,
"marginBottom": 0,
"graphs": [ {
"valueField": "value",
"type": "column",
"fillAlphas": 1,
"showBalloon": false,
"lineColor": "#ffbf63",
"negativeFillColors": "#289eaf",
"negativeLineColor": "#289eaf"
} ],
"valueAxes": [ {
"gridAlpha": 0,
"axisAlpha": 0
} ],
"categoryAxis": {
"gridAlpha": 0,
"axisAlpha": 0
}
} );
},
methods:{
getFeedingsAgain(value) {
axios.get(`${process.env.KITTY_URL}/api/v1/feedings/?cat__slug&cat__name=${value}`)
.then(response => {
console.log("getFeedingsAgain: ");
console.log(response.data.results);
this.catFeedingsAgain = response.data.results
})
.catch(error => console.log(error));
},
getMedicationsAgain(value) {
axios.get(`${process.env.KITTY_URL}/api/v1/medications/?cat__slug=&cat__name=${value}`)
.then(response => {console.log("catMedications: ");console.log(response.data.results); this.catMedications = response.data.results})
.catch(error => console.log(error));
},
}
}
</script>
<style>
.amcharts-chart-div a{
text-indent: -9999px;
outline: none;
}
</style>
```
You could also create a watcher, to perform an action when the variable changes.
something like this
watch: {
catFeedingsAgain: function() {
AmCharts.makeChart( this.$refs.line, {
"type": "serial",
"dataProvider": this.catFeedingsAgain,
...
});
}
},
you can find the documentation here; https://v2.vuejs.org/v2/guide/computed.html#Watchers
First, you should not use beforeMount() method. Avoid it as much as you can. Instead use created() life-cycle method:
created() {
this.getFeedingsAgain(this.message);
}
Second, you want to populate an array before mounted is called. But since your data is being loaded from API asynchronously, you cannot do that. You cannot stop/pause mounted event from happening. Vue.js doesn't know when API response will be available. It could take 2 seconds, 3 seconds or simply fail.
The only option you have is to use v-if in your template. As long as your array length is zero, you can hide DOM elements or show loading progress bar.
First, you should not use beforeMount() method. Avoid it as much as you can. Instead use created() life-cycle method:
created() {
this.getFeedingsAgain(this.message);
}
Second, you want to populate an array before mounted is called. But since your data is being loaded from API asynchronously, you cannot do that. You cannot stop/pause mounted event from happening. Vue.js doesn't know when API response will be available. It could take 2 seconds, 3 seconds or simply fail.
The only option you have is to use v-if in your template. As long as your array length is zero, you can hide DOM elements or show loading progress bar.
Finally, you may want to initialize some sort of Chart, then you can use Vue.js watcher or initialize it within the then() block of the API.
EDIT
I have to do this, then I will use watcher if I wish to initialize Charting component on every change like this:
watch: {
catFeedingsAgain() {
AmCharts.makeChart(this.$refs.line, {
"type": "serial",
"dataProvider": this.catFeedingsAgain,
});
}
},
If I have to do this only once, then I would something like this:
methods: {
getFeedingsAgain(value) {
axios.get(`${process.env.KITTY_URL}/api/v1/feedings/?cat__slug&cat__name=${value}`)
.then(response => {
this.catFeedingsAgain = response.data.results;
AmCharts.makeChart(this.$refs.line, {
"type": "serial",
"dataProvider": this.catFeedingsAgain,
});
})
.catch(error => console.log(error));
},
}
Both are right approaches. It all depends upon the context.
You should fetch the data when the view is created and the data is already being observed and this is happens at created hook.
// rename beforeMount -> created
created(){
this.getFeedingsAgain(this.message);
}
From Vue created docks
At this stage, the instance has finished processing the options which
means the following have been set up: data observation, computed
properties, methods, watch/event callbacks. However, the mounting
phase has not been started
Seems like this is what you are looking for