Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cache subcomponents instance inside components

A lot of Sencha Touch examples I found online, don't really focus on proper view encapsulation. So the Controller listens to every single button's event even if the button is deep nested inside a view. In other words the internals of the view leak through which is never a good thing.

I found one good tutorial that encourages you to create meaningful views that listen to local events and raise meaningful business events etc.

http://miamicoder.com/2012/how-to-create-a-sencha-touch-2-app-part-2/

However, one thing that I couldn't really figure out so far is how to best cache nested component instances. Consider this example:

Ext.define("NotesApp.view.NotesListContainer", {
    extend: "Ext.Container",
    alias: "widget.noteslistcontainer",

    initialize: function () {

        this.callParent(arguments);

        var newButton = {
            xtype: "button",
            text: 'New',
            ui: 'action',
            handler: this.onNewButtonTap,
            scope: this
        };

        var topToolbar = {
            xtype: "toolbar",
            title: 'My Notes',
            docked: "top",
            items: [
                { xtype: 'spacer' },
                newButton
            ]
        };

        this.add([topToolbar]);
    },
    onNewButtonTap: function () {
        console.log("newNoteCommand");
        this.fireEvent("newNoteCommand", this);
    },
    config: {
        layout: {
            type: 'fit'
        }
    }
});

Let's say we want to add a method setSpecialUIState to our NotesListContainer. When it's called we want to do something with the newButton (e.g. hide it). How would I gain access to the newButton instance without misusing Ext.getComp() for that? Can I set it as an instance variable? How is the canonical way?

UPDATE

I just tried this as Nikolaj Borisik suggested.

    this._newButton = this.add([{
            xtype: "button",
            text: 'New',
            ui: 'action',
            handler: this.onNewButtonTap,
            scope: this
        }];

That works like a charm. I just don't know if its idiomatic to do so or if there are any downsides I might be missing. Otherwise I would highly recommend to do this. Sencha aside, it's much better to compose meaningful views that abstract away coherent UI parts. That's much better than leak every single button through to the controller and fiddle directly with them.

So I wonder if there are any downsides of this approach?

like image 470
Christoph Avatar asked Sep 17 '12 14:09

Christoph


1 Answers

I see two options except using getComponent() :

1 Using Ext.create(...) for instance component

initialize: function () {        
   this.callParent(arguments);
   this.newButton = Ext.create('Ext.Button',{
      xtype: "button",
      text: 'New',
      ui: 'action',
      handler: this.onNewButtonTap,
      scope: this
   });
   //....
},

setSpecialUIState : function(){
   this.newButton.hide()
}

2 Move this logic into controller and use refs section

Ext.define('NotesApp.controller.Home',{
        extend : 'Ext.app.Controller',

        config : {
            refs :{
                newButton : '#noteList [itemId=newButton]'
            },

            control :{
                newButton : {
                    tap : 'onNewButtonTap'
                }
            }

        },

        onNewButtonTap : function(){
            console.log('on new Button tap');
        },

        setSpecialUIState : function(){
           this.getNewButton.hide()
        }

    });



Ext.define("NotesApp.view.NotesListContainer", {
    extend :"Ext.Container",
    alias  :"widget.noteslistcontainer",
    id     :'noteList',
    config:{
        items:[
            {
                xtype  :"toolbar",
                title  :'My Notes',
                docked :"top",
                items:[
                    { xtype:'spacer' },
                    {
                        xtype   :"button",
                        text    :'New',
                        ui      :'action',
                        itemId  :'newButton'
                    }
                ]
            }
        ]

    }
});

I prefer the second option

I use both options, but in different case. I think that first option better suited for component that can be reused in other part of application or even in other project. But when we create some views that can be used on only once, i think not neccessary fired the custom events from view. We write more code, and duplicate it. Yes, 'newNoteCommand' more clear than 'tap', but { control : '#noteList [itemId='newButton'] give us all neccessary info. Second why i prefere second option, when we have a deep nesting of components. In this case we should fired event in first component, than fire event from his parent and so on, until controller has chance to handle it.

like image 166
Nikolai Borisik Avatar answered Sep 18 '22 04:09

Nikolai Borisik