Property set to undefined on page reload/refresh - vue.js

I have medications object as follow:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
.........
},
{.......},.....
]
I wanted to add another field residentName on this object list or is there any way so that I can display residentName in the v-data-table ?:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
'residentName': 'ad' //set this new field
.........
},
{.......},.....
]
I am using `v-data-table> as :
<v-data-table
:headers="headers"
:items="medications"
:items-per-page="20"
:search="search"
class="elevation-23"
>
Now I want to add an residentName field based on the resident field. For this I did the following:
export default {
data() {
return {
medications: [],
}
},
computed: {
...mapGetters([
'allMedications', //this is used to get all medication from medication store
'getResidentsById',
]),
},
created() {
this.get_resident_list(),
this.get_registered_medication_list();
},
methods: {
...mapActions([
'get_registered_medication_list', //this is used to call API and set state for medication
'get_resident_list', //this is used to callAPI and set state for resident
]),
getResidentName(id) {
const resident = this.getResidentsById(id)
return resident && resident.fullName
},
},
watch: {
allMedications: {
handler: function () {
const medicationArray = this.allMedications;
console.log("Created this");
this.medications = medicationArray.map(medication => ({
...medication,
residentName: this.getResidentName(medication.resident)
})
);
},
immediate: true
},
}
}
This is in resident.js getter module
getResidentsById: (state) => (id) => {
return state.residents.find(resident => resident.id === id)
}
This is setting residentName only when the component is created but if I reload/refresh page then residentName = undefined is set.

Related

Update object property state inside of watch vue

I'm trying to update the selected boolean to true from my lists items array of objects when the from_id property from the items array inside of the entry object matches with the item_id of the object in lists fromData array. The selected property updates but I got this error:
Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] do not mutate vuex store state outside mutation handlers.
store.js
entry: {
items: [
{
from_id: 5,
to_id: 1,
quantity: 100,
},
{
from_id: 11,
to_id: 3,
quantity: 119,
},
{
from_id: 7,
to_id: 3,
quantity: 59,
},
]
}
lists: {
from: [
{
item: {...},
item_id: 5,
selected: false
},
{
item: {...},
item_id: 6,
selected: false,
},
{
item: {...},
item_id: 7,
selected: false,
}
]
}
const getters = {
entry: (state) => state.entry,
lists: (state) => state.lists,
};
This what I've tried
computed: {
...mapGetters('Conversion', ['entry', 'lists']),
from: function () {
return this.lists.from.filter((item) => !item.selected);
},
},
watch: {
from: {
deep: true,
handler: function (items) {
const _entries = this.entry.items;
_entries.map((entry) => {
items
.filter((item) => item.item_id === entry.item_from_id)
.map((item) => (item.selected = !item.selected));
});
},
},
},
The error means what it says. You're mutating the state outside the store. This should happen in mutation/action.
You need to have an action/mutation that modifies the state this way:
mutations: {
toggle(state, id) {
let item = state.items.find(item => item.id === id)
item.selected = !item.selected;
}
}
And dispatch/commit it outside the store:
this.$store.dispatch('toggle', someId)
Vuex is one-way data flow store. You will not able to mutate data directly with the getters, use action/mutation instead. https://vuex.vuejs.org/#what-is-a-state-management-pattern
In your store.js
const store = createStore({
...
mutations: {
patchEntry (state, payload) {
// Your logic here => return _entries
state.entry = Object.assign({}, state.entry, _entries)
}
}
})
In your watcher:
watch: {
from: {
deep: true,
handler: function (items) {
store.commit('patchEntry', items)
});
},
},
},
Ref: https://vuex.vuejs.org/guide/mutations.html#committing-mutations-in-components

Vue.js access variable from method

I try to fetch stocks data from an API. This data should be used to create a chart.js graph.
how do I access in vue.js data to generate a chart.js line chart from the methods http(axios) call?
Is it possible to access the data directly in the mounted component or should I define a const in the section and create the variables there?
<template>
<select v-model="selected">
<option v-for="option in options" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
<div>
<canvas id="myChart" height="200" width="650"></canvas>
</div>
<script>
export default {
mounted() {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
},
],
},
});
},
data() {
return {
selected: "",
prices: [],
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
// JSON responses are automatically parsed.
this_.prices = response.data;
})
},
},
};
</script>
Yes, you can access variables in data() from mounted().
You need to prepend variables with this. when using the Options API
ex: this.prices[0].price
As you are putting watcher on selected but I did not see any changes in the selected variable in your code. As per my understanding you are making an API call to get the graph data based on the selected option.
If Yes, Instead of generating a chart in mounted you can generate it inside your getPrice() method itself based on the response. It should be :
methods: {
getPrice: function () {
var this_ = this;
axios
.get(
"https://site/...."
)
.then((response) => {
this.generateChart(response.data);
})
},
generateChart(prices) {
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: [prices[0].date],
datasets: [
{
label: 'Dataset msft',
data: prices[0].price
},
{
label: 'Dataset google',
data: prices[1].price
}
]
}
});
}
}
Here, a very basic example:
<script>
export default {
async mounted() {
await this.$nextTick();
const ctx = document.getElementById("myChart");
this.chart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [],
},
});
},
data() {
return {
selected: "",
chart: null,
options: [
{ text: "msft", value: "msft" },
{ text: "GOOGL", value: "GOOGL" },
],
};
},
watch: {
selected: function () {
this.getPrice();
},
},
methods: {
async getPrice() {
let { data } = await axios.get("https://site/....");
this.chart.data.datasets = [{ label: "dummy data" , data: [2, 3, 4]}];
this.chart.data.label = [1, 2, 3];
this.chart.update(); //very important, always update it
},
},
};
</script>
You create a property called chart and save your chart to it.
Then, after you fetch your data, you can access your chart with this.chart and then you set your datasets and labels. Whenever you make an change to the chart, use this.chart.update() to update it on the browser.
If you execute this code, you should see some dummy data in the chart

Apexchats.js axios gives me undefined with Vue

I am trying to get data from server using vue and apexcharts, but even after I called data with axios, it gives me undefined..
What have I missed?
template
<apexchart
ref="chart1"
width="100%"
:options="chartOptions" :series="series">
</apexchart>
data from url
{
"pageviews": 1313,
"new_users": 1014
}
script
export default {
data: function () {
return {
series: [],
chartOptions: {
chart: {
type: 'donut',
},
colors: ['#01cd49', '#007568'],
labels: ['new', 're'],
}
},
created: function () {
this.getByVisitor()
},
methods: {
getByVisitor() {
const url = 'url';
axios
.get(url)
.then(response => {
this.$refs.chart1.updateSeries([{
name: 'Sales',
data: response.data
}])
})
.catch(error => (this.byVisitor = error.data));
console.log(`---------------this.$refs.chart1`, this.$refs.chart1);
},
}
See Updating Vue Chart Data
There's no need to directly call the updateSeries() method on the chart component since it is able to react to changes in series. All you have to do is update your series data property
export default {
data: () => ({
series: [], // 👈 start with an empty array here
byVisitor: null, // 👈 you seem to have missed this one for your error data
chartOptions: {
chart: {
type: 'donut',
},
colors: ['#01cd49', '#007568'],
labels: ['new', 're'],
}
}),
created: function() {
this.getByVisitor()
},
methods: {
async getByVisitor() {
const url = 'url';
try {
const { data } = await axios.get(url)
// now update "series"
this.series = [{
name: "Sales",
data
}]
} catch (error) {
this.byVisitor = error.data
}
},
}
}

Add extra field on items of <v-data-table>

I have medications object as follow:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
.........
},
{.......},.....
]
I wanted to add another field residentName on this object list or is there any way so that I can display 'residentName' in the v-data-table ?:
medications: [
{
'name': 'abc',
'id': naks23kn,
'resident': //this is resident id, resident is another object
'residentName': 'ad' //set this new field
.........
},
{.......},.....
]
I am using `v-data-table> as :
<v-data-table
:headers="headers"
:items="medications"
:items-per-page="20"
:search="search"
class="elevation-23"
>
Now I want to add an residentName field based on the resident field. For this I did the following:
export default {
data() {
return {
medications: [],
}
},
computed: {
...mapGetters([
'allMedications', //this is used to get all medication from medication store
'getResidentsById',
]),
},
created() {
this.get_resident_list(),
this.get_registered_medication_list();
},
methods: {
...mapActions([
'get_registered_medication_list', //this is used to call API and set state for medication
'get_resident_list', //this is used to callAPI and set state for resident
]),
getResidentName(id) {
const resident = this.getResidentsById(id)
return resident && resident.fullName
},
},
watch: {
allMedications: {
handler: function () {
const medicationArray = this.allMedications;
console.log("Created this");
this.medications = medicationArray.map(medication => ({
...medication,
residentName: this.getResidentName(medication.resident)
})
);
},
immediate: true
},
}
}
In header
headers: [
{ text: 'Medication Name', value: 'name' },
{ text: 'Resident', value: 'residentName' },
]
This is in resident.js getter module
getResidentsById: (state) => (id) => {
return state.residents.find(resident => resident.id === id)
}
Edit: This is working, i.e I am getting residentName when the page is created but if I refresh the page then I get residentName=undefined
You can use map to add new prop to your each item in array
let medications = [{
name: 'abc',
id: 'naks23kn',
resident: 1
}]
medications.map(item => item.residentName = "Your Resident Name")
console.log(medications)
This should work
watch: {
allMedications: {
handler: function() {
const medicationArray = this.allMedications;
console.log("Created this");
this.medications = medicationArray.map(medication => medication.residentName = this.getResidentName(medication.resident)));
},
immediate: true
},
}

Vue.js : How do I create a form where on submit the input data in the form is added to a table?

I want to create a form where in which the input data is added to a table that is on the next page. With VueJS.
The form has only a name and a dropdown menu.
I just want to input a name and a selected option to the table from the form.
The data from the dropmenu is - I'm unsure how to pull it into the dropdown.
Here is the JSON and my code:
Vue.js:
new Vue({
el: "#app",
data () {
return {
loading: false,
todos: [],
users_todos:[]
}
},
data:
{
currentstep: 1,
steps: [
{
id: 1,
title: "Personal",
icon_class: "fa fa-user-circle-o"
},
{
id: 2,
title: "Details",
icon_class: "fa fa-th-list"
},
{
id: 3,
title: "Send",
icon_class: "fa fa-paper-plane"
}
]
},
methods: {
stepChanged(step) {
this.currentstep = step;
}
},
mounted () {
this.loading = true;
axios.get('https://jsonplaceholder.typicode.com/users/1/todos?page=1')
.then(response => {this.users_todos = response.data})
.catch(error => console.log(error))
.finally(() => this.loading = false)
}
});