Learn from Saki

Knowledge is power

This content is for registered users only. Please login.
Hello! To access your account, please Log in. Not a member? Sign up
  • Videos
  • Blog
  • Examples
  • Services
  • Add-ons
  • About

Blessing and Curse of refs

March 31, 2014 by saki 5 Comments

refs
If you use MVC architecture in ExtJS or Sencha Touch you most likely already used refs configuration option of controller. The purpose of refs is to list views at the controller for easy later access. An accessor, a getter, method is automatically created for each listed ref.   For example:
1
2
3
4
5
6
7
Ext.define('My.Controller', {
     extend:'Ext.app.Controller'
    ,refs:[{
         ref:'myWindow'
        ,selector:'mywindow'
    }]
});
Having the above controller configuration, we can call the controller method getMyWindow to get a reference to the window instance. The following code works (provided it is run in the scope of the controller).
1
2
var win = this.getMyWindow();
win.show();
That’s the sunny part of life. No long ComponentQuery calls, no special handling of class variables, just a simple array of refs and that’s it.

Where’s the problem then?

It happens quite often, especially in larger apps, that we need more than one instance of the window. What then? Which one is returned by getMyWindow? First? Last? Or all in an array? I’ve created a little MVC application with one grid wrapped in an Ext window. You can create multiple independent instances of the grid. Grid has “Remove record” button in the top toolbar that is enabled by selecting a grid row and disabled by deselecting. First, create one instance of the grid to test it works that way.  
  Then create two instances and see what’s happening: The first grid works as before but selecting and deselecting a row in the second grid enables and disables button in the first grid. If you close first grid, second starts to work. Weird isn’t it? Now, let’s analyze the code to see why it is happening.

Grid configuration:

1
2
3
4
5
6
7
8
9
10
Ext.define('Saki.view.PersonGridView', {
     extend: 'Ext.grid.Panel'
    ,alias:'widget.persongrid'
 
    ,enableRemove:function(enable) {
        this.down('button#removerecord').setDisabled(!enable);
    } // eo function enableRemove
 
    // ... etc
});
There is nothing special here: we define the grid, give it an alias and implement button enable/disable public method.

Controller configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Ext.define('Saki.controller.MainController', {
     extend: 'Ext.app.Controller'
    ,refs:[{
         selector:'persongrid'
        ,ref:'personGrid'
    }]
    ,init:function() {
        var me = this;
        me.control({
            persongrid:{
                selectionchange:me.onSelectionChange
            }
        })
    } // eo function init
 
    ,onSelectionChange:function(selModel, records) {
        var  me = this
            ,grid = me.getPersonGrid()
        ;
        grid.enableRemove(!!records.length);
    } // eo function onSelectionChange
 
    // ... etc
});
We define our refs that selects xtype persongrid so that we can later call getPersonGrid() method to grab a reference to the grid. We also listen to grid selectionchange event. The listener (onSelectionChange method) only tests that anything is selected and calls grid’s method to update the enable state of the button.

The culprit!

When user selects a record in any grid controller knows that a row in some grid has been selected, onSelectionChange runs but getPersonGrid returns the reference to the first grid only. Internally, Ext.ComponentQuery.query('persongrid') is run but although that returns the array of all instances, only the first one is returned by getPersonGrid.

Conclusion

You can and should use refs but with caution: The moment we need more than one instance of a view the controller refs are useless, perhaps worse than that because they can be the source of hard-to-find bugs.  
Refs are good if their selectors can never select more than one view.

The solution

Simply stated: use initComponent and custom events if you need multi-instance views.
  • Author
  • Recent Posts
Follow me:
saki
I'm a well seasoned developer, consultant and educator of web applications based mainly on Sencha libraries, PHP, MySQL and Node.js. Besides (Apple) computers, I love photography and mountain biking.
Follow me:
Latest posts by saki (see all)
  • Ext, Angular, React, and Vue - June 27, 2019
  • The Site Resurgence - February 11, 2018
  • Configuring ViewModel Hierarchy - June 19, 2015

Filed Under: Architecture, ExtJS, Touch Tagged With: controller, multiple instances, MVC, refs, view

Comments

  1. Kyle Trusler says

    September 3, 2014 at 10:05 pm

    I’m interested in putting a container inside HTML like your inline “Create Grid Window” I have put

    like you, and inside the container I have

    renderTo: ‘saki-ext-Refs’,

    but I must be doing something wrong. Any help would be appreciated as this is the only place I’ve seen this.

    Log in to Reply
    • Saki says

      September 4, 2014 at 2:05 pm

      First of all make sure that the container with ‘saki-ext-Refs’ exists, for example <div id="saki-ext-Refs"></div>

      If you still do not see the expected component, try to renderTo:Ext.getBody() first to debug the code and after it works in body, render it back into the container of your liking.

      Log in to Reply
      • Kyle Trusler says

        September 4, 2014 at 10:23 pm

        The element is in index.html inside the body tags. I think my problem is that I have everything inside the main.js which I know isn’t correct, but that’s how the http://docs.sencha.com/extjs/5.0/getting_started/getting_started.html told me to. From what I understand main tries to create a viewport which I don’t want.

        I finally have the container rendering when I open up index.html, but the container is always on top of everything no matter what I do or what I designate it to “renderTo:”

        My problem is I do not have enough experience (I just started last week with no knowledge of css/html/js) to be able to make custom models and views and controllers since I don’t yet know how they all work, but I am trudging through. Thanks for your comment and this amazing site!

        Log in to Reply
        • Saki says

          September 5, 2014 at 1:52 pm

          Yeah, I do understand feelings of a beginner, I had also been one. I’ll probably make a video to get you and other beginners started if you want to embed an Ext app in an existing page.

          Log in to Reply
          • Kyle Trusler says

            September 5, 2014 at 9:52 pm

            That would be great! What do you do about createAutoViewport In app.js? From what I read when a viewport is made it tries to take up the whole webpage.

We will be happy to hear back from you Cancel reply

You must be logged in to post a comment.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Categories

  • Addons (2)
  • Architecture (14)
  • Examples (2)
  • ExtJS (26)
  • Howtos (16)
  • Javascript (1)
  • Know-how (32)
  • Linux (1)
  • Mac OS X (2)
  • SASS/CSS (2)
  • Snippets (9)
  • Theory (14)
  • Touch (6)
  • Tutorials (5)
  • What is a … (9)

Tag cloud

abstract class accordion application button class cluster column component config css definition deprecated design education event example extension extjs factory function form grid html initComponent items javascript Know-how knowledge layout Linux listener mysql old panel pattern php plugin render snippet sql sqlite state table touch tree viewpoint

Membership

Become a Member
Affiliate Program

Support

FAQ
Contact

Legal

Terms and Conditions
Licensing
Privacy Policy

Copyright © 2021 · Dynamik-Gen on Genesis Framework · WordPress · Log in