Fullcalendar and Vuex - vue.js

After fullcalendar updated their props to go outside of the <FullCalendar /> element I have some problems rendering events.
I know that the state request is fulfilled in Vuex because I've tested this so many this without a getter and with a getter and nothing seems to work...
<template>
<v-container>
<FullCalendar :options="calendarOptions" />
<li v-for="event in events" :key="event.id">
{{event.name + ' ' + event.start}}
</li>
</v-container>
</template>
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import timeGridPlugin from '#fullcalendar/timegrid'
import listPlugin from '#fullcalendar/list'
import { mapState, mapActions, mapGetters } from 'vuex'
export default {
components: {
FullCalendar
},
data() {
return {
calendarOptions: {
plugins: [timeGridPlugin, listPlugin ,dayGridPlugin, interactionPlugin ],
initialView: 'dayGridMonth',
selectable: true,
events: this.allEvents,
}
}
},
computed: {
...mapState({
events: state => state.calendar.events
}),
...mapGetters('calendar', ['allEvents']),
},
created () {
this.getAll();
},
methods: {
...mapActions('calendar', {
getAll: 'getAll',
}),
}
}
</script>
Is there any way to render the elements with just the state? I thought that setting events to this.events would be working, but I'm probably way off here. I'm new to Vue and Vuex so help is much appreciated! :) The list is just to know that the state is working as it should be.

You can still bind the events in template by doing something like this:
<FullCalendar :options="{
...calendarOptions,
events: events
}" />

Related

Getting an error TypeError: Cannot read properties of undefined (reading 'state') in vuejs while using Vuex

I am trying to learn vuex and following tutorials on youtube for vuex, I am in a error of
TypeError: Cannot read properties of undefined (reading 'state'), where I am not able figure out why I am getting this error , I assume it might be because of the newer version not sure.
Here is my code:
TodoList.vue
<template>
<div>
<h4>Todo list</h4>
<todo
v-for="(task, index) in $store.state.todos" // getting error here
:key="index"
:todo="todo"
></todo>
</div>
</template>
<script>
import Todo from "./Todo.vue";
export default {
name: "TodoList",
components: { Todo },
computed: {},
};
</script>
<style>
</style>
here is my
store/index.js
import { createStore } from 'vuex';
export const store = createStore({
state: {
todos: [{
title: 'Task 1',
completed: false
},
{
title: 'Task 2',
completed: false
}
]
}
// other stuff
});
mapState is a helper that simplifies creating a computed property that reflects the value of a given state
You can access your data like below:
<template>
<div>
<h4>Todo list</h4>
<todo
v-for="(task, index) in todos"
:key="index"
:todo="todo"
></todo>
</div>
</template>
import { mapState } from 'vuex'
export default {
data: {},
computed: {
...mapState({
todos: state => state.todos
})
}
}

Async loading child component doesn't trigger v-if

Hi everyone and sorry for the title, I'm not really sure of how to describe my problem. If you have a better title feel free to edit !
A little bit of context
I'm working on a little personal project to help me learn headless & micro-services. So I have an API made with Node.js & Express that works pretty well. I then have my front project which is a simple one-page vue app that use vuex store.
On my single page I have several components and I want to add on each of them a possibility that when you're logged in as an Administrator you can click on every component to edit them.
I made it works well on static elements :
For example, here the plus button is shown as expected.
However, just bellow this one I have some components, that are loaded once the data are received. And in those components, I also have those buttons, but they're not shown. However, there's no data in this one except the title but that part is working very well, already tested and in production. It's just the "admin buttons" part that is not working as I expect it to be :
Sometimes when I edit some codes and the webpack watcher deal with my changes I have the result that appears :
And that's what I expect once the data are loaded.
There is something that I don't understand here and so I can't deal with the problem. Maybe a watch is missing or something ?
So and the code ?
First of all, we have a mixin for "Auth" that isn't implemented yet so for now it's just this :
Auth.js
export default {
computed: {
IsAdmin() {
return true;
}
},
}
Then we have a first component :
LCSkills.js
<template>
<div class="skills-container">
<h2 v-if="skills">{{ $t('skills') }}</h2>
<LCAdmin v-if="IsAdmin" :addModal="$refs.addModal" />
<LCModal ref="addModal"></LCModal>
<div class="skills" v-if="skills">
<LCSkillCategory
v-for="category in skills"
:key="category"
:category="category"
/>
</div>
</div>
</template>
<script>
import LCSkillCategory from './LCSkillCategory.vue';
import { mapState } from 'vuex';
import LCAdmin from '../LCAdmin.vue';
import LCModal from '../LCModal.vue';
import Auth from '../../mixins/Auth';
export default {
name: 'LCSkills',
components: {
LCSkillCategory,
LCAdmin,
LCModal,
},
computed: mapState({
skills: (state) => state.career.skills,
}),
mixins: [Auth],
};
</script>
<style scoped>
...
</style>
This component load each skills category with the LCSkillCategory component when the data is present in the store.
LCSkillCategory.js
<template>
<div class="skillsCategory">
<h2 v-if="category">{{ name }}</h2>
<LCAdmin
v-if="IsAdmin && category"
:editModal="$refs.editModal"
:deleteModal="$refs.deleteModal"
/>
<LCModal ref="editModal"></LCModal>
<LCModal ref="deleteModal"></LCModal>
<div v-if="category">
<LCSkill
v-for="skill in category.skills"
:key="skill"
:skill="skill"
/>
</div>
<LCAdmin v-if="IsAdmin" :addModal="$refs.addSkillModal" />
<LCModal ref="addSkillModal"></LCModal>
</div>
</template>
<script>
import LCSkill from './LCSkill.vue';
import { mapState } from 'vuex';
import LCAdmin from '../LCAdmin.vue';
import LCModal from '../LCModal.vue';
import Auth from '../../mixins/Auth';
export default {
name: 'LCSkillCategory',
components: { LCSkill, LCAdmin, LCModal },
props: ['category'],
mixins: [Auth],
computed: mapState({
name: function() {
return this.$store.getters['locale/getLocalizedValue']({
src: this.category,
attribute: 'name',
});
},
}),
};
</script>
<style scoped>
...
</style>
And so each category load a LCSkill component for each skill of this category.
<template>
<div class="skill-item">
<img :src="img(skill.icon.hash, 30, 30)" />
<p>{{ name }}</p>
<LCAdmin
v-if="IsAdmin"
:editModal="$refs.editModal"
:deleteModal="$refs.deleteModal"
/>
<LCModal ref="editModal"></LCModal>
<LCModal ref="deleteModal"></LCModal>
</div>
</template>
<script>
import LCImageRendering from '../../mixins/LCImageRendering';
import { mapState } from 'vuex';
import Auth from '../../mixins/Auth';
import LCAdmin from '../LCAdmin.vue';
import LCModal from '../LCModal.vue';
export default {
name: 'LCSkill',
mixins: [LCImageRendering, Auth],
props: ['skill'],
components: { LCAdmin, LCModal },
computed: mapState({
name: function() {
return this.$store.getters['locale/getLocalizedValue']({
src: this.skill,
attribute: 'name',
});
},
}),
};
</script>
<style scoped>
...
</style>
Then, the component with the button that is added everywhere :
LCAdmin.js
<template>
<div class="lc-admin">
<button v-if="addModal" #click="addModal.openModal()">
<i class="fas fa-plus"></i>
</button>
<button v-if="editModal" #click="editModal.openModal()">
<i class="fas fa-edit"></i>
</button>
<button v-if="deleteModal" #click="deleteModal.openModal()">
<i class="fas fa-trash"></i>
</button>
</div>
</template>
<script>
export default {
name: 'LCAdmin',
props: ['addModal', 'editModal', 'deleteModal'],
};
</script>
Again and I'm sorry it's not that I haven't look for a solution by myself, it's just that I don't know what to lookup for... And I'm also sorry for the very long post...
By the way, if you have some advice about how it is done and how I can improve it, feel free, Really. That how I can learn to do better !
EDIT :: ADDED The Store Code
Store Career Module
import { getCareer, getSkills } from '../../services/CareerService';
const state = () => {
// eslint-disable-next-line no-unused-labels
careerPath: [];
// eslint-disable-next-line no-unused-labels
skills: [];
};
const actions = {
async getCareerPath ({commit}) {
getCareer().then(response => {
commit('setCareerPath', response);
}).catch(err => console.log(err));
},
async getSkills ({commit}) {
getSkills().then(response => {
commit('setSkills', response);
}).catch(err => console.log(err));
}
};
const mutations = {
async setCareerPath(state, careerPath) {
state.careerPath = careerPath;
},
async setSkills(state, skills) {
state.skills = skills;
}
}
export default {
namespaced: true,
state,
actions,
mutations
}
Career Service
export async function getCareer() {
const response = await fetch('/api/career');
return await response.json();
}
export async function getSkills() {
const response = await fetch('/api/career/skill');
return await response.json();
}
Then App.vue, created() :
created() {
this.$store.dispatch('config/getConfigurations');
this.$store.dispatch('certs/getCerts');
this.$store.dispatch('career/getSkills');
this.$store.dispatch('projects/getProjects');
},
Clues
It seems that if I remove the v-if on the buttons of the LCAdmin, the button are shown as expected except that they all show even when I don't want them to. (If no modal are associated)
Which give me this result :
Problem is that refs are not reactive
$refs are only populated after the component has been rendered, and they are not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid accessing $refs from within templates or computed properties.
See simple demo below...
const vm = new Vue({
el: "#app",
components: {
MyComponent: {
props: ['modalRef'],
template: `
<div>
Hi!
<button v-if="modalRef">Click!</button>
</div>`
}
},
data() {
return {
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-component :modal-ref="$refs.modal"></my-component>
<div ref="modal">I'm modal placeholder</div>
</div>
The solution is to not pass $ref as prop at all. Pass simple true/false (which button to display). And on click event, $emit the event to the parent and pass the name of the ref as string...

Vuex: unknown mutation type: dropdownState

im beginner and trying something for learn. im using vue js 2 and have a problem with vuex. When I click div of dropdown, I want to add active class and show content of dropdown. The problem is
unknown mutation type: dropdownState.
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
active: false,
},
getters: {
isOpen (state) {
return state.active;
},
},
mutation: {
dropdownState (state) {
state.active = !state.active;
console.log('hi');
},
},
});
Dropdown.vue
<template>
<div class="dropdown" #click="dropdownState">
<slot name="button"></slot>
<slot></slot>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
name: 'Dropdown',
methods: {
...mapMutations(['dropdownState']),
}
};
</script>
DropdownContent.vue
<template>
<div>
<div class="dropdown-content right" :class="{ active : active }"></div>
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
export default {
name: 'DropdownContent',
computed: {
...mapState(['active']),
...mapGetters(['isOpen']),
},
};
</script>
It's supposed to be mutations (with an s)
mutations: {
...
}
https://vuex.vuejs.org/guide/mutations.html#mutations
Btw, it will be actions too!

Vue components - recursive rendering or what is the problem here?

I'm trying to make a new Vue app with 2 components but the components don't render.
The error is - "Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option."
I read quite a bit on the problem but could not identify the problems in the code unlike with others' codes.
Seems OK to me, not the first app with components I've written :/
App:
require('../../lib/jquery.event.drag-2.2/jquery.event.drag-2.2');
require('../../lib/jquery.event.drag-2.2/jquery.event.drag.live-2.2');
require('../../lib/jquery.event.drop-2.2/jquery.event.drop-2.2');
require('../../lib/jquery.event.drop-2.2/jquery.event.drop.live-2.2');
import Vue from 'vue';
import Axios from 'axios';
Vue.prototype.$http = Axios;
import tournamentCourtManager from
'../../components/tournament/courtManager/courtManager';
import tournamentScheduleButton from
'../../components/tournament/tournamentScheduleButton';
import { store } from "../../store/store";
new Vue({
el: '#tournamentMatchSettingsApp',
store,
components: { 'tournamentCourtManager' : tournamentCourtManager,
'tournamentScheduleButton' : tournamentScheduleButton }
});
tournamentCourtManager:
<template>
<button type="submit" class="btn btn-info">
dadada
</button>
<script>
export default {
name: 'tournamentScheduleButton',
data() {
return {}
},
mounted: function mounted() {
},
methods: {
}
}
</script>
courtManager:
<template>
<div id="tournamentCourtManager">
..
</div>
</template>
courtManager JS:
export default {
name: 'tournamentCourtManager',
components: {
'match-cell': matchCell
},
data() {
return {
};
},
....
}
And the code that prompts the error -
<tournamentschedulebutton></tournamentschedulebutton>
<tournamentcourtmanager></tournamentcourtmanager>
Because you have named the components like 'tournamentCourtManager' in the components object, they must be named like <tournament-court-manager> in the template.

Vuex - changing value based on component's current index and passing the value to other components

I have hit a wall and cannot get over it without your help now. I've spent a good few days trying to get my head around mutations and actions but this particular case I have doesn't seem to apply to tutorials online, also the answers on here are for different scenarios to mine. So here goes:
Setup:
- Project is using vuex and store for data and state management
- Currently App.vue has two child components: PizzaGenerator.vue and BaseButtons.vue
I am trying to achieve this:
- When I click on a specific button in BaseButtons.vue I need a centrally managed showBaseIndex to be assigned an index value. This value is then available to the other, PizzaGenerator.vue, component which will reflect the change and show a layer that matches the new value of showBaseIndex.
Please see all the two components and store below.
Can you help me head in the right direction?
PizzaGenerator.vue
<template>
<div class="pizza-generator section" id="screen3" data-anchor="screenThree">
<ul class="pizza-layers">
<!-- Display pizzas -->
<li v-for="(item, index) in getBase" class="pizza-canvas pizza-canvas--base" v-bind:class="item.class" v-if="$store.state.showBaseIndex == index"></li>
<!-- END Display pizzas -->
</ul>
<div class="pizza-items">
<app-base-buttons></app-base-buttons>
</div>
</div>
</template>
<script>
import Base from './pizza-buttons/BaseButtons'
import { mapGetters, mapActions } from 'vuex'
export default {
components: {
appBaseButtons: Base
},
computed: {
getBase(){
return this.$store.state.base
}
},
methods: mapActions([
'baseLayer',
]),
}
</script>
BaseButtons.vue
<div class="pizza-items-selector pizza-items-selector--dough">
<div class="pizza-items-selector__items pizza-items-selector__items--dough">
<div class="sliding-buttons">
<button v-for="(item, index) in getBase" class="sliding-buttons__button dough-button" :key="index" #click="baseLayer = index"> {{ item.name }}</button>
</div>
<button class="buttons-prev-1 prev">prev</button>
<button class="buttons-next-1 next">next</button>
</div>
</div>
<script>
import { mapActions, mapMutations } from 'vuex'
export default {
computed:{
getBase(){
return this.$store.state.base
},
},
methods:{
...mapMutations([
'baseLayer',
]),
baseLayerIndex() {
this.$store.commit('baseLayer');
}
},
}
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
showBaseIndex: 1,
base : [
{ name: 'Dünner Italienisch', class: 'pizza-canvas--base-italienisch', id: 1 },
{ name: 'Dünner Italienisch - Vollkorn', class: 'pizza-canvas--base-italienisch--vollkorn', id: 2 },
{ name: 'Dicker Amerikanisch', class: 'pizza-canvas--base-amerikanisch', id: 3 },
{ name: 'Dicker Amerikanisch / Chili-Käse-Rand', class: 'pizza-canvas--base-amerikanisch--chilli-kaese-rand', id: 4 },
{ name: 'Dicker Amerikanisch / Käse-Rand', class: 'pizza-canvas--base-amerikanisch--kaese-rand', id: 5 }
],
},
getters: {
//
},
mutations: {
baseLayer (state){
state.showBaseIndex
}
},
});
export default store;
Mutations are functions, not simple values. You should check the Vuex guide about mutations, they are quite straightforward.
What you should do is declaring the given mutation in this way, so it will also accept a parameter:
mutations: {
baseLayer (state, id){
state.showBaseIndex = id;
}
},
and commit the mutation properly in the component:
methods:{
...mapMutations([
'baseLayer',
]),
baseLayerIndex(index) { // call this at #click on button, giving the index as parameter
this.$store.commit('baseLayer', index);
}
}
This will set the desired index in the store, and from that on you could get the current base from store using vuex getters like:
getters: {
getSelectedBase(state){
return state.base.find(base=>{return base.id === state.showBaseIndex});
}
},