0
votes

A jQuery datepicker is wrappped in a Vue component. The component emits an update message used to update the app model.

The app has two datepicker input fields:

  • startDate
  • adjustmentDate

When startDate is modified, adjustmentDate is to be updated to the next first or fifteenth of the month. However, the adjustmentDate datepicker component is not being notified of the update.

Expected behaviour:

  • startDate datepicker onSelect triggers the Vue component emit which is captured by Vue method updateStartDate

  • method updateStartDate sets model property adjustmentDate

It was hoped this would trigger the adjustmentDate component update since the adjustmentDate model attribute is bound to the datepicker componentDate property which has a watch.

But changing the model doesn't have the affect of notifying the component.

Any suggestions how to do this properly and show the newly calculated adjustmentDate when the startDate is changed?

Demo code:

<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">

    <link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

    <script src="https://unpkg.com/vue"></script>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

</head>


<body>

    <div id="app">

        <div><label>Start date</label></div>
        <div>
            <date-picker 
                v-model="startDate"
                v-bind:component-date="startDate"
                date-format="yy-mm-dd"
                @update-date="updateStartDate"
                v-once
            ></date-picker>
        </div>

        <div><label>Adjustment date</label></div>
        <div>
            <date-picker
                v-model="adjustmentDate"
                v-bind:component-date="adjustmentDate"
                date-format="yy-mm-dd"
                @update-date="updateAdjustmentDate"
                v-once
            ></date-picker>
        </div>

    </div>



    <script>

    Vue.component('date-picker', {

        props: ['dateFormat', 'componentDate'],

        template: '<input/>',


        mounted: function() {

        var self = this;

        var _convertDateStringToDate = function(dateString) {
                var dateParts = dateString.split("-");
                var year = dateParts[0];
                var month = dateParts[1];
                var dayOfMonth = dateParts[2];
                return new Date(year, month, dayOfMonth);
        };


        $(this.$el).datepicker({

                dateFormat: this.dateFormat,

                onSelect: function(date) {
                        self.$emit('update-date', _convertDateStringToDate(date));
                },

                onClose: function(date) {
                        self.$emit('update-date', _convertDateStringToDate(date));
                }

        });

        $(this.$el).datepicker('setDate', this.componentDate);

        },


        watch: {
            componentDate: function(newValue, oldValue) {
                $(this.$el).datepicker('setDate', this.componentDate);
            }
        },


        beforeDestroy: function() {
            $(this.$el).datepicker('hide').datepicker('destroy');
        }

    });



    var _calculateAdjustmentDate = function(date) {

        var year = date.getFullYear();
        var month = date.getMonth();
        var dayOfMonth = date.getDate();

        if (dayOfMonth > 15) {
            month = month + 1;
            dayOfMonth = 1;
        } else if (dayOfMonth > 1 && dayOfMonth < 15) {
            dayOfMonth = 15;
        }

        return new Date(year, month, dayOfMonth);

    };


    var data = function() {

        var now = new Date();

        return {
                startDate: now,
                adjustmentDate: _calculateAdjustmentDate(now),
        };

    };


    new Vue({

        el: '#app',

        data: data,

        methods: {

                updateStartDate: function(date) {
                        this.startDate = date;
                        this.adjustmentDate = _calculateAdjustmentDate(date);
                },

                updateAdjustmentDate: function(date) {
                        this.adjustmentDate = date;
                },

        }

    });


    </script>


</body>


</html>
1

1 Answers

1
votes

You need to remove the v-once directive from your adjustment date component as it prevents re-rendering when the data changes.

Additionally, you can simply put _calculateAdjustmentDate into a computed property, see Computed Properties.

See your updated example here: https://codepen.io/anon/pen/VQYarZ

There are some other issues with your code, I suggest you look into the Vue guide, especially at Method Event Handlers and Computed Properties as well as into Reactivity in Depth.

Also, _calculateAdjustmentDate does not really do what you describe, so you might look into this as well. You might consider Moment.js