'How can I get the count of Object keys in a Vue template?

I'm trying to count the number of entries in an object and output that to the user. In a method this works fine using Object.keys(this.myObject).length but when outputting that in the template it is always 0.

Example:

<template>
    <div>
        Selected: {{ selectedCount }}<br> <!-- Always 0 -->
        Selected: {{ Object.keys(selected).length }}<br> <!-- Always 0 -->

        <div class="referral-redemptions-table">
            <b-table 
                ref="table"
                :items="referrals">
                <template v-slot:cell(isReferralRedeemed)="data">
                    <button type="button" class="btn btn-sm btn-primary" @click="markSelected(data.index)" :class="{ 'btn-ghost' : data.item.isSelected }">
                        {{ data.item.isSelected ? 'Selected' : 'Redeem' }}
                    </button>
                </template>
            </b-table>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                referrals: [
                    {
                        id: 1,
                        isSelected: false,
                        name: 'Test',
                        email: '[email protected]'
                    },
                    {
                        id: 2,
                        isSelected: false,
                        name: 'Test',
                        email: '[email protected]'
                    },
                    {
                        id: 3,
                        isSelected: false,
                        name: 'Test',
                        email: '[email protected]'
                    },
                    {
                        id: 4,
                        isSelected: false,
                        name: 'Test',
                        email: '[email protected]'
                    },
                ],
                fields: [
                    {
                        key: 'name',
                        label: 'Who',
                        sortable: true
                    },
                    {
                        key: 'email',
                        label: 'Email',
                        sortable: true
                    },
                ],
                selected: {},
            }
        },

        computed: {
            // a computed getter
            selectedCount: function () {
                return Object.keys(this.selected).length;
            }
        },

        methods: {
            // Mark an item as selected
            markSelected: function(index) {
                // Not selected, add it
                if(!this.referrals[index].isSelected) {
                    this.selected[index] = {
                        'id' : this.referrals[index].id, 
                        'email' : this.referrals[index].email
                    };
                } else {
                    delete this.selected[index];
                }

                console.log(Object.keys(this.selected).length); // Outputs the correct number

                this.referrals[index].isSelected = !this.referrals[index].isSelected;
                this.$refs.table.refresh();
            },
        }
    }
</script>

Update

To add to the confusion, if I set a data attribute of numSelected: 0 and then set this in the markSelected method using the Object.keys approach then everything works, even Object.keys(selected).length is available in the template, not just the variable I'm setting.

<!-- In template... -->
Selected: {{ numSelected }}<br> <!-- This now shows correctly... -->
Selected: {{ Object.keys(selected).length }} <!-- But so does this. Why would this not work before? -->

markSelected: function(index) {
    // [...]

    this.numSelected = Object.keys(this.selected).length;

    // [...]
},


Solution 1:[1]

I can't find the Vue 3 version of this but I believe you're running into change detection caveats (Vue doesn't know you're adding a new key to the object, so it does not re-render)

See https://v2.vuejs.org/v2/guide/reactivity.html#For-Objects

EDIT Can you clarify if you're on Vue 2 or 3? This answer says this problem shouldn't affect you in Vue 3

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1