Cannot read properties of undefined (reading 'element') when accessing event object - vue.js

So I am using Vue Draggable and I am to access the event object in VueJs like below:
<draggable group="leads"
:list="newLeads"
#change="seeChange($event, 'New')">
In methods:
async seeChange(event, status) {
console.log(event.added.element.id);
await axios.patch('http://localhost/api/leads/'+event.added.element.id+'/update-status',
{status : status}).then(response => {
this.leads.unshift(response.data.data);
this.getLeads();
}).catch(error => {
console.log(error);
});
},
I can see the id in the console. But when I drag the card (triggering the event) I get a
Cannot read properties of undefined (reading 'element')
error when the card lands. Even the Axios call gets the correct id and the request is sent fine. But the white screen with this error appears nonetheless.
What am I missing?

Change event is called with one argument containing one of the following properties: added, removed, moved. Docs.
event.added contains information of an element added to the array but when you do removed, moved you haven't property added in object event.
You can use it like this:
async seeChange(event, status) {
console.log(event?.added.element.id);
if(event.added) {
await axios.patch('http://localhost/api/leads/'+event.added.element.id+'/update-status', {status : status}).then(response => {
this.leads.unshift(response.data.data);
this.getLeads();
}).catch(error => {
console.log(error);
});
}
}
request will be send only after added event.
If you want to send request on each event you can do it
by using Object.values(event)[0], example:
async seeChange(event, status) {
const id = Object.values(event)[0].element.id;
console.log(id);
await axios.patch('http://localhost/api/leads/'+id+'/update-status', {status : status}).then(response => {
this.leads.unshift(response.data.data);
this.getLeads();
}).catch(error => {
console.log(error);
});
}

in vue 3 you should use draggable library as below:
install:
npm i -S vuedraggable#next
import:
import Draggable from 'vuedraggable';
and this is the link with full examples:
https://github.com/SortableJS/vue.draggable.next

Related

Vue 2 / Nuxt 2 Emit From Axios With Dialog Confirm

i am using Vue 2 / nuxt to emit from a axios post* call which itself is called from a Buefy dialog confirm. The emit from this component will close the window / panel and then re-load the users.
If I call the axios request from the button, this works without any issues, but once being called from the dialog, it just don't work?
*most likely this will be updated to a delete request, just not gotten to that let
See code below:
removeUser() {
this.$buefy.dialog.confirm({
message: 'Continue on this task?',
onConfirm: () => {
this.removeUserFunc()
}
})
},
removeUserFunc() {
// console.log(that)
const that = this
// Build URL
const EndPoint = '/remove_user/' + this.id
this.$axios.post(EndPoint).then((res) => {
// User Remove Message
UserRemoved(this.$swal)
that.$parent.$emit('completed')
// console.log(this.$emit('complete'))
// // Emit 'completed' Message
console.log(that.$emit('completed'))
console.log(that)
}).catch((res) => {
console.log(res)
// Check For Errors
GeneralError(this.$swal)
})
}
I was thinking it was losing access to the correct this, so i was trying to pass that back in, but not sure that is the case?
I have also tried with await, while that sort of works? I think is firing the emit too fast, as it re-loads the users but it still includes the user that as just been deleted?
removeUser() {
this.$buefy.dialog.confirm({
message: 'Continue on this task?',
onConfirm: async() => {
this.removeUserFunc()
await this.$emit('completed')
}
})
},
The this keyword refers to the object the function belongs to, or the window object if the function belongs to no object.
Try to use .bind and use a ES5 function
removeUser() {
this.$buefy.dialog.confirm({
message: 'Continue on this task?',
onConfirm: function() {
this.removeUserFunc()
}.bind(this)
})
},

VueJS getting "undefined" data from ipcRenderer (ElectronJS)

When trying to get a message from ipcMain to ipcRenderer (without node integration and with contextIsolation), it's received but as undefined. Not only that, but if I were to reload the VueComponent (regardless of what change I make to it), the number of responses gets doubled.
For example, the first time I start my application, I get 1x undefined at a time every time I click the button. If I reload the component, I start getting 2x undefined every time I click the button. I reload again and get 4x undefined every time I click the button... and it keeps doubling. If I restart the application, it goes back to 1x.
SETUP
ElectronJS + VueJS + VuetifyJS has been set up as described here.
preload.js as per the official documentation.
import { contextBridge, ipcRenderer } from 'electron'
window.ipcRenderer = ipcRenderer
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('ipcRenderer', {
send: (channel, data) => {
// whitelist channels
let validChannels = ['toMain']
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data)
}
},
receive: (channel, func) => {
let validChannels = ['fromMain']
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args))
}
}
})
background.js (main process) as per the official documentation for the preload.js file. The omitted code via ... is the default project code generated upon creation.
...
const path = require('path')
const { ipcMain } = require('electron')
async function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
},
icon: 'src/assets/icon.png',
})
ipcMain.on('toMain', (event, data) => {
console.log(data)
event.sender.send('fromMain', 'Hello IPC Renderer')
// The two lines below return 'undefined' as well in the 'ipcRenderer'
//win.webContents.send('fromMain', "Hello IPC Renderer")
//event.reply('fromMain', 'Hello IPC Renderer')
})
...
}
...
vue.config.js file:
module.exports = {
...
pluginOptions: {
electronBuilder: {
preload: 'src/preload.js',
}
}
}
main.js (renderer process) contains only the default project code generated upon creation.
VueComponent.vue
<template>
<div id="vue-component">
<v-btn #click="sendMessageToIPCMain()">
</div>
</template>
<script>
export default {
name: "VueComponent",
components: {
//
},
data: () => ({
myData: null,
}),
methods: {
// This works. I get 'Hello IPC Main' in the CMD console.
sendMessageToIPCMain() {
var message = "Hello IPC Main"
window.ipcRenderer.send("toMain", message);
}
},
mounted() {
window.ipcRenderer.receive('fromMain', (event, data) => {
// this.myData = data // 'myData' is not defined error
this.$refs.myData = data;
console.log('myData variable: ' + this.$refs.myData) // undefined
console.log(data) // undefined
})
},
}
</script>
The VueComponent.vue's mounted() has been set up as described here, though If I try to send the data to a variable using this.myData = data, I get an error saying that myData has not been defined - using this.$refs.myData works, though it's still undefined.
P.S. myData has not been defined error =/= undefined. The former is a proper error in red letters while the latter is as seen in the image above.
For solving the first problem (doubling of function calls) you have to remove window.ipcRenderer = ipcRenderer. In contextIsolation mode the approach is to use contextBridge.exposeInMainWorld() only. Using both implementation definitely causes issues.
For the second problem, the callback to receive in ipcRenderer is called with only ...args from main (no event passed to func). see:
ipcRenderer.on(channel, (event, ...args) => func(...args)) <-- func() is called with only args
The only thing you should change is your function in mounted, to accept only data:
window.ipcRenderer.receive('fromMain', (data) => {
console.log(data) // should log you data
})

How to get access to store from action in VueJS?

Im using VueJS and Vuex. I have the userid into the store, this way:
vuex screenshot
And i try pass the userid to a fetch, but vuejs return error
([Vue warn]: Error in created hook: "TypeError: this.$store is
undefined")
import { LOAD_APPOINTMENTS } from './types'
export default {
loadProducts ({ commit }) {
var user = this.$store.state.user.userid
fetch('api/appointments/' + user)
.then((result) => {
return result.json()
})
.then((appointments) => {
commit(LOAD_APPOINTMENTS, appointments)
})
.catch(er => {
console.log(er)
})
}
}
First, when referencing the store within vuex files:
context.state instead of this.$store.state.
context for all of the this.$store. So, context.commit and context.dispatch.
Second, the loadProducts needs to be rewritten as an action per docs.
Third, loadProducts needs to incorporate the context as a parameter:
actions: {
loadProducts (context) {
...
context.commit(...)
...
}
}
As #phil has mentioned in this thread, it is important to view the documentation entirely, as this single answer will get you on the way to debugging the problem, but there might be multiple more problems showing up (e.g. fetch errors, file structure errors, component/App level errors).

Unable to access `get` method in vue-resource

I have a tiny vue app where I'm wanting to use vue-resource to request an api endpoint.
I've installed vue-resource via npm
I've added the Vue.use(VueResource) lines to my bootstrap file
I've setup my component like this to call the .get method
Blog.vue
...
mounted () {
this.fetchPosts()
},
methods: {
fetchPosts: () => {
debugger;
this.$http.get('my-url')
.then(response => {
console.log(response)
})
}
}
...
I've seen a few github issues and SO posts which touch on this type of problem but most seem to relate to incorrect configuration which I don't think I have (happy to be proven wrong!)
The specific console error I get is:
Error in mounted hook: "TypeError: Cannot read property 'get' of undefined"
What's odd about this is that if you see my debugger line, if I console.log this.$http.get at that point I get:
function (url, options$$1) {
return this(assign(options$$1 || {}, {url: url, method: method$$1}));
}
If I let the code run and then attempt the console.log afterwards I get:
Cannot read property 'get' of undefined
As a result I presume it's some kind of this context issue, but from what I can see the reference should be correct...shouldn't it?
Methods should not be arrows function. The this will not point to the vue instance if a methods is declared using arrow function.
Use normal function instead:
methods: {
fetchPosts(){
debugger;
this.$http.get('my-url')
.then(response => {
console.log(response)
})
}
You can see the warning here

Vue not reacting to data change

I have the following vue2 code
methods: {
open: function(conversation){
conversation.loading = true;
this.$set(this, 'activeConversation', conversation);
this.$http.get('/conversation/messages', {
params: {
conversationId: conversation.id
}
}).then((response) => {
// this.$set(this.activeConversation, 'messages', response.data); // this was the first try
this.activeConversation.messages.push(response.data[0]); // this is the second try
})
}
}
The template reacts to the first $set when i change the activeConversation. But when I change the messages property of the activeConversation nothing happens.
I see the changes in vue devtools, but nothing changes in the DOM.
By nothing changes, I mean the v-for="message in activeConversation.messages" does not render anything. nor does the {{activeConversation}}
in data i have activeConversation: null. As a conversation i pass an object with id, sender, messages