Neve12ende12
Neve12ende12

Reputation: 1194

VueJS: Replace/Update Array

I currently have an array of object that I am rendering to a table. I am trying to follow the examples provided by Vuejs to use a "single source of truth" shared between multiple vues on the same page.

Overall, I am trying to make it where when vue1.refresh() is triggered, all the vues update their data when the "single source of truth" is updated. However, self.surveys = surveys; only updates the data on vue1.

Note: I am following the guide from https://v2.vuejs.org/v2/guide/state-management.html

// The single source of truth
var cache = {
    data: [{...}] // Array of objects
}

var vue1 = new Vue({
    el: "#table",
    data: {
        surveys: cache.data // Points to the single source of truth
    },        
    methods: {
        refresh: function(){
            var self = this;                 

            // After getting data back from an ajax call
            .done(function(surveys) {
                self.surveys = surveys;
            });
        },
    }
});

var vue2 = new Vue({
    el: "#table",
    data: {
        surveys: cache.data // Points to the single source of truth
    },        
    methods: {
        // Methods
    }
});

Upvotes: 3

Views: 9903

Answers (4)

Filipe Costa
Filipe Costa

Reputation: 555

As said in the comment before, you can use vuex to accomplish what you need, everytime you need to pass data between diferent components you can do that with a eventBus or passing props up and down between the components.

When you have a aplication that needs to pass a lot of data and receive it you can use vuex, first you need to install it and then you can do it this way:

you should cut the methods out and place the mounted(), it fires when the component loads, i think it was you need

var vue1 = new Vue({
    el: "#table",
    data: {
        surveys: cache.data // Points to the single source of truth
    },        
    methods: {

    }.
    mounted() {
      var self = this;                 

      // After getting data back from an ajax call
      .done(function(surveys) {
      self.surveys = surveys;
      });
    }
});

when you get the response pass it to vuex store, you can do it with a mutation like this:

this.$store.mutation('handlerFunction', self.surveys)

in the vuex you need to have the handlerfunction inside the mutation

  mutations: {
    // appends a section to the tree
    handlerFunction: (state, dataReceived) => {
      //then you can do
      state.surveys = dataReceived
    },

then in your other component you can receive it via a getter, the logic is the same watch vuex for more deaills, you have the main logic of connection here.

Hope it helps!

Upvotes: 0

Roy J
Roy J

Reputation: 43899

There are two principles of Vue that will help you here:

  1. In Vue, every data item is a source of truth.
  2. Only the owner of a data item should modify it.

In your example, you have three sources of truth: the one you want to be the single source, and two others that are initialized from it. Also, the one you want to be the source of truth isn't a data item, it is outside Vue.

So to start, you should have a single Vue that represents your entire application and defines any data that represents application-level state:

new Vue({
  el: '#app',
  data: {
    cache: {
      data: [...]
    }
  }
});

The two Vue objects that you created should be children of the application Vue, which is to say, components.

The parent tells the children what the truth is via props. The child can suggest changes to the truth by emitting events to the parent, but the child does not directly modify the truth. That keeps all management of the truth in one place.

Upvotes: 2

user6748331
user6748331

Reputation:

Problem is, you are replacing shared Cache object previously assigned to surveys variable, with new, not shared object. And solution? Do not try to mutate cache object. Just use Vuex. Vuex is simple, real "Vue way" solution.

// The single source of truth
var cache = {
    data: [{...}] // Array of objects
}

var vue1 = new Vue({
    el: "#table",
    data: {
        surveys: cache.data // Points to the single source of truth
    },        
    methods: {
        refresh: function(){
            var self = this;                 

            // After getting data back from an ajax call
            .done(function(surveys) {
                self.surveys = surveys; // Problem is right here

            });
        },
    }
});

var vue2 = new Vue({
    el: "#table",
    data: {
        surveys: cache.data // Points to the single source of truth
    },        
    methods: {
        // Methods
    }
});

Try this example, which works like you code - not correct way:

var cache = {
  key1: 'Value1'
}

var vue1 = new Vue({
  el: '#app1',
  data: {
    surveys: cache
  },
  methods: {
    replace () {
      this.surveys = {key1: 'Replaced'}
    }
  }
})

var vue2 = new Vue({
  el: '#app2',
  data: {
    surveys: cache
  },
  methods: {
    replace () {
      this.surveys = {key1: 'Replaced'}
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app1">
  Input for Vue1: <input type="text" v-model="surveys.key1">
  <button @click="replace">Replace</button>
  <p>{{ surveys.key1 }}</p>
</div>

<div id="app2">
  Input for Vue1: <input type="text" v-model="surveys.key1">
  <button @click="replace">Replace</button>
  <p>{{ surveys.key1 }}</p>
</div>

Then try this example, with Vuex, where you can freely replace "cache object" and replacint will affect other instance:

const store = new Vuex.Store({
  state: {
    cache: {
      key1: 'Value1'
    }
  },
  mutations: {
    replace (state) {
      state.cache = {key1: 'Replaced'}
    }
  }
})

var vue1 = new Vue({
  el: '#app1',
  store,
  computed: {
    surveys () {
      return this.$store.state.cache
    }
  },
  methods: Vuex.mapMutations([
    'replace'
  ])
})

var vue2 = new Vue({
  el: '#app2',
  store,
  computed: {
    surveys () {
      return this.$store.state.cache
    }
  },
  methods: Vuex.mapMutations([
    'replace'
  ])
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuex.min.js"></script>

<div id="app1">
  Input for Vue1: <input type="text" v-model="surveys.key1">
  <button @click="replace">Replace</button>
  <p>{{ surveys.key1 }}</p>
</div>

<div id="app2">
  Input for Vue1: <input type="text" v-model="surveys.key1">
  <button @click="replace">Replace</button>
  <p>{{ surveys.key1 }}</p>
</div>

Upvotes: 0

Sam R
Sam R

Reputation: 702

You would need to mutate the array, not replace it.

Array.prototype.splice can do this for you, if you don't want to use something like Vuex, as suggested by Vanojx1.

Splice expects specific elements, not a complete array for insertions. Because you have an array you want to use and you need to clear the old one, the syntax is a little odd... You pass this, the start, the count to remove (the entire length), and then the elements to add (concatenated on from your new array).

Array.prototype.splice.apply([self.surveys, 0, self.surveys.length].concat(surveys));

Upvotes: 1

Related Questions