Single scrolled parent with multiple containers in Sencha

Swarnendu De February 20, 2014

App developers often need to create a view with multiple dataviews, lists and/or containers. In Sencha, we have seen a common problem of multiple scrollbar when a page has many containers. The whole view looks pretty mixed while scrolling any of the containers. Developers often look for a realistic solution to this problem; I have come across many forum discussions on this topic but hardly found a real solution.

Finally, I have come up with my own way of solving it. I am describing this problem and giving solution with dataview. Here you go.

In demo, when we scroll the “Dataview without parent page scrolling” part, there is a smooth scroll in child container. But when we scroll the “Dataview with parent page scrolling” part, the parent panel scroll with child’s scroll which makes the view pretty clumsy.

[button link=”https://www.innofied.com/iphonetest/?url=https://www.innofied.com/sencha/anand/customdataview” linking=”new-window” size=”medium” type=”simple” title=”iPhone like infobubble with Sencha Touch”]Demo[/button] [button link=”https://github.com/anandasansol/customdataview” linking=”new-window” size=”medium” type=”simple” title=”Download” label=”Download”]Download[/button]

Now, without wasting time, let’s create a Sencha Touch application. The application will contain the following files in MVC style:

 

Controller

  1. App.js

Views

  1. Main.js

  2. ux.CustomDataView.js

In CustomDataView.js we have extended the Sencha’s Ext.dataview.DataView class and have added a config property ‘parentPanel’ to the defined CustomDataView class.

ux.CustomDataView.js

/**
* @class CustomDataview.view.ux.CustomDataView
* @extends Ext.dataview.DataView
* This class creates the custom dataviews, and lets them scroll without
* scrolling the parent container.
*/
Ext.define('CustomDataview.view.ux.CustomDataView', {
    extend: 'Ext.dataview.DataView',
    xtype: 'customdataview',
    parentPanel: null, // Adding parentPanel to config of 'customdataview'
    initialize: function() {
        this.callParent(arguments);
    },

    config: {
        listeners: {
            painted: function() {
                var me = this,
                    parentPanel = me.parentPanel || me.config.parentPanel;
                me.getScrollable().getScroller().on('scrollstart', function() {
                    parentPanel.setScrollable(false);
                }, me);

                me.getScrollable().getScroller().on('scrollend', function() {
                    parentPanel.setScrollable(true);
                }, me);
            }
        }
    }
});

In the above file, we can see, on scrollstart of the child container (dataview inside the parent container), we set the setScrollable() method of ‘parentPanel’ false. Hence, on scroll of child container, parent container’s scroll is revoked/locked.

When user releases the scroll of the child container, scrollend is fired and we set the setScrollable() method of ‘parentPanel’ to true.

As a result, when we start scrolling the child container, the parent wouldn’t scroll, resulting in a single smooth scroll.

Main.js

Ext.define('CustomDataview.view.Main', {
    extend: 'Ext.Container',
    xtype: 'main',
    requires: [
    'Ext.data.Store'
    ],
    config: {
        scrollable: true,
        name: 'main_container',
        items: [{
            xtype: 'toolbar',
            title: 'Dataview without parent page scrolling',
            docked: 'top'
        }, {
            xtype: 'customdataview',
            name: 'custom_dataview',
            itemTpl: '{text}',
            height: 200,
            data: (function(){
                var count, data = [];
                for(count = 1; count <=25; count++) {
                    data.push({text: "Custom Dataview"});
                }
                return data;
            })()

        }, {
            xtype: 'toolbar',
            title: 'Dataview with parent page scrolling',
            height: 25
        }, {
            xtype: 'dataview',
            itemTpl: '{text}',
            height: 200,
            data: (function(){
                var count, data = [];
                for(count = 1; count <=25; count++) {
                    data.push({text: "Sencha Dataview"});
                }
                return data;
            })()
        }]
    }
});

In Main.js, we have defined a container which mainly contains two dataview. Second dataview is showing the issue which developers often face and first one is our solution for this issue.

App.js

Ext.define("CustomDataview.controller.App", {
    extend: "Ext.app.Controller",
    config: {
        refs: {
            // Container
            mainContainer: 'container[name="main_container"]',
            customDataview: 'dataview[name="custom_dataview"]'
        },
        control: {
            mainContainer: {
                initialize: function() {
                    // Assigning the 'parentPanel' config of 'customdataview' with parent panel
                    this.getCustomDataview().config.parentPanel = this.getMainContainer(); 
                }
            }
        }
    }
});

Here, we are taking the reference of ‘mainContainer’ as parent panel and ‘customDataview’ as child panel and then setting the ‘parentPanel’ config option of child panel with the reference of parent panel (‘mainContainer’). That is it.

If the blog was useful, let me know with your comments. Any query or suggestion is welcome here. Here we have links of demo as well as github source code.

[button link=”https://www.innofied.com/iphonetest/?url=https://www.innofied.com/sencha/anand/customdataview” linking=”new-window” size=”medium” type=”simple” title=”iPhone like infobubble with Sencha Touch”]Demo[/button] [button link=”https://github.com/anandasansol/customdataview” linking=”new-window” size=”medium” type=”simple” title=”Download” label=”Download”]Download[/button]