3

I have a page where an object with nested array values are passed in from the parent component. The user can then, using a series of events and components manage the data in these subscriptions. Currently I'm facing an issue where when a subscriptionId is removed from the props, conditions on the page aren't changing, but they do when it's added.

Child Component

export default {
    props: {
        // Format of this object is:
        // { "gameId": [
        //     'subscriptionId',
        //     'subscriptionId',
        // ] }
        subscriptions: {
            type: Object,
            required: true
        }
    },
    watch: {
        subscriptions: {
            handler: function (newSubscriptions, oldSubscriptions) {
                // NEVER gets fired when `subscriptionId` deleted from array list, but is fired when a new subscription is added
                console.log('handler');
                }
            },
            deep: true
        }
    },

I suspect this might be related to how I'm removing the array from the object. Essentially I'm copying the array, deleting the index in question and overwriting the original array. My hope with this approach is that the watcher wouldn't be needed but it appears to have no impact. Here's the code that exists on the parent component to update the subscriptions:

Parent Component

// Works great, don't have any issues here
handleSubscribed (subscriptionId) {
    let newSubscriptions = [subscriptionId];

    if (this.subscriptions.hasOwnProperty(this.currentGame.id)) {
        newSubscriptions = this.subscriptions[this.currentGame.id];
        newSubscriptions.push(subscriptionId);
    }

    this.$set(this.subscriptions, this.currentGame.id, newSubscriptions);
},
handleUnsubscribed (subscriptionId) {
    // if there's more than one, delete only the one we're looking for
    if (this.subscriptions.hasOwnProperty(this.currentGame.id) && this.subscriptions[this.currentGame.id].length > 1) {
        let newSubscriptions = this.subscriptions[this.currentGame.id];

        delete newSubscriptions[newChannels.indexOf(subscriptionId)];

        this.$set(this.subscriptions, this.currentGame.id, newSubscriptions);

        // shows my subscription has been removed, but GUI doesn't reflect the change
        console.log('remove-game', newSubscriptions); 
        return;
    }

    this.$delete(this.subscriptions, this.currentGame.id);
},

I was hoping watch might be the solution, but it's not. I've looked over the reactive docs several times and don't see a reason for why this wouldn't work.

VueJS version: 2.5.7

Ben
  • 60,438
  • 111
  • 314
  • 488
  • can you make any fiddle of this ? – Niklesh Raut Jul 02 '18 at 03:10
  • 1
    Have you tried using [Vue.delete](https://vuejs.org/v2/api/#Vue-delete) inside the if block instead of `delete`? – Brian Lee Jul 02 '18 at 06:09
  • or [splice](https://stackoverflow.com/questions/43046332/how-to-remove-an-item-from-an-array-in-vue-js) – Jacob Goh Jul 02 '18 at 09:16
  • @DigitalDrifter I'm shocked, but that seems to have solved it. This is some extensive stuff it seems to make it work that deep under the covers... – Ben Jul 02 '18 at 21:46
  • Cool, glad that did the trick. I assume the cause is that using the js `delete` keyword destroys the observable and hence the object is no longer reactive as expected. Vue's `set` and `delete` methods ensure they remain so. – Brian Lee Jul 02 '18 at 22:22
  • This is weird though, `Vue.delete` appears to be some kind of global handler, meaning you don't want to do it twice. Can you post that as the answer so I can give you credit? – Ben Jul 02 '18 at 22:37

1 Answers1

0

Use Vue.delete instead of the delete keyword.

The object is no longer observable when using delete, therefore not reactive.

Delete a property on an object. If the object is reactive, ensure the deletion triggers view updates. This is primarily used to get around the limitation that Vue cannot detect property deletions, but you should rarely need to use it.

tony19
  • 125,647
  • 18
  • 229
  • 307
Brian Lee
  • 17,904
  • 3
  • 41
  • 52