[Vuejs]-Vue.js computed on nested arrays

0👍

You are asking for global state management, so you need to use Vuex.

https://vuex.vuejs.org/en/intro.html

Once you have Vuex installed, you’ll create a store (which represents the current state of your application) then you’ll create an action that sends an asynchronous API request (the ajax request) and updates the store accordingly. Every component that depends on the data received in this API call will react to this update. You can optionally have a Vuex getter, which behaves exactly as a regular component getter but is available across all your components.


The idea is that the dates of each activity are editable.

There is no secret about editing nested properties. You just need to update the whole object in order to keep the reactivity.

Here is a complete example:

const store = new Vuex.Store({
  state: {
    phases: [
      {
        phaseId: 1,
        activities: [
          { activityId: 1, start: 1, end: 6 },
          { activityId: 2, start: 5, end: 9 },
        ],
      },
      {
        phaseId: 2,
        activities: [
          { activityId: 3, start: 10, end: 16 },
          { activityId: 4, start: 14, end: 19 },
        ],
      },
    ],
  },
  mutations: {
    setDuration (state, {phaseId, activityId, start, end}) {
      const phase = state.phases.find(x => x.phaseId === phaseId);
      state.phases = [
        ...state.phases.filter(x => x !== phase),
        {
          ...phase,
          activities: [
            ...phase.activities.filter(x => x.activityId !== activityId),
            { activityId, start, end }
          ],
        },
      ];
    },
  },
});

const example = {
  data() {
    return {
      phaseId: null,
      activityId: null,
      start: null,
      end: null
    };
  },
  computed: {
    ...Vuex.mapState(['phases']),
    phasesFormated() {
      return JSON.stringify([...this.phases].sort((a, b) => a.phaseId - b.phaseId), null, 2);
    },
  },
  methods: {
    ...Vuex.mapMutations(['setDuration']),
    updatePhase() {
      this.setDuration({
        phaseId: parseInt(this.phaseId),
        activityId: parseInt(this.activityId),
        start: parseInt(this.start),
        end: parseInt(this.end),
      });
    },
  },
  template: `
    <div>
      <div>
        Phase ID:
        <input type="text" v-model="phaseId">
        <br />
        Activity ID:
        <input type="text" v-model="activityId">
        <br />
        Start:
        <input type="text" v-model="start">
        <br />
        End:
        <input type="text" v-model="end">
      </div>
      <button type="button" v-on:click="updatePhase">update</button>
      <pre style="margin-right: 1rem">{{ phasesFormated }}</pre>    
    </div>
  `,
};

const app = new Vue({
  store,
  el: '#app',
  components: { example },
  template: `
    <div v-cloak>
      <h1>app</h1>
      <example></example>
    </div>
  `
});

Reconstructing the whole object may get a bit messy, tho. That’s why people that use state management libraries (Vuex, Redux etc) often normalize the data.

The docs of Redux library have a nice example of what data normalization is, and the creator of Vue has an interesting post on the subject as well.

Leave a comment