1

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?

2 Answers 2

2
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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. When I call this.$set(this.userTools, i, response.data) inside of the for loop, the 0th and 1st indices of this.userTools do not update. Only index 2 updates and is overwritten each time through the loop. Why is this? Maybe a result of calling an async function inside of a for loop?
I can't help you without the ability to inspect. It largely depends on what's inside your response, I guess. Provide a minimal reproducible example and I'll have a look. Make sure it features the problem.
0

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;
}

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.