Our pure JavaScript Scheduler component


Post by probo »

Hello there,

I'm trying to setup websockets for my scheduler pro. I'm using the following stack:

Backend
Laravel Framework

Socket server
Laravel Reverb

Frontend
Vue 3
Laravel Echo (for receiving updates from the socket server)

So here is my setup

  project: {
    eventStore: {
      createUrl: '/print-planning/events/create',
      readUrl: '/print-planning/events/read',
      updateUrl: '/print-planning/events/update',
      deleteUrl: '/print-planning/events/delete',
      autoCommit: true,
      autoLoad: true,
      singleAssignment: true
    }
  }

This is my listener for sending data to the clients. This is event is triggered when an event is succesfully added to the database using the backend.

        window.Echo.channel('PrintPlanningEvents').listen('.addEvent', (e) => {
            if (this.supports(e, user)) {
                scheduler.eventStore.add({
                    type: e.type,
                    startDate: e.startDate,
                    resourceId: e.resourceId,
                    duration: e.duration,
                    name: e.name,
                    _source: 'websocket'
                });
            }
        });
  

Now what i'm trying to accomplish here is that it adds the event to the clients. Of course that doesn't work in this configuration, because autoCommit is set to true, which results in an endless loop... Is there some way to fix this?? To for example, supress the autoCommit behaviour.

A note should be added here, that i can set autCommit to false, then i would have to do the commits manually, i tried this by adding a addconfirmed listener, and comitting in the listener. But when i do this and i want to create a new record on the side where the event was just added, 2 events will be created on the other clients and i want to add the one i just created.

So my actual question is, what would be a good approach to create events (which are already in the databse because some client created it) and add them to the schedulers of clients which don't have them yet.

Kind regards,
Probo


Post by Maxim Gorkovsky »

Hello.
As far as I can see the only way to achieve this is to set autoCommit to false when you add record to the store to avoid triggering the logic:

store.autoCommit = false;
store.add({...});
// after add store will contain changes
// one way to fix it is to call acceptChanges
store.acceptChanges();
// however it may lead to lost changes if store is in the process of autoCommit already
store.autoCommit = true;

Make sure there are no awaits between disabling and enabling autoCommit to not skip any records added by the user. Another good idea could be to wait for all autoCommits to finish before adding remotely created record.

In Scheduler Pro there is API to apply changes: https://bryntum.com/products/gantt/docs/api/SchedulerPro/model/mixin/ProjectChangeHandlerMixin#function-applyProjectChanges which would take care about some of these issues.


Post by probo »

So i currently have this

        window.Echo.channel('PrintPlanningEvents').listen('.addEvent', (e) => {
            console.log('Broadcasting add event...');
            if (this.supports(e, user)) {
                console.log('I am the client');
                scheduler.eventStore.autoCommit = false;
                scheduler.eventStore.add({
                    type: e.type,
                    startDate: e.startDate,
                    resourceId: e.resourceId,
                    duration: e.duration,
                    name: e.name,
                    _source: 'websocket'
                });
                console.log(scheduler.eventStore.changes);
                scheduler.eventStore.acceptChanges();
                console.log(scheduler.eventStore.changes);
                scheduler.eventStore.autoCommit = true;
            }
        });

Before acceptchanges there is 1 record, after acceptChanges there are 0 records. But when i set autoCommit to true, it's resulting in an infinite loop. The result is that it creates the events on all clients for an infinite amount of times.


Post by probo »

I seem to have fixed it, i'm stil using autoCommit: true.

For my listener i am using

        window.Echo.channel('PrintPlanningEvents').listen('.addEvent', (e) => {
            if (this.supports(e, user)) {
                scheduler.eventStore.isSocketClient = true;
                scheduler.eventStore.add({
                    id: e.id,
                    type: e.type,
                    startDate: e.startDate,
                    resourceId: e.resourceId,
                    duration: e.duration,
                    name: e.name
                });
            }
        });

and my eventStore config looks like this now.

        eventStore: {
            createUrl: '/print-planning/events/create',
            readUrl: '/print-planning/events/read',
            updateUrl: '/print-planning/events/update',
            deleteUrl: '/print-planning/events/delete',
            params: {
                production_unit_group: getSelectedFilterValue('production_unit_group'),
                date: getSelectedFilterValue('date')
            },
            autoCommit: true,
            autoLoad: true,
            singleAssignment: true,
            modelClass: Event,
            listeners: {
                beforeCommit() {
                    if (this.isSocketClient) {
                        this.acceptChanges();
                        this.isSocketClient = false;

                    return false;
                }

                return true;
            },
        }
    },

I don't know if i am missing something that might not work, but it seems to be working fine.


Post by Maxim Gorkovsky »

I would say you probably miss setting isSocketClient back to false. But it is hard to tell without a runnable demo, I don't really know full architecture of your application


Post Reply