1
votes

I made a small library to track the loading of all my api calls.
It basically is an array which contains objects describing one loading process. I import this library into a Single File Component to make calls to it. I then pass the array from the library to a child component and want to render all my objects in the array (the loading statuses). I see the data updating in Vue Devtools on the child component, however it is not updated in the page.

What i tried:

  • passing the vue instance from the parent component and use $set to update the array
  • using array.splice to update the array
  • creating a new object with Object.assign, update the new object and then update the array (splice/$set)
  • passing a key and updating this key when updating thew object
  • calling methods in the library in the console

sample updating function:

function _finish(name, descFinished) {
        const i = _loaders.findIndex(l => l.name == name);
        if(i < 0) throw new NameNotFoundException(name);
        let loader = Object.assign({}, _loaders[i]);
        if(descFinished != undefined) loader.descFinished = descFinished;
        loader.loading = false;
        loader.error = false;
        loader.endTime = new Date();
        vm.$set(_loaders, i, loader);
        return _loaders[i];
}

I pass to the child component like this

<loading-status v-if="loadstatus" :statuses="loadstatus.getAllLoaders()"></loading-status>

child component looks this this

<template>
    <div v-if="statuses">
        <div v-for="status in statuses" :key="status.name">
            <div>
                {{ status.loading == true ? 'true' : 'false' }}
            </div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'loading-status',
    props: {
        statuses: {
            type: Array,
            required: true
        }
    }
}

image of the array not being reactive on the page

some more information that may be useful:

the library structure:

function loadmanager(vueinstance) {
    //library internals here
    // for example my array i want to render:
    let _loaders = [];
    var publicInterface() {
        //public accesable functions here
        //i call this to pass the array to my child component
        getAllLoaders() {
            return _loaders;
        }
    }
    return publicInterface;
}
exports.makeLoadManager = loadmanager;

i import the library in the vue SFC and call it in the mounted hook

import loadhelper from "../../helpers/Loadstatus.js";
...
data() {
    return {
        loadstatus: null
    }
}
...
mounted() {
    this.loadstatus = loadhelper.makeLoadManager(this);
}

My question boils down to: How do I reactively render or correctly update an array from a js library in vue.

I would be happy to provide more information if that helps answering my question.

1
What about transform your external lib into a vuex module?Vanojx1
if possible i would like to keep it an external library so i can reuse it in other projects.lcberg
If your only requirement its the portability you can make a vuex pluginVanojx1
this seems interesting and if nothing else pops up i will try it out. thank you.lcberg

1 Answers

1
votes

If your library is creating (and managing) an array of "loaders", simplest thing you can do is define empty reactive array in your Vue component's data and in mounted hook assign a reference to your's library array into it. Like this:

import LoadingStatus from "./components/LoadingStatus";
import loadhelper from "./helpers/LoadManager.js";

export default {
  name: "App",
  components: {
    LoadingStatus
  },
  data() {
    return {
      statuses: []
    };
  }
  mounted() {
    this.statuses = loadhelper.getAllLoaders();
  }
};

Vue takes the array provided by your library and makes it reactive. You can use template like this:

<LoadingStatus :statuses="statuses"/>

See the demo

As long as both Vue and your "load manager" are working with the same array (reference), its all good. I'v added setTimeout callback into LoadManager to demonstrate that changes "from the outside of Vue" to the array will make Vue component re-render....