Access vue vuex namespaced getter from template - vue.js

I have made vuex namespaced getter mapping in my .vue component like this:
...mapGetters([
'fooModule/barGetter'
])
How do I access this getter in the .vue component template?
I have tried {{fooModule.barGetter}} but it doesn't seem to work, {{fooModule/barGetter}} is obviously wrong.
I could assign another key to the getter in mapGetters by
...mapGetters({
fooBarGetter: 'fooModule/barGetter'
})
This allows me to access the value in the template by using {{forBarGetter}}
However, I am wondering if there is a way to access the 'fooModule/barGetter' without assigning it another key. Is it possible? if so how?

The first parameter of mapGetters can be a namespace:
computed: {
...mapGetters("fooModule", [
"barGetter"
]),
...mapGetters("anotherModule", [
"someGetter"
])
}
That will make the value available as this.barGetter or just barGetter in templates. Note, it's perfectly acceptable to have multiple mapGetters statements.
Vuex Getters documentation
Vuex Binding helpers with namespace

Well actually it's registered under the key 'fooModule/barGetter', which is not a valid name for a javascript variable. So you should access the key as a string, ah, and so, it's not so elegant. But you can still do it, access it in the template with {{ _self['fooModule/barGetter'] }}.
See this working example:
new Vue({
el: '#app',
store: new Vuex.Store({
modules: {
fooModule: {
namespaced: true,
state: {},
getters: {
barGetter() {
return 'Hi :)';
}
}
}
}
}),
computed: Vuex.mapGetters([
'fooModule/barGetter'
])
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.min.js"></script>
<script src="https://unpkg.com/vuex#2.3.1"></script>
<div id="app">
{{ _self['fooModule/barGetter'] }}
</div>

For anyone who wants to achieve this without specifying the namespace as a first parameter, there's also a possibility to pass object/map to mapGetters with already namespaced names of the getters.
...mapGetters({
'activeItems': ACTIVE_ITEMS_GETTER_WITH_NAMESPACE
})
This is extremely useful when you have constants with namespaced names of mutations, getters and actions. In our case, we have lots of modules and it sometimes time consuming to look up the module our getter, mutation or action is inside. This is why we add namespace to our constants.

this.$store.getters.productName
in template, ex:
<vs-td width="20%">{{$store.getters.productName}}</vs-td>

Related

How to use VueRouter with Storybook

I'm trying to write a story for a component that references this.$route.params. I'm not sure how to synthetically define this.$route in the context of a story. I think the solution is to use decorators, but all the examples in the docs focus on rendering, like adding a wrapping <div> etc. I'm not sure how to inject values.
I also found this project which appears designed for this exact situation, but it hasn't been maintained in years and README references outdated syntax that doesn't match modern versions of Storybook, so I don't think it's an option.
Here's what doesn't work:
import AssetShow from '../app/javascript/src/site/components/assets/Show'
export default {
title: 'Site/AssetShow',
component: AssetShow,
parameters: {
}
};
export const CustomerSpotlight = () => ({
components: { AssetShow },
template: '<AssetShow />',
});
import Vue from 'vue'
import VueRouter from 'vue-router'
import StoryRouter from 'storybook-vue-router';
CustomerSpotlight.decorators = [
(story) => {
Vue.use(VueRouter)
return {
components: { story },
template: '<story />'
}
}
];
The component I'm writing the story for has this:
mounted() {
axios.get(`.../bla/${this.$route.params.id}.json`)
},
...which causes Storybook to throw this error: TypeError: Cannot read properties of undefined (reading 'params')
I suppose that your intention is to do something with the story's component based on the route parameters?
If that is the case, then I don't think you need to define the route.params within the story context. I suggest either keeping that code within the component itself, or create an option within the story for the user to simulate adding parameters to the path. Which you can simply have as an input text / select field that you send down to the component as a prop.

NUXTJS share JS method with Store Getters

I want to write a simple JS method that I will use both in Store GETTERS.
I created a new file: /plugins/myMethod.js and added it to nuxt.config.js (at plugins part).
Follows the content of the file:
export default ({ app }, inject) => {
// Inject $hello(msg) in Vue, context and store.
inject('exportaData', msg => console.log(`Data is: ${msg}!`))
}
I can use this method in Vue Components and in store ACTIONS, but not in Store GETTERS. I tried this.$myMethod(1) without any success.
Follows the code of store/data.js
export const getters = {
hoje: state => {
console.log('Running getter HOJE')
this.$exportaData('12345')
},
}
and in my Vue component:
<p>DATA: {{ $store.getters['datas/hoje'] }}</p>
Any idea how to access my custom method in the store getter?
Thanks

vue js trigger other component method

my files looks like this
./components/UserCreate.vue
./components/UserList.vue
./main.js
my vue instance in main.js
new Vue({
el: '#user-operations',
components: {
CreateUser,
UserList
}
});
index.html
<div id="user-operations">
<create-user></create-user>
<user-list></user-list>
</div
I want to trigger userList() method in UserList.vue when createUser() method in CreateUser.vue is triggered. Or how can i pass last_user property to UserList component from CreateUser.vue for append.
here is my create-user component [working]
https://jsfiddle.net/epp9y6vs/
here is my user-list component [working]
https://jsfiddle.net/ore3unws/
so i want the last user to be listed when createUser() is triggered
I recommend to create a service with all the methods operating user entities. It will separate your Components from the implementaton of the logic which is good because:
The Components doesn't have to know which calls they have to do to servers to retrieve data - it's better to use abstraction level
The Component will be lighter and easier for reuse
You will be able to use this logic (from the service) in several Components - exactly your problem
You have several ways to implement services:
Stateless service: then you should use mixins
Statefull service: use Vuex
Export service and import from a vue code
any javascript global object
I prefer (4). Here is an example how to do it:
In file /services/UsersService that will describe your service put all the relevant methods and expose them with export:
import axios from 'axios'
export default {
get() {
return axios.get('/api/posts)
}
}
Then in any Component that needs this methods import this service:
import UsersService from '../services/UsersService'
export default {
data() {
return {
items: []
}
},
created() {
this.fetchUsers()
},
methods: {
fetchUsers() {
return UsersService.get()
.then(response => {
this.items = response.data
})
}
}
}
Find even more about it in this question:
What's the equivalent of Angular Service in VueJS?
This solution is much better than using this.$parent.$refs.userList which suppose that this components will always stay "brothers" (will have the same parent).
You can trigger userList in CreateUser.vue by this code:
this.$parent.$refs.userList.userList()
and change your index.html:
<div id="user-operations">
<create-user></create-user>
<user-list :ref="userList"></user-list>
</div>
You can create last_user property in main.js then pass it to 2 components:
.
<div id="user-operations">
<create-user:lastUser="last_user"></create-user>
<user-list :lastUser="last_user"></user-list>
</div>

How to access Vuex module getters and mutations?

I'm trying to switch to using Vuex instead of my homegrown store object, and I must say I'm not finding the docs as clear as elsewhere in the Vue.js world. Let's say I have a Vuex module called 'products', with its own state, mutations, getters, etc. How do I reference an action in that module called, say, 'clearWorking Data'? The docs give this example of accessing a module's state:
store.state.a // -> moduleA's state
But nothing I can see about getters, mutations, actions, etc.
In Addition to the accepted answer I wanna provide you with a workarround for the getter which is missing in the answer.
Debug the Store
In any case you can call console.log(this.$store) to debug the Store.
If you do so you will see the getters are prefixed with the namespace in their name.
Access namespaced getter
this.$store.getters['yourModuleName/someGetterMethod']
Dispatch namespaced
this.$store.dispatch('yourModuleName/doSomething')
Dispatch namespaced with params
this.$store.getters['yourModuleName/someGetterMethod'](myParam)
Conclusion
The key is to handle the namespace like a file System like Justin explained.
Edit: found a nice library for handling vuex Store
In addition to the basic knowledge I'd like to add this vuex library as a nice addition for working effectivly and fast with the vuex store. https://github.com/davestewart/vuex-pathify .
It looks pretty interesting and cares much of the configuration for you and also allows you to handle 2waybinding directly with vuex.
** Edit: Thanks to the other Answers. Added Dispatching method with params for wholeness.
In your example it would be store.dispatch('products/clearWorkingData') you can think of actions/mutations as a file system in a way. The deeper the modules are nested the deeper in the tree they are.
so you could go store.commit('first/second/third/method') if you had a tree that was three levels deep.
As another addition to the accepted answer, if you need to pass parameter(s) to the getter (for instance to fetch a specific item from the store collection), you need to pass it as follows:
this.$store.getters['yourModuleName/someGetterMethod'](myParam)
I don't think I like this notation very much, but it is what it is - at least for the moment.
Try this approach!
getCounter(){
return this.$store.getters['auth/getToken'];
}
auth is my module name and getToken is my getter.
Using Vuex mapGetters and mapActions you can now do this pretty easily. But I agree, it still isn't very obvious in the documentation.
Assuming your store module 'products' has a getter called 'mostPopular' and an action called 'clearWorkingData':
<template>
<div>
<p>{{mostPopularProduct}}<p>
<p><button #click="clearProductData">Clear data</button></p>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: mapGetters({
mostPopularProduct: "products/mostPopular"
}),
methods: mapActions({
clearProductData: "products/clearWorkingData"
})
}
</script>
The mapGetters helper simply maps store getters to local computed properties:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// mix the getters into computed with object spread operator
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
If you want to map a getter to a different name, use an object:
...mapGetters({
// map `this.doneCount` to `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
You have to be aware of using namespaced: true when configuring particular store object
In Addition to the accepted answer, I feel it's not a good idea to mutate the state and commit the mutation directly in component. Thumb rule I follow is, Always use an action to commit the mutation and state only mutate inside mutations.
Use getters to get a transformed state.
Getters can be mapped to computed using mapGetters and actions can be mapped to methods using mapActions as below example
// component.vue
// namespace_name=products
<template>
<div>
<p> This is awesome product {{getRecentProduct}} </p>
</div>
<button #click="onButtonClick()"> Clear recent</button>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
computed: {
...mapGetters({
getRecentProduct: "products/getRecentProduct",
}),
anotherComputed(){
return "anotherOne"
}
},
methods: {
...mapActions({
clearRecentProduct: "products/clearRecentProduct",
}),
onButtonClick(){
this.clearRecentProduct(); /// Dispatch the action
},
anotherMethods(){
console.log(this.getRecentProduct); // Access computed props
}
}
};
</script>
Here's how you can access vuex Getters & Mutations using Composition API (setup)
<script setup>
import { useStore } from 'vuex'
const store = useStore();
var value = store.getters['subModuleName/getterMethod'];
store.commit['subModuleName/MutationMethod'];
</script>

Vuejs + vue-router, pass data between views like http post

I'm try to pass data between Vuejs views with vue-router.
//View1.vue
route: {
data: function (transition) {
transition.next({
message: "this is it!!"
});
}
}
I call next wiew with a click action button with:
//View1.vue
methods:{
showResult: function(){
this.$router.go('/View2');
}
}
but the data are not filled in the next view:
//View2.vue
<template>
<p>Message: {{ message }}</p>
</template>
Does somebody knows what's wrong with my usage of vue-router? I don't think I need to pass through services for this, right?
Working examples on jsfiddle (or jsbin, etc) are welcome :D
If View2 is a child component you can pass it using props:
//View1.vue
<view2-component :passedData='message'></view2-component>
Alternatively, I believe if you set data on the $route object from View1, since that object is shared between all vue instances, I believe it will be available application-wide.
//View1.vue
this.$router.myProps.message = message
But arguably the better way to share data is use a POJO - plain old javascript object and bind it to both views. To do this you typically need a shared state object and you can if you wish use Vuex for this although it is a little more complicated than a POJO.
I know this has already been answered, but if someone is here looking for a way to pass data to a route from a router, I use Meta Data.
Not sure if this is what the questioner meant or not but I think it is?
I personally prefer this to props just because I am more used to using it.
It allows for data to be easily passed and received without having to modify children.
Anyway here is a snippit and link!
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Homepage',
meta: {
logo:{
"/imgs/Normal-Logo.png"
}
}
},
{
path: '/admin',
name: 'Admin',
meta: {
logo:{
"/imgs/Admin-Logo.png"
}
}
},
]
})
In any children who want to use vars:
<logo :src="this.$route.meta.logo"/>
Ref:
https://router.vuejs.org/guide/advanced/meta.html