How to hide a paragraph using v-if through vuex? - vue.js

I am trying to create a small app in which i can click on the button and hide the paragraph but i am trying to implement that using vuex.I have a paragraph in my Home.vue file and a button in my About.vue File. I want the paragraph hide conditionally in the click of the button but i want to accomplish that using vuex. How would i do that? My store.js, home.vue and About.vue are as follows.
This is how my store looks like.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
show:true,
},
mutations: {
toggle : state => {
state.show = !state.show
}
},
actions: {
}
})
This is the Home.vue file
<template>
<p>This needs to disappear</p>
</template>
<script>
import {mapMutations} from "vuex"
export default {
computed : {
...mapMutations ([
"toggle"
])
}
}
</script>
This is the About.vue file
<template>
<div>
<button #click="toggle">Click Me</button>
</div>
</template>
<script>
import {mapMutations} from "vuex"
export default {
computed : {
...mapMutations ([
"toggle"
])
}
}
</script>

the mapMutations should be used in methods not in computed property :
methods:{
...mapMutations ([
"toggle"
])
}
like you see in the official docs :
You can commit mutations in components with this.$store.commit('xxx'), or use the mapMutations helper which maps component methods to store.commit calls (requires root store injection):

Related

ag-grid in vue display custom component when loading the rows

Am trying to display the v-progress-circular vuetify component when ag-grid is loading the rows, i have been following the ag-grid documentation but that doesn't seems to work. the ag-grid documentation for vue seems to be outdated so i don't know what to do. What i have done so far is the following:
TableProgress.vue
<template>
<v-progress-circular :value="20" color="primary" indeterminate>
</v-progress-circular>
</template>
<script>
export default {
name: 'TableProgress'
}
</script>
MyTable.vue (Relevant parts)
<template>
<ag-grid-vue
:grid-options="gridOptions"
class="ag-theme-material"
:frameworkComponents="frameworkComponents"
:loadingOverlayComponent="loadingOverlayComponent"
/>
</template>
<script>
import TableProgress from "./TableProgress";
export default{
data(){
return{
gridOptions: null,
frameworkComponents: null,
loadingOverlayComponent: null
}
},
beforeMount () {
this.frameworkComponents = {
tableProgress: TableProgress
}
this.gridOptions.loadingOverlayComponent = 'tableProgress'
this.loadingOverlayComponent = 'tableProgress'
},
}
</script>
What am i doing wrong here? Or is it that this simply doesn't work on vue?
I think the attribute is overlayLoadingTemplate in ag-grid instead of loadingOverlayComponent. Kindly visit ag-grid overlays to see how you can add loader to your ag-grid table
You import the TableProgress but you don't use it. You must add it in components.
<script>
import TableProgress from "./TableProgress";
export default {
components: {
TableProgress
},
//...
}
</script>

Passing multiple properties in vuejs

I'm quite new with VueJS. I'm working on a new project with VueCLI3 & VuetifyJS.
I'm trying to create a reusable components based on VuetifyJS components and would like to make things easier by passing multiple props in a separate file to render them at once in my new component files.
I found this article that explains a technique to achieve such thing.
https://alligator.io/vuejs/passing-multiple-properties/
Every time I need to render them I must import my seperate file.
component1.vue
<template>
<v-btn v-bind='buttonProps'>
Button 1
</v-btn>
</template>
<script>
import { buttonProps } from './props.js';
export default {
data: () => ({ buttonProps })
}
</script>
component2.vue
<template>
<v-btn v-bind='buttonProps'>
Button 2
</v-btn>
</template>
<script>
import { buttonProps } from './props.js';
export default {
data: () => ({ buttonProps })
}
</script>
Is there any way to register the file globally so it allows me to use it anywhere in the app like this?
props.js
export const buttonProps = {
color: 'primary',
small: true,
outline: true,
block: true,
ripple: true,
href: 'https://alligator.io'
}
main.js
import Props from 'props.js';
component3.vue
<template>
<v-btn v-bind='buttonProps'>
Button 3
</v-btn>
</template>
<script>
... // no import needed
</script>
You can use a mixin and register that mixin globally.
buttonPropsMixin
export default {
data() {
return {
buttonProps: {
color: 'primary',
small: true,
  outline: true,
block: true,
ripple: true,
href: 'https://alligator.io'
}
}
}
}
main.js
import buttonPropsMixin from '...';
Vue.mixin(buttonPropsMixin)
Note That each vue component has its own buttonProps, so if you change in one component the color it will not affect the other components!
If you want buttonProps to have the same state across all your components you can go the vuex way as Igor mentioned and use it with an mixin where you define the mapGetters in that mixin.
If data in props.js doesn't need to be reactive and all the components are children of some root component you could do this:
main.js:
import buttonProps from 'props.js';
new Vue({
el: rootComponentElement,
buttonProps: buttonProps,
render: h => h(rootComponent)
})
component.vue:
<template>
<v-btn v-bind='$root.$options.buttonProps'>
Button 3
</v-btn>
</template>
<script>
... // no import needed
</script>
Otherwise I would advice you to use Vuex or use the global bus method described here.

How can I pass parameters from vue custom element to a vue component?

I don't have a whole vue app, so I use custom elements to replace some elements that should be handled with vue.
I simply want to use the vue multiselect plugin in a html file.
So I tried the following:
index.ts
import Vue from "vue"
import VueCustomElement from 'vue-custom-element'
import Autocomplete from "./vue/autocomplete.vue"
Vue.use(VueCustomElement);
Vue.customElement('auto-complete', Autocomplete);
test.html
<auto-complete
v-model="value"
:options="options"
placeholder="test"
#search-change="getData"
>
</auto-complete>
test.vue
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
components: { Multiselect },
data () {
return {
value: 'test',
options: ['list', 'of', 'options']
}
},
methods: {
getData (query) {
console.log(123)
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
In the output the data of the custom element is always ignored and only the parameters in the part in the .vue file is used.
How can i achieve that the parameters like placeholder or #search-change are used from the custom element?
I am also using vue-custom-elements in one of my projects.
You are passing option as props so you need to add it as a prop in your autocomplete.vue.
<template>
<multiselect v-model="value" :options="options" #search-change="getData"></multiselect>
</template>
<script type="ts">
const Multiselect = require('vue-multiselect').default
export default {
props: ['options'],
components: { Multiselect },
data () {
return {
value: 'test'
}
},
methods: {
getData (query) {
console.log('123')
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

vue component does not update when data is changed external

My component does not update the loaded property when Store.loaded changes:
Component
import { Vue } from 'vue-property-decorator'
import Component from 'nuxt-class-component'
import { Store } from '../repositories'
#Component
export default class Layout extends Vue {
loaded = Store.loaded
}
Store
class Root {
loaded = false
}
export let Store = new Root()
export default Store
In your example Store is just plain function (class), without any reactivity (no Vue watchers attached for Store.loaded field).
Only properties inside component's data are reactive. If you want reactive single store outside of vue components (better for big frontend applications), you should use Vuex
Simple example will be:
App.vue:
<script>
import { mapGetters, mapMutations } from 'vuex';
import store from './store';
import ChildComponent from './components/ChildComponent.vue';
export default {
store,
components: { ChildComponent },
methods: {
...mapMutations(['toggleLoaded']),
},
computed: {
...mapGetters({
isLoaded: 'isLoaded',
}),
}
}
</script>
<template>
<div id="app">
Toggle loaded
<h3>Root component: </h3>
<div>The loaded flag is: {{ isLoaded }}</div>
<ChildComponent />
</div>
</template>
components/ChildComponent.vue:
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
isLoaded: 'isLoaded', //accessing to same data, as root through single Vuex state
}),
}
}
</script>
<template>
<div class="hello">
<h3>Child component</h3>
<div>The loaded flag is: {{ isLoaded }}</div>
</div>
</template>
And reactive Vuex store:
store/index.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const state = {
loaded: false
};
const getters = {
isLoaded: state => state.loaded,
};
const mutations = {
toggleLoaded: (state) => {
state.loaded = !state.loaded;
}
};
export default new Vuex.Store({
state,
mutations,
// actions,
getters,
strict: true
});
You can find full source of this example on GitHub.

Pass data from one component to all with $emit without using #click in VueJS

Trying to learn vuejs I got to the question how to pass any data from one component to all, using $emit but without using any #click.
It is possible some how that the data to be just available and grab it any time, without using the click?
Let's say we have this example with normal #click and $emit.
main.js
export const eventBus = new Vue()
Hello.vue
<template>
<div>
<h2>This is Hello component</h2>
<button
#click="emitGlobalClickEvent()">Click me</button>
</div>
</template>
<script>
import { eventBus } from '../main'
export default {
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods: {
emitGlobalClickEvent () {
eventBus.$emit('messageSelected', this.msg)
}
}
}
</script>
User.vue
<template>
<div>
<h2>This is User component</h2>
<user-one></user-one>
</div>
</template>
<script>
import { eventBus } from '../main'
import UserOne from './UserOne.vue'
export default {
created () {
eventBus.$on('messageSelected', msg => {
console.log(msg)
})
},
components: {
UserOne
}
}
</script>
UserOne.vue
<template>
<div>
<h3>We are in UserOne component</h3>
</div>
</template>
<script>
import { eventBus } from '../main'
export default {
created () {
eventBus.$on('messageSelected', msg => {
console.log('From UserOne message !!!')
})
}
}
</script>
I want to get this message : Welcome to Your Vue.js App from Hello.vue in all components, but without #click, if is possible.
You can create another Javascript file which holds an Object with your initial state. Similar to how you define data in your components.
In this file your export your Object and import it in all Components which need access to this shared state. Something along the lines of this:
import Store from 'store';
data() {
return {
store
}
}
This might help:
https://v2.vuejs.org/v2/guide/state-management.html
At this point if you app grows even more in complexity you might also start checking out Vuex which helps to keep track of changes(mutations) inside of your store.
The given example is essential a very oversimplified version of Vuex.