vue js returned value gives undefined error - vue.js

i want to check the returned value of $http.get() but i get undefined value. Here is my vue js code:
var vm = new Vue({
el: '#permissionMgt',
data: {
permissionID: []
},
methods:{
fetchPermissionDetail: function (id) {
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
this.permissionID = data.permissionID; //permissionID is a data field of the database
alert(this.permissionID); //*****this alert is giving me undefined value
});
},
}
});
Can you tell me thats the problem here?.. btw $http.get() is properly fetching all the data.

You need to check what type is the data returned from the server. If #Raj's solution didn't resolve your issue then probably permissionID is not present in the data that is returned.
Do a colsole.log(data) and check whether data is an object or an array of objects.
Cheers!

Its a common js error. Make the following changes and it will work.
fetchPermissionDetail: function (id) {
var self = this; //add this line
this.$http.get('../api/getComplaintPermission/' + id, function (data) {
self.permissionID = data.permissionID; //replace "this" with "self"
});
},
}
the reason is this points to window inside the anonymous function function()
This is a well known js problem. If you are using es2015 you can use arrow syntax (() => { /*code*/ }) syntax which sets this correctly

Related

Event only firing as inline JS statement

I have the following code in a Nuxtjs app in SSR mode.
<Component
:is="author.linkUrl ? 'a' : 'div'"
v-bind="!author.linkUrl && { href: author.linkUrl, target: '_blank' }"
#click="author.linkUrl ? handleAnalytics() : null"
>
The click event in case it's an a tag, will only fire if it's written as handleAnalytics(), but handleAnalytics will not work.
Don't get me wrong the code is working, but I don't understand why.
With classical event binding (#click="handleAnalytics), Vue will auto bind it for you because it sees it's a function.
But when provided a ternary condition, it's not auto binded but wrapped into a anonymous function instead. So you have to call it with parenthesis otherwise you're just returning the function without executing it.
To be clearer, you can write it this way: #click="() => author.linkUrl ? handleAnalytics() : null"
Note: when having a dynamic tag component, I'd suggest to use the render function instead.
This is an advanced technique, but this way you won't bind things to an element that doesn't need it (without having the kind of hack to return null).
Example:
export default {
props: {
author: { type: Object, required: true },
},
render (h: CreateElement) {
const renderLink = () => {
return h('a', {
attrs: {
href: author.linkUrl,
target: '_blank',
},
on: {
click: this.handleAnalytics
},
)
}
const renderDiv = () => {
return h('div')
}
return this.author.linkUrl ? renderLink() : renderDiv()
}
}
Documention: Vue2, Vue3
In javascript functions are a reference to an object. Just like in any other language you need to store this reference in memory.
Here are a few examples that might help you understand on why its not working:
function handleAnalytics() { return 'bar' };
const resultFromFunction = handleAnalytics();
const referenceFn = handleAnalytics;
resultFromFunction will have bar as it's value, while referenceFn will have the reference to the function handleAnalytics allowing you to do things like:
if (someCondition) {
referenceFn();
}
A more practical example:
function callEuropeanUnionServers() { ... }
function callAmericanServers() { ... }
// Where would the user like for his data to be stored
const callAPI = user.preferesDataIn === 'europe'
? callEuropeanUnionServers
: callEuropeanUnionServers;
// do some logic
// ...
// In this state you won't care which servers the data is stored.
// You will only care that you need to make a request to store the user data.
callAPI();
In your example what happens is that you are doing:
#click="author.linkUrl ? handleAnalytics() : null"
What happens in pseudo code is:
Check the author has a linkUrl
If yes, then EXECUTE handleAnalytics first and then the result of it pass to handler #click
If not, simply pass null
Why it works when you use handleAnalytics and not handleAnalytics()?
Check the author has a linkUrl
If yes, then pass the REFERENCE handleAnalytics to handler #click
If not, simply pass null
Summary
When using handleAnalytics you are passing a reference to #click. When using handleAnalytics() you are passing the result returned from handleAnalytics to #click handler.

how can a Buefy toast be made available to all components in a Vue app?

In a component in a Vue app the following method runs after a user clicks a Submit button on a form:
execute() {
let message = '';
let type = '';
const response = this.actionMode == 'create' ? this.createResource() : this.updateResource(this.data.accountId);
response.then(() => {
message = 'Account ' + this.actionMode + 'd for ' + this.data.name;
type = 'is-success';
})
.catch(e => {
message = 'Account <i>NOT</i> ' + this.actionMode + 'd<br>' + e.message;
type = 'is-danger';
})
.then(() => {
this.displayOutcome(message, type);
this.closeModal();
});
}
The displayOutcome() method in that same component looks like this:
displayOutcome(message, type) {
this.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
The code is working fine within the component. Now I'm trying to move the displayOutcome() method into a helpers.js file and export that function so any component in the app can import it. This would centralize maintenance of the toast and prevent writing individual toasts within each component that needs one. Anyhow, when displayOutcome() gets moved over to helpers.js, then imported into the component an error appears in the console when the function is triggered:
I suspect it has to do with referring to the Vue instance so I experimented with the main.js file and changed this
new Vue({
router,
render: h => h(App),
}).$mount('#app');
to this
var vm = new Vue({
router,
render: h => h(App),
}).$mount('#app');
then in helpers.js
export function displayOutcome(message, type) {
// this.$buefy.toast.open({
vm.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
but that resulted in a "Failed to compile." error message.
Is it possible to make displayOutcome() in helpers.js work somehow?
displayOutcome() requres a reference to this to work, which is fine if you define it as a method on your component object (the standard way). When you define it externally however, you just supply any function instead of a method, which is a function "targeted" on an object. This "targeting" is done through this. So when you're passing a simple function from an external file, there's no association to a specific object, and thus no this available.
To overcome this, you can use displayOutcome.apply(thisArg, methodArgs), where thisArg will be whatever is the this reference in your function, and methodArgs are the remaining arguments that are being passed to the function.
So displayOutcome.apply(4, ['some', 'thing']) would imply that the this reference in displayOutcome() becomes 4 in this case.
Further reading:
Understanding "This" in JavaScript
this on MDN
import { displayOutcome } from './component-utils'
// when calling displayOutcome() from within your component
displayOutcome.apply(this, ['Hello World', 'is-info'])
// component-utils.js
export function displayOutcome(message, type) {
// this.$buefy.toast.open({
this.$buefy.toast.open({
duration: type == 'is-danger' ? 10000 : 3500,
position: 'is-bottom',
message: message,
type: type
});
}
You can create an action in Vuex store and dispatch it from any component.

Is it possible to call own Method in Vue data()?

So I'm using Element Vue, I need to get access to a method or to the value of the
acceptedDates
export default {
data() {
return {
acceptedDates: [],
pickerOptions1: {
disabledDate(time) {
return moment(time).isBetween(this.acceptedDates[0], this.acceptedDates[1]);
}
}
};
},
methods: {
//setting acceptedDates method...
}
I get a ReferenceError for this.accptedDates or even without using this. How do you do this?
Update
Thank you for the first anwsers, but I still can't figure it out.
I created this fiddle for you to see: https://jsfiddle.net/05nru5xq/13/
If you go to http://element.eleme.io/#/en-US/component/date-picker you will find that disabledDate is a Function in PickerOption.
Now that I know exactly what you are after, I've updated accordingly to your example https://jsfiddle.net/05nru5xq/31/
some points on your code:
never use capital to name methods, capital letter first is to name Object that can be created with the new attribute;
today is not a moment object so you can't call isBetween on it
from the docs you need to name your options as there's 3 of them, hence specifying the option :picker-options="{ disabledDate: betweenOneWeek }"
data is just a place to hold variables, don't put methods there.
As a side note:
I've done the same (bought it for me) and I'm not in any way affiliated with them, just a happy customer. If you want to know VueJs well enough and quick, try this Udemy course, it's pretty good and worth all the money
In the data section you can define variables with functions but you're not able to do things like you did. Why? It's simple. You're using this which binding to pickerOptions1 object, not data. Even when you use arrow function in object it won't work as well because in that case it will return window object.
Those operations on data you can move to separate function and in my opinion it would be the best way.
For example you can do something like that:
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
customMessage: 'Test ',
testFunction() {
this.customMessage += this.message;
alert(this.customMessage);
}
},
mounted() {
this.testFunction();
}
})
https://jsfiddle.net/mxuh7c9p/
or more suitable to your case:
new Vue({
el: '#app',
data: {
acceptedDates: [],
pickerOptions1: null,
},
methods: {
getDisabledDate(time) {
return moment(time).isBetween(this.acceptedDates[0], this.acceptedDates[1]);
},
setAcceptedDates() {
const disabledDate = this.getDisabledDate(time);
// do something
}
},
mounted() {
//this.getDisabledDate();
}
})
https://jsfiddle.net/mxuh7c9p/13/

Vuex: Referencing specific state data in getter

I have to pull in data from 12 specific departments. When my Vue store gets mounted, I fire off some actions to load in these orders via 12 different ajax calls. (These calls are to different API end points and servers).
Once I get a response I commit them to the state. So in my state I would have the following data set to arrays:
state: {
sportsOrders: [],
photographicOrders: []
//And more..
},
Now I need to filter these specific orders based on if they are late, in production, etc. So I have a getter that is setup like so:
getters: {
getDepartmentLateOrders: (state) => (department) => {
let resultArray = []
state.department.forEach(function(order, index) {
let now = new Date()
let orderShipDate = new Date(order.ExpectedShipDate)
let diff = date.getDateDiff(orderShipDate, now)
if(diff < 0) {
resultArray.push(order)
}
})
return resultArray
},
}
And then when I need to use it in a component...
return this.$store.getters.getDepartmentLateOrders(this.department+'Orders')
//for example it will end up passing 'sportsOrders' to the getter
However, when I do this, Vue doesn't use the state data for sportsOrders so I know I'm not accessing it correctly. It says:
vue.runtime.esm.js?ff9b:574 [Vue warn]: Error in render: "TypeError: Cannot read property 'forEach' of undefined"
If I hardcode my getter like so it works as expected though (but I don't want to do this for 12 departments)..
state.sportsOrders.forEach(function(order, index) {
...
}
How can I set this up so I can use this one getter and have it work with all 12 departments? I only want to pass the name of the department if possible.

Component method response object data binding

I am starting to lose my mind in debugging an application that I inherited from a fellow developer who is absent.
I have narrowed down the problem to the following place in code (php files are checked, Vue instances are initialised, there are no syntax errors).
This is my the component that gets initialised:
var RadniStol = Vue.component('radnistol', {
template: '#template-RadniStol',
data() {
return {
tableData: [],
requestData: {
sort: "ID",
order: "DESC"
}
}
},
methods: {
reloadTable: function (event) {
data = this.requestData;
this.$http.post('php/get/radni_stol.php', data).then(response => {
console.log(response.data.bodyText);
this.tableData = response.data.records;
});
},
.
.
.
The PHP file that gets called with the POST method is working correctly, querying the database and echoing the response in a JSON format.
The thing that is making me pull out my hair is the following: the console.log(response.data) outputs the following into the console:
{"records":[{"DODAN_NA_RADNI_STOL":"1","..."}]}
It is an JSON object that I expected to have but when trying to assign it to the data of the component with:
this.tableData = response.data;
or any other way… response.data.records returns ‘undefined’ in the console. I have tryed with JSON.parse() but no success.
When logging types to console:
response variable is a response object with a status 200 and body and bodyText containing the data from the database.
response.data is a string type containing the string JSON with the data from the database.
When trying to use JSON.parse(response.data) or JSON.parse() on anything in the callback of the POST method I get the following error in the console:
RadniStol.js?version=0.1.1:17 Uncaught (in promise) SyntaxError: Unexpected token in JSON at position 0
at JSON.parse (<anonymous>)
at VueComponent.$http.post.then.response (RadniStol.js?version=0.1.1:17)
at <anonymous>
I am really starting to lose my mind over this issue, please help!
Thank you
If response.data is string, with JSON inside, then to access the records field, you should decode it like this:
JSON.parse(response.data).records
Not sure this has something to do with PHP or Vue.js, it is just plain javascript issue.
If it not decodes, than problem is definitely in response.data. For example
{"records":[{"DODAN_NA_RADNI_STOL":"1","..."}]}
is not a valid JSON, because key "..." needs to have some value.
But it seems to me that response.data is already parsed.
What I suggest you to do, is to write handler of the response as separate function, make response object that mimics actual response object by hand, and then test it separately from request. So you could show us request object and function that works with it.
I had the same error and fixed it.
Result will be response.body not response.data.
Here is my code:
getS: function(page) {
this.$http.get('vue-manager?page=' + page).then((response) => {
var data = JSON.parse(response.body);
this.student = data.data.data;
this.pagination = data.pagination;
});
},