How to access a mapAction method using Vuejs? - javascript

Regards,
I would like to know how I can access the logOut function that comes from mapActions,
What I do not understand is how it is possible, that with the logIn function when I refer to it, it works for me but with the function of logOut no.
Here is the error: Uncaught ReferenceError: logOut is not defined
Here I leave the code:
<template>
<div class="home">
<v-card height="200px" flat dark app>
<div class="headline text-xs-center pa-5">
Active: {{ bottomNav }}
</div>
<v-bottom-nav :active.sync="bottomNav" :value="true" absolute color="transparent">
<v-btn color="teal" flat value="messages">
<span>Messages</span>
<v-icon>chat</v-icon>
</v-btn>
<v-btn color="teal" flat value="notifications">
<span>Notifications</span>
<v-icon>notifications</v-icon>
</v-btn>
<v-btn color="red" #click.prevent="logIn()" flat value="logIn">
<span>LogIn</span>
<v-icon>whatshot</v-icon>
</v-btn>
<v-menu offset-y origin="center center" :nudge-bottom="10" transition="scale-transition">
<v-btn icon large flat slot="activator">
<v-avatar size="30px">
<img src="../assets/logo.png" alt="user-logo"/>
</v-avatar>
</v-btn>
<v-list class="pa-0">
<v-list-tile v-for="(item , index) in items"
:to="!item.href ? { name: item.name } : null"
:href="item.href"
#click.prevent="item.click"
ripple="ripple"
:disabled="item.disabled"
:target="item.target"
rel="noopener"
:key="index"
ref="myBtn"
>
<v-list-tile-action v-if="item.icon">
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>{{ item.title }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-menu>
</v-bottom-nav>
</v-card>
<script>
import { mapActions, mapState } from 'vuex';
export default {
name: 'home',
computed: mapState(['data' , 'loading']),
data(){
return{
bottomNav: 'LogIn',
items: [
{
icon: 'account_circle',
href: '#',
title: 'Profile',
click: ''
},
{
icon: 'settings',
href: '#',
title: 'Settings',
click: ''
},
{
icon: 'fullscreen_exit',
href: '#',
title: 'Logout',
click: () =>{
this.logOut();
}
}
]
}
},
methods:{
...mapActions(['logIn' , 'logOut']),
},
}
</script>
Actions.js
Im getting this error: Uncaught TypeError: Cannot set property 'data' of undefined this error is pointing to the mutation file in the UPDATE_DATA.
import { GROUP_ID } from '../config/env';
export const actions = {
logIn({state , commit}){
FB.login((res) =>{
console.log(res);
if(res.status == "connected"){
state.user.id = res.authResponse.userID;
state.user.accessToken = res.authResponse.accessToken;
console.log("user:%s\ntoken:%s" , state.user.id , state.user.accessToken);
FB.api('/me' , (res) =>{
this.user.username = res.authResponse.name;
});
FB.api(`/${GROUP_ID}/feed`,'GET', (res) =>{
if(res && !res.error){
res['data'].forEach((data) =>{
console.log("api connection => " , data);
commit('UPDATE_DATA' , data);
commit('IS_LOADING_DATA' , false);
});
}
});
}
},{scope:'public_profile, email, groups_access_member_info'});
},
logOut({state}){
console.log(state.user.accessToken);
try{
if(FB.getAccessToken() != null) {
FB.logout(function(res) {
console.log("User is logged out");
console.log(res);
});
}else{
console.log("User is not logged in");
}
}catch(err){
console.log(err);
}
}
}
Mutations.js
export const mutations = {
UPDATE_DATA({state} , payload){
state.data = payload;
},
IS_LOADING_DATA({state} , payload){
state.loading = payload;
}
}

If you change to use a non-arrow function in your data click, you'll have access to the correct Vue instance. By using an arrow function, this is not the Vue instance you're expecting and this.logOut will be undefined.

Related

After calling add method from vuex second argument doesn't apply

I create vuex with addNews method Inside of it and pass two arguments, title and body of item. But after calling that method inside my component it only prints my first argument title in HTML. Also i try to console.log body and i get data
This is my method in vuex
async addNews({ commit }, title, body) {
const response = await axios.post(
`https://jsonplaceholder.typicode.com/posts`,
{ title: title, body: body }
);
commit("addNews", response.data);
},
And here is component where I call it
<template>
<div class="text-center">
<v-dialog v-model="dialog" width="500">
<template v-slot:activator="{ on, attrs }">
<v-btn class="mb-5" fab dark color="primary" v-bind="attrs" v-on="on">
<v-icon dark> mdi-plus </v-icon>
</v-btn>
</template>
<v-card>
<v-card-title class="text-h5 blue lighten-2">
ADD NEW POST
</v-card-title>
<v-text-field v-model="title" required></v-text-field>
<v-text-field v-model="body" required></v-text-field>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="primary"
class="mr-4"
#click="
onSubmit();
dialog = false;
"
>
Do It
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "AddNews",
data() {
return {
title: "",
body: "",
dialog: false,
};
},
methods: {
...mapActions(["addNews"]),
onSubmit() {
this.addNews(this.title, this.body);
this.title = "";
this.body = "";
},
},
};
</script>
Try passing an object with arguments to your action:
async addNews({ commit }, { title, body }) {
const response = await axios.post(
`https://jsonplaceholder.typicode.com/posts`,
{ title, body }
);
commit("addNews", response.data);
},

Pass $route as parameter in axios post request

So I have a vue project with a dashboard that contains many tests and i want to pass the test name as a parameter in an axios request when the user clicks on a button and gets redirected on another page.
I already did the first part and passed the name of the test in route as a parameter name and now i'm trying to fetch the corresponding item in the collection.When using $route.params.name I get an error that says $route is not defined
here's my code so far
<template>
<v-app>
<app-navbar />
<v-main>
<div class="text-center">
<h3>
test {{ $route.params.name }}, {{ $route.query.status }},{{
$route.query.tag
}}
</h3>
<h3 v-if="this.loadAPI">{{failreason()}}</h3>
</div>
<v-data-table
:headers="headers"
:items="imagesref"
:items-per-page="5"
class="elevation-1"
>
<template v-slot:[`item.index`]="{ index }">
{{index+1}}
</template>
<template v-slot:[`item.status`]="{ index }">
{{imagesresult[index][2]}}
</template>
<template v-slot:[`item.ref`]="{ index }">
<v-img :src="imagesref[index]" max-width="750" max-height="750" #click="expref[index] = !expref[index]"/>
<v-overlay :value="expref[index]"><v-img :src="imagesref[index]" max-width="1300" max-height="900" #click="expref[index] = !expref[index]"/> </v-overlay>
</template>
<template v-slot:[`item.test`]="{ index }">
<v-img :src="imagestest[index]" max-width="750" max-height="750" #click="exptest[index] = !exptest[index]"/>
<v-overlay :value="exptest[index]"><v-img :src="imagestest[index]" max-width="1300" max-height="900" #click="exptest[index] = !exptest[index]"/> </v-overlay>
</template>
<template v-slot:[`item.res`]="{ index }">
<v-img :src="imagesresult[index][0]" max-width="750" max-height="750" #click="expres[index] = !expres[index]"/>
<v-overlay :value="expres[index]"><v-img :src="imagesresult[index][0]" max-width="1300" max-height="900" #click="expres[index] = !expres[index]"/> </v-overlay>
</template>
<template #[`item.mis`]="{ index }">
{{Math.round(imagesresult[index][1]*100)/100}}
</template>
<template #[`item.Scrubber`]="{ index }">
<nuxt-link :to="{ path: 'scrubber', query: { imageref: imagesref[index],imagetest:imagestest[index],imageres:imagesresult[index] }}">Show Scrubber</nuxt-link>
</template>
</v-data-table>
</v-main>
</v-app>
</template>
<script>
import appNavbar from "../../../components/appNavbar.vue"
import axios from "axios"
export default {
components: { appNavbar },
name: "App",
data() {
return {
loadAPI:false,
dialog:false,
expref:[],
exptest:[],
expres:[],
items: [],
imagesref: [],
imagestest: [],
imagesresult: [],
headers: [
{ text: 'index',value: 'index',sortable:false},
{ text: 'Status',value: 'status',sortable:false},
{ text: 'Imagesref', value: 'ref',sortable:false },
{ text: 'Imagestest', value: 'test',sortable:false },
{ text: 'Imagesresult', value: 'res',sortable:false },
{ text: 'Mismatch percent', value: 'mis',sortable:false },
{ text: 'Scrubber', value: 'Scrubber',sortable:false },
]
}
},
async created() {
try {
const res = await axios({
method: 'post',
url: 'http://localhost:3002/backend/gettestbyname',
data: {name: $route.params.name}
})
this.items = res.data.data;
this.imagesref = res.data.data[0].refimages;
this.imagestest = res.data.data[0].testimages;
this.imagesresult = res.data.data[0].testresults;
for (let i of this.imagesref){
this.expref.push(false);
this.exptest.push(false);
this.expres.push(false);
}
this.loadAPI=true;
} catch (error) {
console.log(error);
}
},
methods:{
failreason()
{
if (this.items[0].status=="failed"){
let index=0;
for (let i of this.items[0].testresults)
{ console.log(i);
index++;
if (i[2]=="failed")
{
return 'Visual test failed at step number '+index;
}
}
return 'Test set missing screenshots';
}
}
}
}
</script>
<style scoped>
</style>
Globally injected properties in Vue are available from the Vue context, not the global javascript context (like window).
So, in the <script> tag, you have to use this.$router to access it.
In your created hook:
// replace
data: {name: $route.params.name}
//by
data: {name: this.$route.params.name}
From the vue-router docs:
By calling app.use(router), we get access to it as this.$router as well as the current route as this.$route inside of any component:

Data transfer problem between two siblings components (Vue js)

I have three components and one of those is the parent of the others I'm trying to pass an object called talk between siblings emiting it inside an event from FollowedBrowser to LeftBar and then passing it via prop from LeftBar to TalksList component, after that another event is emited by TalksList and listened one more time for LeftBar and finally this component redefine the talk object as an empty object.
This is my parent component LeftBar.
<template>
<v-navigation-drawer width="25%" permanent clipped app light>
<talks-list v-if="inRoute('messages')" :talk="talk" #talkAdded="talkAdded()"/>
<template v-if="inRoute('messages')" v-slot:prepend>
<followed-browser #newTalk="addTalk($event)"/>
</template>
</v-navigation-drawer>
</template>
<script>
import FollowedBrowser from "./FollowedBrowser";
import TalksList from "./TalksList";
import { mapGetters } from "vuex";
export default {
data(){
return {
talk: {}
}
},
components: {
FollowedBrowser,
TalksList
},
methods: {
addTalk(talk){
this.talk = talk;
},
talkAdded(){
this.talk = {};
}
}
}
</script>
And this is my two children:
TalksList.vue
<template>
<v-container class="my-0 px-5">
<v-list flat>
<v-list-item-group class="my-0">
<div class="ma-0 pa-0" v-for="(talk, index) in talks" :key="index">
<v-divider v-if="talk.divider"></v-divider>
<v-list-item v-else class="px-2" style="cursor: pointer">
<template>
<v-list-item-avatar>
<v-img :src="correctedImageUrl(talk.recipient)"></v-img>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>
<span class="blue--text text--lighten-1">{{ completeName(talk.recipient) }}</span>
</v-list-item-title>
<v-list-item-subtitle>
<span>{{ talk.recipient.username }}</span>
</v-list-item-subtitle>
</v-list-item-content>
</template>
</v-list-item>
</div>
</v-list-item-group>
</v-list>
</v-container>
</template>
<script>
import axios from "axios";
export default {
data(){
return {
talks: []
}
},
props: {
talk: {
type: Object,
default: null,
required: true
}
},
watch: {
talk(val){
if(val){
this.talks.splice(0, 1, val);
this.$emit("talkAdded");
}
}
}
}
</script>
FollowedBrowsed.vue
<template>
<div style="display: inline">
<v-dialog scrollable v-model="dialog" max-width="400px" max-height="500px">
<v-card :loading="loading">
<v-text-field dense outlined color="blue lighten-1" label="Nombre de usuario" class="px-5" append-icon="mdi-magnify" v-model="browsedUsername"/>
<v-divider></v-divider>
<v-card-text style="height: 300px;" class="px-2">
<v-list>
<v-list-item class="px-2" style="cursor: pointer" v-for="listUser in filteredFollowed" :key="listUser.id" #click.prevent="newTalk(listUser)">
<v-list-item-content>
<v-list-item-title>
<span class="blue--text text--lighten-1">{{ completeName(listUser) }}</span>
</v-list-item-title>
<v-list-item-subtitle>
<span>{{ listUser.username }}</span>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-dialog>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import axios from "axios";
export default {
data(){
return {
browsedUsername: "",
loading: false,
dialog: false,
skeleton: true,
followed: []
}
},
watch: {
dialog(dialog){
if(!dialog){
this.browsedUsername = "";
this.item = null;
}
}
},
computed: {
...mapGetters({
authenticated: "auth/authenticated",
user: "auth/user"
}),
filteredFollowed(){
return this.followed.filter((user) => {
return user.username.toLowerCase().indexOf(this.browsedUsername.toLowerCase()) !== -1;
})
}
},
mounted(){
axios.get("all_followers_followed/followed")
.then((response) => {
if(response.data){
this.followed = response.data;
this.skeleton = false;
}
})
.catch((error) => {
console.log(error)
});
},
methods: {
async newTalk(user){
this.loading = "blue lighten-1";
await axios.post("messages/new_talk", {recipient_id: user.id})
.then((response) => {
if(response.data){
this.dialog = false;
this.$emit("newTalk", {
messages_number: 0,
recipient: user,
sender: this.user
});
}
})
.catch((error) => {
console.log(error);
});
}
}
}
When the newTalk method is called inside FollowedBrowser component newTalk event is emited but after that my screen freezes like the app was inside infinite loop and I don't know why. I omitted some code that I thought was irrelevant.
Can anybody help me.
Thanks in advance.
I solved... So simple, I just had to get a copy of talk prop inside TalksList, inside watch just put this:
watch: {
talk(val){
if(val){
if(this.talks.length){
this.talks.unshift({ divider: true });
}
let buffer = new Object();
let talk = new Object();
buffer.data = val;
talk = buffer.data;
this.talks.unshift(talk);
}
}
},

Two way data binding in Vue: Unable to update the Parent component from the child component

I got the following two components:
Parent:
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12" class="parent">
<p>Ich bin der Parent component</p>
<button #click="changeDetail" :name.sync="name">Change Details</button>
<Child v-bind:name="name"></Child>
</v-col>
</v-row>
</v-container>
</template>
<script>
import Child from "./Child";
export default {
name: "Parent",
data: () => ({
name: "test"
}),
methods: {
changeDetail() {
this.name = "Updated from Parent";
}
},
components: {
Child
}
};
</script>
Child:
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12">
<p>My name is: {{ name}}</p>
<button #click="resetname">Reset the name</button>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
// props: ["name"],
props: {
name: {
type: String,
required: true
}
},
data: () => ({
newname: "Updated from Child"
}),
methods: {
resetname() {
this.$emit("update:name", this.newname);
}
}
};
</script>
As far as I read here: https://v2.vuejs.org/v2/guide/components-custom-events.html#sync-Modifier, I should use update and sync to pass props from the child back to the parent. However it does not work. I don´t understand what´s wrong here. What am I missing?
It is usually best to not bind your template to the prop but a computed property instead to ensure the data is accessed and modified externally. It will also simplify your code a bit so that you don't have to trigger updates.
Parent:
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12" class="parent">
<p>Ich bin der Parent component</p>
<button #click="changeDetail">Change Details</button>
<Child v-bind:name.sync="name"></Child>
</v-col>
</v-row>
</v-container>
</template>
<script>
import Child from "./Child";
export default {
name: "Parent",
data: () => ({
name: "test"
}),
methods: {
changeDetail() {
this.name = "Updated from Parent";
}
},
components: {
Child
}
};
</script>
Child:
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12">
<p>My name is: {{ currentName }}</p>
<button #click="resetname">Reset the name</button>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
// props: ["name"],
props: {
name: {
type: String,
required: true
}
},
data: () => ({
//Be careful with fat arrow functions for data
//Because the value of *this* isn't the component,
//but rather the parent scope.
}),
computed: {
currentName: {
get() { return this.name },
set(value) { this.$emit("update:name", value); }
}
},
methods: {
resetname() {
this.currentName = "updated from child";
}
}
};
</script>

I can't display properly v-data-table data: ''Invalid prop: type check failed for prop "items". Expected Array, got Object''

I'm starting a project in which I had to use Vue. I'm actually really new to this, so I'm learning on the go. I do apologize in advance since this question have answered before, however, I didn't really understand the solutions provided, which is why I'm here asking myself.
Well, I was trying to display some data on my Data Table (more specifically, v-data-table from Vuetify). I was able to get the data from the API, but, for some reason it doesn't show me anything. Thanks to Vuex I can see that the mutation worked because on the console on Google Chrome I can see the Array of objects. But as I said, it still does't show me a single thing on the table, it even says 'no data available'. Some errors that I get are things like '[Vue warn]: Invalid prop: type check failed for prop "items". Expected Array, got Object' and 'TypeError: this.items.slice is not a function'.
Here is the code from List.vue
<template>
<v-container id="data-tables" tag="section">
<div class="text-right">
<v-btn class="mx-2" fab dark color="primary" :to="{ name: 'UserCreate' }">
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</div>
<base-material-card
color="indigo"
icon="mdi-vuetify"
inline
class="px-5 py-3"
>
<template v-slot:after-heading>
<div class="display-2 font-weight-light">
Lista de Empleados
</div>
</template>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
class="ml-auto"
label="Search"
hide-details
single-line
style="max-width: 250px;"
/>
<v-divider class="mt-3" />
<v-data-table
:headers="headers"
:items="users"
:search.sync="search"
:sort-by="['name', 'office']"
:sort-desc="[false, true]"
multi-sort
>
<template v-slot:item.actions="{ item }">
<v-icon small class="mr-2" #click="editItem(item)">
mdi-eye
</v-icon>
<v-icon
small
class="mr-2"
#click="editItem(item)"
:to="{ name: 'UserUpdate' }"
>
mdi-pencil
</v-icon>
<v-icon small #click="deleteItem(item)">
mdi-delete
</v-icon>
</template>
</v-data-table>
</base-material-card>
</v-container>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'UsersTable',
data() {
return {
headers: [
{
text: 'Nombre',
value: 'empleado.nombre',
},
{
text: 'Apellido',
value: 'empleado.apellido',
},
{
text: 'Dirección',
value: 'empleado.direccion',
},
{
text: 'Correo Electrónico',
value: 'email',
},
{
text: 'Teléfono',
value: 'empleado.telefono',
},
{
sortable: false,
text: 'Actions',
value: 'actions',
},
],
loader: true,
search: undefined,
}
},
created() {
this.$store.dispatch('users/fetchUsers')
},
computed: {
...mapState(['users']),
},
methods: {},
mounted() {},
}
</script>
And the code from user.js, where the fetchUsers it's coming from.
import auth from '#/api/auth'
export const namespaced = true
export const state = {
users: [],
}
export const mutations = {
SET_USERS(state, users) {
state.users = users
},
}
export const actions = {
fetchUsers({ commit, dispatch }) {
auth
.getAllAccounts()
.then((response) => {
commit('SET_USERS', response.data)
})
.catch((error) => {
const notification = {
type: 'error',
message: 'There was a problem fetching users: ' + error.message,
}
dispatch('notification/add', notification, { root: true })
})
},
}
Thanks in advance.
You are not getting the correct user from vuex, because is namespaced, change to:
computed: {
...mapState('users',['users']),
},
MapState helper dosen't work the same way like the other helpers because the state module isn't registred in the global namespace. So namespacing your module will help or you do it in this way:
computed: {
...mapState({
users: state => state.FilenameOfYourModule.users
})
}

Categories

Resources