0
votes

I am working on the payroll part of a time sheet application. When a time sheet is submitted it has a number of worked shifts, and each of these is represented in Vue as an instance of the Shift component.

The Shift component has a 'paid start time', and a 'paid finish time'. It should also show the 'worked hours'.

When the app is first loaded, the worked hours show correctly. However, when the start or finish times are updated, the worked hours are not recalculated.

Here's the relevant part of the template from the Shift component:

<td><input type="text" v-model="paidStartHours"> : <input type="text" v-model="paidStartMinutes"></td>
<td><input type="text" v-model="paidFinishHours"> : <input type="text" v-model="paidFinishMinutes"></td>
<td>{{ workedHours }}</td>

As you can see, the times are broken in to separate values for 'hours' and 'minutes'. These are bound with v-model to computed properties, as follows.

computed : {
    paidStartHours : {
        get() {
            return this.paidStart ? this.paidStart.format('HH') : '';
        },
        set(value) {
            this.paidStart = this.paidStart.hour(value);
        }
    },
    paidStartMinutes : {
        get() {
            return this.paidStart ? this.paidStart.format('mm') : '';
        },
        set(value) {
            this.paidStart = this.paidStart.minutes(value);
        }
    },
    paidFinishHours : {
        get() {
            return this.paidFinish ? this.paidFinish.format('HH') : '';
        },
        set(value) {
            this.paidFinish = this.paidFinish.hour(value);
        }
    },
    paidFinishMinutes : {
        get() {
            return this.paidFinish ? this.paidFinish.format('mm') : '';
        },
        set(value) {
            this.paidFinish = this.paidFinish.minutes(value);
        }
    },
    workedHours () {
        return this.paidFinish ? this.paidFinish.diff(this.paidStart, 'hours', true) : '';
    }
}

As you can see, the computed setters update the real model properties, paidStart and paidFinish. In the code above you can also see that workedHours is a getter based on these two values.

So, when I update the start or finish hours (or minutes), why does worked hours not update? I thought it might be related to the async update queue, https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue, but if I was going to use nextTick(), how would I do that? What function would it call?

1

1 Answers

1
votes

The problem is with watching moment for changes. I cannot really tell you why exactly this happens, but basically VueJS does not pick up changes you make to the original moment object. You may have already thought about that because you try to assign the object anew in the setters. Sadly the documentation (https://momentjs.com/docs/#/get-set/) states that:

Note: All of these methods mutate the original moment when used as setters.

This means you need to construct a new moment object with the value added to the original moment object. There might be a better solution where VueJS does pick up changes made to the moment object, but i sadly cannot provide that.