GNG
GNG

Reputation: 1531

$set is not working for updating my array in vue.js

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

Answers (2)

tao
tao

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

GNG
GNG

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

Related Questions