Search code examples
oopextjsextjs4getter-setter

Ext JS 4: Getters and setters in view


I've been thinking about this problem for a while, and I can't seem to come up with a reasonable solution. What I would like to do is create getters/setters for a textfield/its value in my view. I realize that the preferred Ext JS way is using a reference within the controller and getting it that way, but that doesn't feel very object-oriented to me. I'd also have to wrap these getters and setters because I want to output a message if the getter returns undefined. What I'd like to do is create my own getters/setters or somehow override the default getters/setters. Here are some ways I was thinking of accomplishing this.

I was thinking I could use the config {}, but that appears to only work for variables I want to define. I then was thinking of using an id somehow, but the community seems split on whether that's a good practice or not. Which leads to my current solution... wrapping. Here's my code:

LoginWindow

Ext.define('MyApp.view.LoginWindow', {
    extend: 'Ext.window.Window',
    alias: 'widget.loginWindow',
    autoShow: true,
    closable: false,
    border: 0,
    plain: true,
    allowBlank: false,
    title: "Enter your username",
    modal: true,
    config: {
        buttons: [{
            text: "Ok"
        }],
        items: [{
            xtype: 'textfield',
            fieldLabel: 'Username',
            id: 'loginUserInput',
            name: 'loginUserInput',
            msgTarget: 'under',
            validator: function(value) {
                if (Ext.isEmpty(value)) {
                    return "You need to enter a username.";
                }
                return true;
            }
        }]
    },

    constructor: function(config) {
        this.callParent(config);
    },

    getButton: function() {
        console.log('here');
    }
});

MyController

Ext.define('MyApp.controller.Chat', {
    extend: 'Ext.app.Controller',

    requires: [
        'Views.ChatModule.view.LoginWindow'
    ],

    refs: [{
        ref: 'loginWindow',
        selector: 'loginWindow',
        xtype: 'loginWindow',
        autoCreate: true
    }, {
        ref: 'loginUserInput',
        selector: '#loginUserInput'
    }],

    init: function() {
        // The events controller oversees
        this.control({
            'loginWindow button[text="Ok"]': {
                'click': this.onSubmitLoginWindow
            }
        });
    },

    getLoginUserInputValue: function() {
        var loginUserInput = this.getLoginUserInput();
        if (loginUserInput) {
            var username = loginUserInput.getValue();
            if (username) {
                console.log(username);
            } else {
                console.warn("username is undefined");
            }
        }
        console.warn("loginUserInput is undefined");
    },

    onSubmitLoginWindow: function(button, event, eOpts) {
        this.getLoginUserInputValue();
    }
});

This works, and I realize it's a very nit-picky thing, but it just doesn't feel right to have the getter in the controller. I feel like it'd be more object-oriented if it was in the Window. However, if I put it in the Window, I believe my only option is to lean on ids or manually create the textfield in the Window's initComponent--which would involve saving off a reference of the textfield in there, but that seems a bit inefficient... as I would have to make a call to doLayout as well.

Just to reiterate, I'd love to have the getters/setters in the Window, and I'm looking for a quick way to reference it, similar to how the controller references objects. I believe the main answer will be to use ids and making a call to Ext.ComponentQuery.query('#loginUserInput') in the Window, but I'd like to know if there were any better approaches out there... like overriding the auto generated getters/setters or adding a simple getter/setter for an input's value.

Cross-post from the Sencha forums.

Edit

I guess I was a bit unclear with what I want. As a more general statement, instead of jamming all things related to my view in the controller, I'd like to store it all in the view itself, which includes things like getters/setters. One of these getters/setters just so happens to be the loginUserInput getter.

Using a model is an interesting idea, but I feel like that would be a whole lot of overhead for singleton values. I'm basically looking for something like Java's setters/getters in the LoginWindow view... and hopefully something as simple as (or close to) Java's.

The idea of including (encapsulating) it in the view makes the controller a bit cleaner, and if I delete the view, I'm deleting its functions as well, so I don't have to go hunting for the functions in the controller... all I have to worry about is removing the references (which should be minimal).


Solution

  • My thoughts are something like this:

    ...
    items: [],
    constructor: function(config) {
      this.loginUserInput = Ext.create('Ext.form.field.Text', {
        fieldLabel: 'Username',
        id: 'loginUserInput',
        name: 'loginUserInput',
        msgTarget: 'under',
        validator: function(value) {
          if (Ext.isEmpty(value)) {
            return "You need to enter a username.";
          }
          return true;
        }
      });
      this.items.push(this.loginUserInput);
      this.callParent(config);
    },
    
    getLoginUserInput: function() {
      var loginUserInput = this.loginUserInput;
      if (!loginUserInput) {
        console.warn("LoginWindow::getLoginUserInput: loginUserInput is undefined");
      }
      return loginUserInput;
    }
    

    So instead of letting Ext do its magic, I am now instantiating the object on my own, which then allows me to store away a reference of it, so I can easily access it in my getter. I just wonder if this is creating any sort of performance hit. It doesn't seem like it'd be that much worse... it actually seems like it'd be a bit better because I'm not referencing this object by its ID, and I don't have to go searching for it when I need it.