Display sections only if it has events in Timeline View : Filtering the Sections

Hello,

In the timeline view, I wish to display only those sections which have events in them. I have written the following code for filtering the sections (saw this code in previous answers on the forum) if it has events or not.

scheduler.attachEvent("OnViewChange", function (new_mode, new_date) { filterSection(); })

        function filterSection(){
        var display = scheduler.serverList("sections").slice();
        for(var i = 0;i<display.length;i++){
            if(!allowSection(display[i])){
                display.splice(i,1)
                i--;
            }
        }
        scheduler.updateCollection("sections", display)
    }
function allowSection(section){
        var start = scheduler.getState().min_date;

        var end = scheduler.getState().max_date;
        var events = scheduler.getEvents(start,end)

        if(section.label == events.label){
            return true
        }
        return false
    }

When I run this, the page takes a very long time to load and when I tried to debug it, I notice that in the attachEvent("OnViewChange") function filterSection() is being called constantly, even after the updateCollection() method is called and the function ends properly.

Can you please look at it and see what mistake I am making here and how to fix this? If not this way, is there a simpler alternative way to do this?

** I get this error on the console of the browser**
Uncaught RangeError: Maximum call stack size exceeded

Hi,

Please note that scheduler.updateCollection internally calls scheduler.setCurrentView, which in its turn fires onViewChange event that you capture - this is a reason for endless calls and stack overflow.

As a solution, you can either set up some flag variable which you’ll use to skip some occurrences of onViewChange event:

var ignoreNext = false;// CHANGED SECTION
scheduler.attachEvent("OnViewChange", function (new_mode, new_date) { 
    if(ignoreNext) return true;// CHANGED SECTION
    filterSection(); 
});


function filterSection(){
    var display = scheduler.serverList("sections").slice();
    for(var i = 0;i<display.length;i++){
        if(!allowSection(display[i])){
            display.splice(i,1)
            i--;
        }
    }

    ignoreNext = true; // CHANGED SECTION // skip next onViewChange
    scheduler.updateCollection("sections", display);
    ignoreNext = false; // CHANGED SECTION
}

function allowSection(section){
    var start = scheduler.getState().min_date;

    var end = scheduler.getState().max_date;
    var events = scheduler.getEvents(start,end)

    if(section.label == events.label){
        return true
    }
    return false
}

Alternatively, you can use onBeforeViewChange. Unlike onViewChange, it provides you both the current state and the new state, so you can tell whether it’s a refresh on the same date/view, or if the user switches to a new view or date:

scheduler.attachEvent("onBeforeViewChange", function (old_mode, old_date, mode, date) {
  var toStr = scheduler.date.date_to_str("%d-%m-%Y");
  var start = scheduler.date[mode + "_start"](new Date(date));
  var end = scheduler.date.add(start, 1, mode);

  //recalculate only when the visible date is about to change
  if (!old_date || old_date.valueOf() != date.valueOf()) {
    filterSections(mode, date);
  }
  return true;
});

Note, that in this case, date values returned from scheduler.getState() will reflect the old state, not the dates that are about to be displayed, so changes in allowSection function will be required.

Here is a working demo:
https://snippet.dhtmlx.com/94232bdbf

https://docs.dhtmlx.com/scheduler/api__scheduler_onbeforeviewchange_event.html