Reputation: 1531
In a vue.js application, I am trying to populate an array with content from a java/postgresql backend using axios. I understand vue does not track changes to an array unless you use the $set keyword. When I use the $set keyword, I run into this error message:
ManageTools.vue?45c2:109 Uncaught (in promise) TypeError: >_this2.userToolsIds.$set is not a function at eval (ManageTools.vue?45c2:109)
I have tried setting vm=this at the beginning of my functions as detailed here... TypeError: this.$set is not a function This did not help.
What must I change?
<template>
<div class="card">
<div class="card-header">
<h3 class="card-title">
Tools
</h3>
</div>
<div class="card-body">
<div class="row row-eq-height">
<div class="col">
<FormDropdown
:field-content="selectedTool"
field-label="Tools"
field-name="tool"
:field-choices="tools"
field-description="Select a tool and click 'install' to install."
@updateValue="updateValue"
></FormDropdown>
<div class="row mt-2 mb-2">
<div class="col">
<button class="btn btn-primary" @click.prevent="installTool">Install Tool</button>
</div>
</div>
</div>
{{finishedFetchingToolIds}} {{finishedFetchingToolsInfo}}
<div class="col col-md-6" v-if="finishedFetchingToolsInfo">
Installed Tools
{{userTools}}
<ul>
<li v-for="tool in userTools" :key="tool">
toolname
{{tool.toolname}}
</li>
</ul>
</div>
</div>
</div>
<div v-if="showTool">
<foo>
</foo>
</div>
</div>
</template>
<style>
</style>
<script>
import axios from 'axios';
import store from "../store.js";
import FormDropdown from "@/components/FormDropdown";
export default {
name: "ManageTools",
components: {
foo: () => import('../test-plugin.js'),
FormDropdown
},
data() {
return {
showTool: false,
tools: ['mass-emailer', 'auto-text-messenger'],
selectedTool: 'mass-emailer',
userToolsIds: [],
userTools: [],
user_id: 2,
finishedFetchingToolIds: false,
finishedFetchingToolsInfo: false
}
},
methods: {
installTool() {
this.showTool = true;
console.log("showing tool");
},
updateValue() {
console.log("updating value");
}
},
watch: {
finishedFetchingToolIds() {
console.log("in watch for finishedFetchingToolIds")
for (var i = 0; i < this.userToolsIds.length; i++) {
axios.get("/tools/"+this.userToolsIds[i]).then(
response => {
console.log("tool info: "+response.data.toolname);
this.userTools.$set(i, response.data);
console.log("userTools[i]: "+this.userTools[i]);
console.log("finishedFetchingToolsInfo: "+this.finishedFetchingToolsInfo);
},
error => {
store.setAxiosErrorMessage("Failed to display tool info", error);
}
);
}
this.finishedFetchingToolsInfo = true;
}
},
mounted() {
console.log("mounted");
axios.get("/tools/installed_tools").then(
response => {
console.log("response.data[0] "+response.data[0].tool_id);
for (var i = 0; i< response.data.length; i++) {
console.log("iter = "+ i);
console.log("tool id: "+response.data[i].tool_id);
this.userToolsIds.$set(i, response.data[i].tool_id);
}
console.log("userToolsIds length: "+this.userToolsIds.length);
this.finishedFetchingToolIds = true;
},
error => {
store.setAxiosErrorMessage("Failed to display user tools info", error);
}
);
}
};
</script>
Is it okay to use arrays here or would objects be more suitable?
Upvotes: 1
Views: 628
Reputation: 90188
this.userToolsIds.$set(i, response.data[i].tool_id);
...should be:
this.$set(this.userToolsIds, i, response.data[i].tool_id);
..., which populates this.userToolsIds[i]
with response.data[i].tool_id
.
The ViewModel has a $set
method, not your data.
See documentation.
Upvotes: 2
Reputation: 1531
The solution to my follow-up question was to add the async/await keywords to the axios call that is inside the for-loop.
watch: {
async finishedFetchingToolIds() {
for (var j = 0; j < this.userToolsIds.length; j++) {
await axios.get("/tools/"+this.userToolsIds[j]).then(
response => {
this.$set(this.userTools, j, response.data);
},
error => {
store.setAxiosErrorMessage("Failed to display tool info", error);
}
);
}
this.finishedFetchingToolsInfo = true;
}
}
Upvotes: 0