Custom Functor for Data Grouping

A functor is a method that is applied to an item property in order to define the way it is presented in a group header.

[
    { id:1, title:"The Shawshank Redemption", year:1994, votes:678790},
    { id:2, title:"The Godfather", year:1972, votes:511495},
    { id:3, title:"The Godfather: Part II", year:1994, votes:319352},
    { id:4, title:"The Good, the Bad and the Ugly", year:1972, votes:213030}
]

When data are grouped by year, we may want to learn the total number of votes per year, or their maximum/minimal value, etc. There are grouping functors designed for this purpose. They are used within the map object of the grouping function.

$group:{
    by:"year",
    map:{
        votes:['votes', 'sum']  
    }   //'sum' is a functor to calculate votes total for each year
}

Related sample:  Data Aggregation

The simplest operations are supplied by prebuilt grouping functors stored in the GroupMethods class.

However, you can a create custom functor to meet your needs.

Adding a New Functor

Any function can become a grouping functor provided that you've given it a unique name, described the logic and added to the GroupMethods class.

Such a function takes two arguments:

  • prop - the property to process;
  • data - a data object with items of this group.

There's no functor to find out the average value for item properties, so let's call it median and add it.

webix.GroupMethods.median = function(prop, data){
    if (!data.length) return 0;
        var summ = 0;
    for (var i = data.length - 1; i >= 0; i--) {
        summ += prop(data[i])*1;
    };
    return summ/data.length;
};

And apply the newly created functor referring to it by its name:

$group:{
    by:"year",
    map:{
        votes:["votes", "median"]   
    }   
}

Related sample:  Custom Aggregation while Grouping

The functor can be as well defined bypassing the GroupMethods class by setting a custom function.

function getAverage(prop, data){
    // the same as for "median" above 
} 
 
$$("mychart").group({
    by:"year",
    map:{
        sales:["sales", getAverage]
    }
});

Related sample:  Grouping

By the way, you can omit the functor yet set the way grouping criterion will be presented:

webix.ui({
    view:"treetable",
    columns:[ //default template for ungrouped items
        { id:"title", template:"{common.icon()} #title#" }, 
    ],
    scheme:{
        $group:{
            by:function(obj){ return Math.floor(obj.year/10); }, 
            map:{
                title:[function(obj){ 
                    var min = obj.year - obj.year%10; 
                    return min + " - "+ (min+10) 
                }]
            }
        }
    }       
});

Related sample:  Static Grouping

Back to top