0
votes

I have a list I am using with a toolbar docked to the top. This list also contains an indexBar. The toolbar appears to be pushing the list down. Therefore the indexBar is not vertically aligned properly, and when I scroll down the list and get to the last item, it does not show properly. Does anyone know how to lay this out properly so the toolbar doesn't push the list down? Here's my code:

app.customerList = Ext.define('CustomerList', {
    constructor: function() {        
        this.listComponent = Ext.create('Ext.List', {
            itemTpl: '<div class="contact">{first_name} <strong>{last_name}</strong></div>',
            store: customerListStore,
            id: 'customer_list',
            grouped: true,
            indexBar: true,
            listeners: {
                itemtap: {
                    fn: function (list, index, item, evt) {

                    },
                    element: 'element'
                }
            }
        });

        this.listWrapper = Ext.create('Ext.Panel', {
            fullscreen: true,
            layout: 'fit',
            items: [
                {
                    xtype: 'toolbar',
                    docked: 'top',
                    title: 'Customers',
                    items: [
                        {
                            xtype: 'button',
                            text: 'Home',
                            ui: 'back',
                            listeners: {
                                tap: {
                                    fn: function() {

                                    },
                                    element: 'element'
                                }
                            }                            
                        }
                    ]
                },
                this.listComponent
            ]
        });

    }
});

As you can see I am getting my data from a store. I was able to fix this on an iPhone by giving the list a css rule of bottom: 38px, but I know this is a hack so I would rather not do it this way. I've watched the Sencha Video on lists and they talk about this exact dilemma. Their solution is to put the list in a wrapper with the toolbar docked in the wrapper. So I did that but I am still unable to get it to layout the way it should.

1

1 Answers

3
votes

This seems to be an issue with your code, rather than a bug with the framework.

I'm going to assume that you want the final result to be a scrollable list, the size of the screen, with a toolbar docked to the top.

Here are some notes on what you need to change in order to make this happen:

  1. When defining a new class using Ext.define, you do not need to set it as a reference (app.customerList in your case), as the reference is automatically created using the first string passed. So in your case, you are doing this:

    app.customerList = Ext.define('CustomerList', { ... });
    

    However, you should just do this:

    Ext.define('app.customerList', { ... });
    

    After you have defined it, you can then reuse that class wherever you like, just like this:

    `var view = Ext.create('app.customerList');
    

    I'd also like to note here that using app.customerList isn't what Sencha suggest you to do regards to naming conventions, so I advice you to take a look at their Class System Guide when you have time to read up on how things should be named.

  2. When you define a class, 99% of the time you need to extend another class. In your case, you should be extending Ext. Container as we want to create the outer most component (which you defined as this.listWrapper) which includes the list, and the docked toolbar.

  3. When extending a class in Sencha Touch, you should not override the constructor method, instead you should use the initialize method. In this method, we will be adding the docked toolbar and our list. Here is what it should look like:

    initialize: function() {
        this.callParent();
    
        this.listComponent = Ext.create('Ext.List', {
            itemTpl: '<div class="contact">{first_name} <strong>{last_name}</strong></div>',
            store: customerListStore,
            id: 'customer_list',
            grouped: true,
            indexBar: true,
            listeners: {
                itemtap: {
                    fn: function (list, index, item, evt) {
    
                    },
                    element: 'element'
                }
            }
        });
    
        this.add([
            {
                xtype: 'toolbar',
                docked: 'top',
                title: 'Customers',
                items: [
                    {
                        xtype: 'button',
                        text: 'Home',
                        ui: 'back',
                        listeners: {
                            tap: {
                                fn: function() {
    
                                },
                                element: 'element'
                            }
                        }
                    }
                ]
            },
            this.listComponent
        ]);
    }
    

    There are a few things to remember from this snippet:

    • You always need to call the parent class in initialize, as the parent may be doing some logic that we need. You can do this by simply calling this.callParent();.
    • First we define our listComponent which we will later insert into this app.customerList container.
    • Next we call this.add with an array of objects. This method will insert our items into our new container class when it is initialized. The first object we pass is the configuration for our toolbar - which is the same as your code. And as the second object in the array we pass the listComponent.
  4. We want the list inside our new container class to stretch to the size of our container, so we can do that by adding the layout configuration of fit into the config block of our class.

    config: {
        layout: 'fit'
    }
    

    Please remember that this config block is only used when defining new classes using Ext.define. If you are using Ext.create, or passing a new component as a object (like we did above) you do not need to put them inside this special object.

  5. Finally, you do not need to use the fullscreen configuration. Instead, we can just create an instance of our new class and add it directly into the Ext.Viewport.

    var customerList = Ext.create('CustomerList');
    Ext.Viewport.add(customerList);
    
    // add this point you can reference the listComponent without the customerList like this:
    console.log(customerList.listComponent.getStore());
    

And the final code for your custom class is:

Ext.define('CustomerList', {
    extend: 'Ext.Container',

    config: {
        fullscreen: true,
        layout: 'fit'
    },

initialize: function() {
    this.callParent();

    this.listComponent = Ext.create('Ext.List', {
        itemTpl: '<div class="contact">{first_name} <strong>{last_name}</strong></div>',
        store: customerListStore,
        id: 'customer_list',
        grouped: true,
        indexBar: true,
        listeners: {
            itemtap: {
                fn: function (list, index, item, evt) {

                },
                element: 'element'
            }
        }
    });

    this.add([
        {
            xtype: 'toolbar',
            docked: 'top',
            title: 'Customers',
            items: [
                {
                    xtype: 'button',
                    text: 'Home',
                    ui: 'back',
                    listeners: {
                        tap: {
                            fn: function() {

                            },
                            element: 'element'
                        }
                    }
                }
            ]
        },
        this.listComponent
    ]);
}
});

var customerList = Ext.create('CustomerList');
Ext.Viewport.add(customerList);

// add this point you can reference the listComponent without the customerList like this:
console.log(customerList.listComponent.getStore());

Sorry about the complete refactor, but I thought I'd show you the correct way to write a custom class like this.