ReactJS: BSD + Patents licensing model

The devil is in details, so people say. Few months ago, while working on prototype of cakephp-calendar, we had an interesting debate over front-end stack for Calendar component. At the same time, in parallel, WordPress community was buzzing about their text editor – Gutenberg whether to use ReactJS vs VueJS libraries. One of the reasons of choosing VueJS, was licensing agreement.

The license granted hereunder will terminate, automatically and without notice,
if you (or any of your subsidiaries, corporate affiliates or agents) initiate directly or indirectly, or take a direct financial interest in, any Patent Assertion…(c)

Investing man-hours into VueJS research and prototyping was right, especially after Raul Kripalani published an interesting article on the license review of ReactJS.

Updated: One more review of FB React JS licensing from WordPress Tavern.

VueJS watchers for MomentJS

It took me some time to figure out what’s been going wrong with the watchers working on datepicker integration for CakePHP-Calendar plugin.

Problem domain:

On loading modal window for creating calendar event, one of the dropdowns pass default start/end time for the event interval (start/end dates). This config object is passed to as a property into interval component that contains two child datepicker components.

Whenever the config property changes, it adjusts startMoment and endMoment objects and passes them into datepickers. The change is monitored via watch functionality of VueJS.

Example:

Vue.component('interval-holder', {
    template: `<div>
        <datepicker :date-moment="startMoment"></datepicker>
        <datepicker :date-moment="endMoment"></datepicker>
    </div>`,
    props: ['config', 'initialMoment'],
    data: function() {
        return {
            startMoment: null,
            endMoment: null
        };
    },
    watch: {
        config: function() {
            this.startMoment = this.initialMoment;
            this.startMoment.set({'hour': this.config.start.hour, 'minute': this.config.start.min});
            
            this.endMoment = this.initialMoment; 
            this.endMoment.set({'hour': this.config.end.hour, 'minute': this.config.end.min});
        }
    }
});

Vue.component('datepicker', {
    // value var is useless here, as we use daterangepicker from jQuery 🙁
    template: `<div>
        <input type="text" :value="value"/>
    </div>`,
    props: ['dateMoment'],
    mounted: function() {
        var self = this;
        //load jquery bootstrap-datepicker instance
        this.instance = $(this.$el).find('input').daterangepicker().data('daterangepicker');
        
        $(this.$el).find('input').on('apply.daterangepicker', function(ev, picker) {
            self.momentObject = picker.startDate;
            self.value = picker.startDate.format('YYYY-MM-DD HH:mm');
        });
    },
    data: function() {
        return {
            instance:null,
            value: null,
            momentObject: null,
        };
    },
    watch: {
        dateMoment: function() {
            this.momentObject = this.dateMoment;
            this.value = this.momentObject.format('YYYY-MM-DD HH:mm');
        },
    }
});

If we set hours and minutes the following way as in the example above, dateMoment watcher won’t catch the change. According to the docs, it’s adviced to use deep param:

To also detect nested value changes inside Objects, you need to pass in deep: true in the options argument. Note that you don’t need to do so to listen for Array mutations.

watch: {
    dateMoment: {
        handler: function(val, old) {
            console.log('dateMoment changed');
        },
        deep: true
    }
}

Still no luck. Apparently, MomentJS object “too deep”. The only way to get it working ended up like this, change the parent component moment objects assignment, keeping the child-component watch function unchanged.

watch: {
    config: function() {
        var newStart = moment(this.startMoment);
        newStart.set({'hour': .., 'minute': ..});
        this.startMoment = newStart;
        
        //create a new instance of newEnd and assigning it to this.endMoment
        // get the dateMoment observe the change.
        // Ugly? Yes. Working? Yes..
    }
}

If anyone has a better (more elegant) way to fix this issue – welcome in the comments section! 🙂