data from api can't assign to property in state - javascript

My project has /store.index.ts. I want to get data from api in actions block. I got data but can't assign data to property in state. I used interface because project has typescript and i used vuexStore. I wanted to work the axios.get in vuex store then i can't assign data to property of state .
/store/index.ts page:
import { createStore } from "vuex";
import axios from "axios";
export interface State {
tasks: any;
}
export default createStore<State> {
state: {
tasks: [],
},
getters: {
getAd(state) {
return state.tasks;
},
},
mutations: {
setTasks: (state, tasks) => {
state.tasks = tasks;
},
},
actions: {
async fetchProfile({ commit }) {
const response = await axios.get(
"https://5dd471358b5e080014dc51d2.mockapi.io/users/"
);
commit("setTasks", response.data);
return response.data;
},
},
modules: {},
};
newcomponent.vue page:
<template>
<div>
<h1>B12 Interactive</h1>
<div>
<h2>Skill Rating System</h2>
</div>
<div><input placeholder="Person/App/Rate" /></div>
<div>
<div class="vl"></div>
<hr />
<div class="v2"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useStore } from "vuex";
export default defineComponent({
setup() {
const store = useStore();
const test = ref(
store.dispatch("fetchProfile")
); /*i can get data this line but
can't use with v:bind:key="item.id" in template block as v-for loop.This line is working in console.log() Array.length is higher than zero */
console.log(
"store:",
store.state.tasks
); /*i can't get data because data can't
assign to property in state. this line isn't working in console.log() Array.length is zero */
return {
test,
};
},
});
</script>

Related

Vuex Mutation not updating the State

Working on a Vuejs application whereby I use Vuex for state management between the components.In Vuex store, I have an action that fetches some data from an API (which works fine) then populate it to the state (via a mutation). Next, I pass the updated state to the component using getters.
The problem is there is a problem populating data to the state from the action. In the DOM I have tried fetching via computed property or using the getter but get empty string
Vuex Store
const getDefaultState = () => {
return {
clientDeposit: ''
}
}
//state
const state = getDefaultState();
//getters
const getters = {
getDeposit: (state) => state.clientDeposit
}
//actions
const actions = {
fetchClients({ commit}) {
const clientId ="23"
axios.post('/api/motor/fetchClients', {
ClientId: clientId,
})
.then((response)=> {
//console.log(response); //returns data
const deposit = response.data;
commit('setIpfDeposit', deposit);
})
}
}
//mutations
const mutations = {
setIpfDeposit: (state, value) => (state.clientDeposit = value)
}
export default {
state,
getters,
actions,
mutations
}
Component
<template>
<div>
<button onclick="fetchClients()">Fetch Clients</button>
Deposit (Via computed property) : {{ fetchDeposit }}
Deposit (from getter) : {{ getDeposit }}
</div>
</template>
<script>
import { mapGetters , mapActions } from "vuex";
import axios from "axios";
export default {
name: "",
data() {
return {
}
},
computed: {
...mapGetters([
"getDeposit"
]),
fetchDeposit(){
return this.getDeposit
},
},
methods:{
...mapActions([
"fetchClients"
])
}
};
</script>
<style scoped>
</style>
You need to fetch the data first.
Import mapActions from vuex
import {mapActions, mapGetters} from 'vuex';
Bring in the fetchClients method in your component's methods object
methods:{
... mapActions(['fetchClients']),
}
Then in your component's created life cycle method call the fetchClients method
created(){
this.fetchClients();
}

Pass Laravel data to Vue component using vue router

I have a laravel collection that should pass json data to a vue component
$problems = $maintenance->getMaintenanceTypes();
return new MaintenanceTypesCollection($problems);
I'm then creating a radio button using that json collection
<div v-for="m_type in maintenance_types" :key="m_type.id">
<input type="radio" v-model="form.m_type" :value="m_type.id" :id="m_type.id">
<label :for="m_type.id">{{ m_type.problem }}</label>
</div>
and the data is being passed well when I'm using Laravel web routing but when I switch to Vue router the data is not being passed at all.
For reference here is my routes/api.php
Route::get('/maintenance/types', 'Maintenance\MaintenanceTypesController#index');
Here is my Vuex store
import axios from 'axios'
import { data } from 'jquery'
export default {
namespaced: true,
state:{
maintenance_types: []
},
getters:{
maintenance_types (state) {
return state.maintenance_types
}
},
mutations:{
PUSH_M_TYPE (state, data) {
state.maintenance_types.push(...data)
}
},
actions:{
async getMaintenanceTypes ({ commit }) {
let response = await axios.get('/maintenance/types')
commit('PUSH_M_TYPE', response.data.data)
}
}
}
And here is my Vue component script logic
import { mapGetters, mapActions } from 'vuex'
import axios from 'axios'
export default {
data () {
return {
form: {
description: '',
m_type: ''
}
}
},
computed: {
...mapGetters({
maintenance_types: 'maintenance/maintenance_types'
})
},
methods: {
...mapActions({
getMaintenanceTypes: 'maintenance/getMaintenanceTypes'
}),
async submit () {
await axios.post('/api/maintenance/store', this.form)
}
},
mounted () {
this.getMaintenanceTypes()
}
}
When I'm using this Vue routing it is not working
import AppMaintenanceForm from './components/maintenance/AppMaintenanceForm.vue'
export const routes = [
{
path: '/maintenance/form',
component: AppMaintenanceForm,
name: 'MaintenanceForm'
},
]
but when I switch to Laravel's routes/web.php it is working. What could be the problem? Thanks.

Vuex: Getter is not fetching data from external API

I'm trying to fetch data from an external API and display the data in my component but it is returning an empty array when I actually have data in my API.
Inside my module I have the following:
import axios from 'axios';
const state = {
countries = []
}
const getters = {
allCountries: (state) => state.countries;
}
const actions = {
//Fecth all the countries from the API
async fetchCountries({ commit }) {
const response = await axios.get('URL');
commit('setCountries', response.data);
},
}
const mutations = {
setCountries: (state, countries) => (state.countries = countries),
}
export default {
state,
getters,
actions,
mutations,
};
Component:
<template>
<div v-for="country in allCountries" :key="country.id">
<small>{{country.name}}</small>
</div>
</template>
<script>
import { mapGetters} from 'vuex';
export default{
name: 'CompCountry',
computed: mapGetters(['allCountries'])
}
</script>
You're missing to dispatch the action, to do that you should run it in a life cycle hook like mounted :
<template>
<div v-for="country in allCountries" :key="country.id">
<small>{{country.name}}</small>
</div>
</template>
<script>
import { mapGetters} from 'vuex';
export default{
name: 'CompCountry',
computed:{ ...mapGetters(['allCountries']},
mounted(){
this.$store.dispatch('fetchCountries')
}
}
</script>

How to map state back to component in Vue.js AWS Amplify auth page

I am building an authentication page with Vue.js, Vuex, and AWS Amplify.
This auth page is based off Erik Hanchett's AWS Auth Example (https://github.com/ErikCH/Aws-auth-example/blob/master/src/components/HelloWorld.vue). Erik's original demo utilized Vuex for state management, but for the sake of simplicity only employs the state handler in the store.js file.
I am attempting to reconfigure this demo so that the various methods and hooks in HelloWorld.vue are set up to also dispatch actions and commit mutations.
So far, I have been successful in setting up the findUser() method in HelloWorld.vue to dispatch actions, pass user and signedIn as payloads to their respective action handlers, and then commit mutations.
However, my issue now pertains to the computed property in the HelloWorld component.
Erik's original demo returns the state directly to the component using return this.$store.state.signedIn as seen in the computed property. Based on my experience with Vuex in other projects, I would normally use a mapState helper to map directly to the state.
Is it correct in this project to use this.$store.state.signedIn to return the state? Or should I use mapState? If so, how can I reconfigure this computed property in order to employ mapState to map directly to signedIn?
My code is below:
HelloWorld.vue
<template>
<div class="hello">
<div v-if="!signedIn">
<amplify-authenticator></amplify-authenticator>
</div>
<div v-if="signedIn">
<Home></Home>
</div>
</div>
</template>
<script>
import { Auth } from 'aws-amplify'
import { AmplifyEventBus } from 'aws-amplify-vue';
import { mapState } from 'vuex'
import Home from '../components/Home.vue'
export default {
name: 'HelloWorld',
components: {
Home
},
data() {
return {
login: '',
password: ''
}
},
props: {
msg: String,
},
created(){
this.findUser();
AmplifyEventBus.$on('authState', info => {
if(info === "signedIn") {
this.findUser();
} else {
this.$store.state.signedIn = false;
this.$store.state.user = null;
}
});
},
computed: {
signedIn(){
return this.$store.state.signedIn;
}
},
methods: {
async findUser() {
try {
const user = await Auth.currentAuthenticatedUser();
let signedIn = true
this.$store.dispatch('setUser', user)
this.$store.dispatch('setSignedIn', signedIn)
}
catch(err) {
let signedIn = false
this.$store.dispatch('setSignedIn', signedIn)
}
}
}
}
</script>
Store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: null,
signedIn: false
},
mutations: {
setUser(state, user) {
state.user = user
},
setSignedIn(state, signedIn) {
state.signedIn = signedIn
}
},
actions: {
setUser: (context, user) => {
context.commit('setUser', user)
},
setSignedIn: (context, signedIn) => {
context.commit('setSignedIn', signedIn)
}
}
})
Home.vue
<template>
<div class="goodbye">
<h1>HOME</h1><br>
<amplify-sign-out></amplify-sign-out>
</div>
</template>
<script>
import { Auth } from 'aws-amplify'
export default {
name: 'Home',
data() {
return {
login: '',
password: ''
}
},
props: {
msg: String,
},
methods: {
signOut() {
Auth.signOut()
}
}
}
</script>
The mapState helper is just sugar syntax for not repeating multiple times the whole this.$store.state.foo piece of code.
You can certainly use mapState like this
import { mapState } from 'vuex'
computed: mapState([
// map this.signedIn to this.$store.state.signedIn
'signedIn'
])
Or like this if you want to also use local properties besides the ones of mapState
import { mapState } from 'vuex'
computed:
localComputed () { /* ... */ },
...mapState([
// map this.signedIn to this.$store.state.signedIn
'signedIn'
])
Here are the docs for more information on this.

Vuex computed property not updating v-show

I have a simple Vuex module with one object: selectedEvent.
I am able to update my selected event using:
<Event :event="selectedEvent" />
However, I am unable to update the visibility of this property using a computed getter defined in the module:
<Event :event="selectedEvent" v-show="isEventSelected" />
My computed values in App.js:
computed: mapState({
selectedEvent: state => state.events.selectedEvent,
isEventSelected: state => state.events.isEventSelected
})
I'm aware that Vue has trouble observing some Object/ Array changes, so I have used Vue.set in my mutation. I have also attempted to move v-show inside the Event component, with no success.
If I move the getter logic inside the v-show, it works fine (however it's messy), e.g.:
<Event :event="selectedEvent" v-show="selectedEvent.hasOwnProperty('id')" />
I'm fairly new to Vue - What am I missing here?
store/modules/events.js:
import { EVENT_SELECT } from "./types";
import Vue from "vue";
const state = {
selectedEvent: {}
};
const getters = {
selectedEvent: state => {
return state.selectedEvent;
},
isEventSelected: state => {
return state.selectedEvent.hasOwnProperty("id");
}
};
const actions = {
setSelectedEvent({ commit }, selectedEvent) {
commit(EVENT_SELECT, selectedEvent);
}
};
const mutations = {
[EVENT_SELECT](state, selectedEvent) {
Vue.set(state, "selectedEvent", selectedEvent);
}
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
};
App.vue:
<template>
<div id="app">
<b-container>
<Calendar />
<Event :event="selectedEvent" v-show="selectedEvent.hasOwnProperty('id')"/>
</b-container>
</div>
</template>
<script>
import Calendar from "./components/Calendar.vue";
import Event from "./components/Event.vue";
import { mapState } from "vuex";
export default {
name: "app",
components: {
Calendar,
Event
},
computed: mapState({
selectedEvent: state => state.events.selectedEvent,
isEventSelected: state => state.events.isEventSelected
})
};
</script>
In your store, isEventSelected is a getter, not a state property so you should use mapGetters, eg
import { mapState, mapGetters } from 'vuex'
// snip
computed: {
...mapState('events', ['selectedEvent']),
...mapGetters('events', ['isEventSelected'])
}

Categories

Resources