VueJS - function in import js file not getting triggered - vue.js

We are building a web application using Vue JS and PHP, we are new to Vue JS. The server-side execution is fine, the API is able to fetch data as JSON. While trying out a static array display before making the API call, we find that the function in imported "app.js" is not getting called and the table displayed is empty. Please let us know what we might be doing wrong. Appreciate your help.
import Vue from 'vue';
export const MY_CONST = 'Vue.js';
export let memberList = new Vue({
el: '#members',
data: {
members: []
},
mounted: function () {
this.getAllMembers();
},
methods: {
getAllMembers: function () {
/*
axios.get("https://xxxxxx.com/services/api.php")
.then(function (response) {
memberList.members = response.data.members;
});
*/
memberList.members = [{ "empname": "Dinesh Dassss" },
{ "empname": "Kapil Koranne" }];
}
}
});
This is the Vue component. The members object is empty.
<script>
import * as mykey from './app.js'
export default {
name: 'Home',
props: {
msg: String
},
data() {
return {
message: `Hello ${mykey.MY_CONST}!`,
members: mykey.memberList.members
}
}
};
</script>

You can also use this reference for current instance reference:
getAllMembers: function () {
var me = this;
/*
axios.get("https://xxxxxx.com/services/api.php")
.then(function (response) {
// direct this not works here but we have
//saved this in another variable and scope of a var is there
me.members = response.data.members;
});
*/
// this reference works fine here.
this.members = [{ "empname": "Dinesh Dassss" },
{ "empname": "Kapil Koranne" }];
}

Related

How to get the this instance in vue 3?

In vue 2+ I can easily get the instance of this as a result I can write something like this,
// main.js
app.use(ElMessage)
// home.vue
this.$message({
showClose: true,
message: 'Success Message',
type: 'success',
})
What should I do for vue 3 as,
Inside setup(), this won't be a reference to the current active
instance Since setup() is called before other component options are
resolved, this inside setup() will behave quite differently from this
in other options. This might cause confusions when using setup() along
other Options API. - vue 3 doc.
Using ElMessage directly
ElementPlus supports using ElMessage the same way as $message(), as seen in this example:
import { ElMessage } from 'element-plus'
export default {
setup() {
const open1 = () => {
ElMessage('this is a message.')
}
const open2 = () => {
ElMessage({
message: 'Congrats, this is a success message.',
type: 'success',
})
}
return {
open1,
open2,
}
}
}
Using $message()
Vue 3 provides getCurrentInstance() (an internal API) inside the setup() hook. That instance allows access to global properties (installed from plugins) via appContext.config.globalProperties:
import { getCurrentInstance } from "vue";
export default {
setup() {
const globals = getCurrentInstance().appContext.config.globalProperties;
return {
sayHi() {
globals.$message({ message: "hello world" });
},
};
},
};
demo
Note: Being an internal API, getCurrentInstance() could potentially be removed/renamed in a future release. Use with caution.
Providing a different method where the idea is to set a globally scoped variable to the _component property of the viewmodel/app or component:
pageVM = Vue.createApp({
data: function () {
return {
renderComponent: true,
envInfo: [],
dependencies: [],
userGroups: []
}
},
mounted: function () {
//Vue version 3 made it harder to access the viewmodel's properties.
pageVM_props = pageVM._component;
this.init();
},

How to use Nuxt Context to call Axios request with param

so I'm trying to get my Axios to do a get request with a param that'll end the url in
'/?user= {id}'
the id is passed in by my loggedInUser.id from Vuex. I know that async functions won't accept 'this' inside the call so I included store as a parameter. Something's still off with how I passed the data around thought I think. Would appreciate any help, thanks!
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["loggedInUser"])
},
head() {
return {
title: "Actors list"
};
},
components: {
EditProfile
},
async asyncData({ store }) {
try {
const body = { data: store.getters.loggedInUser.id };
const { actors } = await $axios.$get(`/api/v1/actors/`, {
params: {
user: body
}
});
return { actors };
} catch (e) {
return { actors: [] };
}
},
data() {
return {
actors: []
};
Edit
I got it to work when I removed the data: from 'const body' and removed the brackets as well around 'actor'
try {
const body = store.getters.loggedInUser.id;
const actors = await $axios.$get(`/api/v1/actors/`, {
params: {
user: body
}
});
You can access your params from Context.
Context is available in special nuxt lifecycle areas like asyncData, fetch, plugins, middleware and nuxtServerInit.
In Nuxt, with asyncData hook you can get query parameters from the route context key.
Please read the Nuxt.js Context documentation. The context provides additional objects/params from Nuxt to Vue components
With your-domain/?user=wonderman
asyncData({ route: { query: queryParams} }) {},
variable queryParams is an object:
{ user: "wonderman" }

VueJS How to access Mounted() variables in Methods

I'm new in Vue and would like assistance on how to access and use variables created in Mounted() in my methods.
I have this code
Template
<select class="controls" #change="getCatval()">
Script
mounted() {
var allcards = this.$refs.allcards;
var mixer = mixitup(allcards);
},
methods: {
getCatval() {
var category = event.target.value;
// I want to access mixer here;
}
}
I can't find a solution anywhere besides this example where I could call a method x from mounted() and pass mixer to it then use it inside my getCatval()
Is there an easier way to access those variables?
I will first suggest you to stop using var, and use the latest, let and const to declare variable
You have to first declare a variable in data():
data(){
return {
allcards: "",
mixer: ""
}
}
and then in your mounted():
mounted() {
this.allcards = this.$refs.allcards;
this.mixer = mixitup(this.allcards);
},
methods: {
getCatval() {
let category = event.target.value;
this.mixer
}
}
like Ninth Autumn said : object returned by the data function and props of your components are defined as attributes of the component, like your methods defined in the method attribute of a component, it's in this so you can use it everywhere in your component !
Here an example:
data() {
return {
yourVar: 'hello',
};
},
mounted() { this.sayHello(); },
method: {
sayHello() { console.log(this.yourVar); },
},
Update
you cannot pass any value outside if it's in block scope - Either you need to get it from a common place or set any common value
As I can see, var mixer = mixitup(allcards); is in the end acting as a function which does some operation with allcards passed to it and then returns a value.
1 - Place it to different helper file if mixitup is totally independent and not using any vue props used by your component
In your helper.js
const mixitup = cards => {
// Do some operation with cards
let modifiedCards = 'Hey I get returned by your function'
return modifiedCards
}
export default {
mixitup
}
And then in your vue file just import it and use it is as a method.
In yourVue.vue
import Helpers from '...path../helpers'
const mixitup = Helpers.mixitup
export default {
name: 'YourVue',
data: ...,
computed: ...,
mounted() {
const mixer = mixitup(allcards)
},
methods: {
mixitup, // this will make it as `vue` method and accessible through
this
getCatval() {
var category = event.target.value;
this.mixitup(allcards)
}
}
}
2- Use it as mixins if your mixitup dependent to your vue and have access to vue properties
In your yourVueMixins.js:
export default {
methods: {
mixitup(cards) {
// Do some operation with cards
let modifiedCards = 'Hey I get returned by your function'
return modifiedCards
}
}
}
And import it in your vue file:
import YourVueMixins from '...mixins../YourVueMixins'
const mixitup = Helpers.mixitup
export default {
name: 'YourVue',
mixins: [YourVueMixins] // this will have that function as vue property
data: ...,
computed: ...,
mounted() {
const mixer = this.mixitup(allcards)
},
methods: {
getCatval() {
var category = event.target.value;
this.mixitup(allcards)
}
}
}

Vuex - Baffling mutation payload in new window/tab

I have a simple VueJS SPA served by Express. Express also handles API endpoints called by Vue front-end.
Express is connected to Postgres, and API endpoints interact with the database (perform basic CRUD operations).
In my database, I have a single "patient" table, with columns "first_name", "last_name", "date_of_birth", and "id".
In the created() hook of PatientList.vue component, database is queried for all patients, and this information is saved to component data, displayed using v-for loop.
My PatientList.vue code is:
<script>
import auth from '#/auth/authenticator';
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientsList',
},
data() {
return {
patients: [],
}
},
computed: {
accessTokenGetter: {
get: function () {
return this.$store.getters.accessToken;
},
},
patientEditStatusGetter: {
get: function () {
return this.$store.getters.g_patientEditStatusCheck;
},
},
},
methods: {
...mapMutations([
'm_startPatientEditProcess',
'm_endPatientEditProcess',
'm_clearPatientEditState',
'm_cachePatient'
]),
cachePatientHandler(ptnt) {
console.log('PatientList.vue method cachePatientHandler', ptnt);
var patientObject = {
'date_of_birth': ptnt.date_of_birth.split('T')[0],
'first_name': ptnt.first_name,
'last_name': ptnt.last_name,
'patient': ptnt.patient,
'uid': ptnt.uid
}
this.m_endPatientEditProcess(false);
this.m_clearPatientEditState('');
this.m_startPatientEditProcess(true);
this.m_cachePatient(patientObject);
},
getPatients() {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://voyager.wrk.health/patients/index');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.setRequestHeader('Cache-control', 'no-cache');
xhr.onload = () => {
var data = JSON.parse(xhr.response);
for( var i=0, r = data.results; i<r.length; i++ ){
this.patients.push(r[i]);
}
};
xhr.onerror = () => {
console.log(xhr.statusText);
};
xhr.send();
},
},
beforeCreate() {
},
created() {
console.log('PatientList.vue created()');
if(auth.isUserLogged()){
this.getPatients();
} else {
router.go('/');
}
},
};
</script>
In order to edit a patient, I have router-link to edit page. Router-link has click-handler, argument passed in is iterable from v-for loop (i.e. single patient object). I have 4 mutations related to this
const mutations = {
m_startPatientEditProcess(state, trueStatus) {
console.log('Vuex patient m_startPatientEditProcess');
state.patientEditStatus = trueStatus;
},
m_endPatientEditProcess(state, falseStatus) {
console.log('Vuex patient m_endPatientEditProcess');
state.patientEditStatus = falseStatus;
},
m_clearPatientEditState(state, emptyString) {
console.log('Vuex patient m_clearPatientEditState');
state.patientDetails.date_of_birth = emptyString;
state.patientDetails.first_name = emptyString;
state.patientDetails.last_name = emptyString;
state.patientDetails.patient = emptyString;
state.patientDetails.uid = emptyString;
},
m_cachePatient(state, patientObj) {
console.log('Vuex patient m_cachePatient, received: ', patientObj);
state.patientDetails.date_of_birth = patientObj.date_of_birth;
state.patientDetails.first_name = patientObj.first_name;
state.patientDetails.last_name = patientObj.last_name;
state.patientDetails.patient = patientObj.patient;
state.patientDetails.uid = patientObj.uid;
},
Also, my PatientEdit.vue code is:
<script>
import { mapMutations } from 'vuex';
export default {
components: {
name: 'PatientEdit',
},
data() {
return {
patientToEdit: {
first_name: '',
last_name: '',
date_of_birth: '',
patient: '',
uid: '',
},
patientDetailsLoaded: false,
}
},
computed: {
patientToEditDetailsGetter: {
get: function() {
return this.$store.getters.g_patientToEditDetails;
}
},
accessTokenGetter: {
get: function() {
return this.$store.getters.accessToken;
}
}
},
methods: {
...mapMutations([
'm_endPatientEditProcess',
'm_clearPatientEditState',
]),
populatePatientEditState() {
const pDeets = this.patientToEditDetailsGetter;
this.patientToEdit.first_name = pDeets.first_name;
this.patientToEdit.last_name = pDeets.last_name;
this.patientToEdit.date_of_birth = pDeets.date_of_birth;
this.patientToEdit.patient = pDeets.patient;
this.patientToEdit.uid = pDeets.uid;
this.patientDetailsLoaded = true;
},
submitUpdatedPatientDetails() {
const payload = Object.assign({}, this.patientToEdit);
const xhr = new XMLHttpRequest();
xhr.open('PUT', `https://voyager.wrk.health/patients/update/${payload.uid}`)
xhr.setRequestHeader('Content-type', 'application/json');
xhr.setRequestHeader('Authorization', `Bearer ${this.accessTokenGetter}`);
xhr.onload = async () => {
try {
await console.log(xhr.response);
await console.log('Sent patient data to update endpoint \n Ready to be redirected.');
await Promise.all([this.m_endPatientEditProcess(false), this.m_clearPatientEditState('')]);
await this.$router.push('/patients/index');
} catch (e) {
throw new Error(e);
}
}
xhr.send(JSON.stringify(payload));
}
},
created() {
this.populatePatientEditState();
},
};
</script>
My reasoning was to avoid unnecessary request to database.
Everything works as intended. I have a store.subscription set up to save Vuex state to localStorage (for session persistence when this application is refreshed).
Store subscription logs state and mutation, everything is normal like so:
First store output
If I open a new tab or window (cookies left untouched), and try to perform the same update operations, my store subscription freaks out, and I cannot auto-populate my PatientEdit page with patient information from Vuex.
According to the output, suddenly mutation is committing things that I never specified like so:
Store output 2
Why does this happen?
Thanks for reading.
NB: If I have missed information necessary to figure this behaviour out, please let me know.
Edit 1:
Vuex store:
import Vue from 'vue';
import Vuex from 'vuex';
import session from './modules/session';
import patient from './modules/patient';
Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
session,
patient,
},
mutations: {
initStore(state) {
console.log('Vuex root state checking for local snapshot');
if (localStorage.getItem('store')) {
console.log('Snapshot found, hydrating...');
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
}
},
},
});
store.commit('initStore');
store.subscribe((mutation, state) => {
console.warn('Subscription detected');
console.log('mutation: ', mutation);
console.log('state: ', state);
localStorage.setItem('store', JSON.stringify(state));
});
export default store;
You end up with a "cannot stringify circular JSON" error, because you are turning the state, but also the getters, mutations and actions into a string. These contain references to the object you are trying to stringify, which results in an infinite loop.
This is not a problem in your first run, because your localStorage is still empty then. You correctly stringify your state, but when you reload the following line runs:
this.replaceState(Object.assign(store, JSON.parse(localStorage.getItem('store'))));
This line replaces your state with your store, extended with what you have in localStorage. If you replace store with state things should work much better.

Cannot access Vue data set within mounted via ajax

I am using Vue2. I am getting json data via ajax in my mounted method. I then set that data to a data variable expecting to be able to access it from other methods outside of mounted, but all I get is an empty observable.
Any suggestions/advice? Thanks for the help.
var vm = new Vue({
el: '#app',
data: function () {
return {
allJson: []
};
},
methods: {
updateTableData: function(isActive) {
// cannot access this.allJson here
}
},
mounted: function() {
$.getJSON(Routes.USERS_GET_JSON, function(json) {
this.allJson = json;
});
}
});
I haven't used jQuery in a long, long time, but if I remember correctly you need to explicitly declare the context of this if you wish to use it within the callback, else you get something unexpected. However, I don't know if $.getJSON supports it even though it's a wrapper. So you can try the following:
$.getJSON(Routes.USERS_GET_JSON, function(json) {
this.allJson = json;
}, {
context: this
})
Or you can use .bind off of the function to scope this
$.getJSON(Routes.USERS_GET_JSON, function(json) {
this.allJson = json
}.bind(this))
Or if you're tranpsiling down with babel (which you probably are) you can use fat arrow syntax:
$.getJSON(Routes.USERS_GET_JSON)
.done( (json) => {
this.allJson = json
})
Or you can just alias this before the $.getJSON
let _self = this
$.getJSON(Routes.USERS_GET_JSON, function(json) {
_self.allJson = json
})
My guess is that this is not bound to your vue instance inside the callback function. Try the following
var vm = new Vue({
el: '#app',
data: function () {
return {
allJson: []
};
},
methods: {
updateTableData: function(isActive) {
// cannot access this.allJson here
}
},
mounted: function() {
const self = this;
$.getJSON(Routes.USERS_GET_JSON, function(json) {
self.allJson = json;
});
}
});