Ext JS 4: 视图中的Getter和Setter

3
我已经思考了一段时间这个问题,但是似乎无法想出一个合理的解决方案。我想要做的是在视图中为文本字段/其值创建getter/setter。我知道首选的Ext JS方法是在控制器内使用引用并以此获取它,但这对我来说不太符合面向对象的设计思想。我还需要封装这些getter和setter,因为如果getter返回undefined,我想输出一条消息。我想做的是创建自己的getter/setter或以某种方式覆盖默认的getter/setter。以下是我考虑实现这一点的几种方法。
我想我可以使用config {},但这似乎只适用于我想定义的变量。然后我想以某种方式使用id,但社区似乎对此持不同意见。这导致了我的当前解决方案... 封装。以下是我的代码:

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');
    }
});

我的控制器

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();
    }
});

这个方法可行,我意识到这是一个非常苛刻的事情,但在控制器中使用getter并不合适。如果将其放在Window中,会更符合面向对象的设计思想。然而,如果我将其放在Window中,我相信我的唯一选择就是依赖于ID或在Window的initComponent中手动创建textfield——这需要保存一个引用,在那里,但这似乎有点低效……因为我还需要调用doLayout。
再次强调,我希望在Window中具有getter/setter,并寻找一种快速引用它的方法,类似于控制器引用对象的方式。我相信主要答案将是使用ids并在Window中调用Ext.ComponentQuery.query('#loginUserInput'),但我想知道是否有其他更好的方法……比如重写自动生成的getter/setter或添加一个简单的getter/setter来获取输入的值。
Sencha论坛跨发。 编辑 我想我之前表达不够清楚。更普遍地说,我想将所有与我的视图相关的内容存储在视图本身中,而不是将它们都放在控制器中,这包括像getter/setter这样的内容。其中一个getter/setter恰好是loginUserInput getter。
使用模型是一个有趣的想法,但我觉得这对于单例值来说会增加很多开销。我基本上正在寻找类似于Java中的setters/getters 在LoginWindow视图中...希望它也和Java一样简单。
将其包含(封装)在视图中使控制器变得更加简洁,如果我删除了视图,它的函数也会被删除,因此我不必去控制器中搜寻函数...我所要担心的只是移除引用(应该很少)。
3个回答

1
我认为你需要的“OO”方式是使用Ext.data.Model来处理表单。如果你查看Ext.form.Basic,你会发现有一些操作模型(称为记录)和获取视图值对象的方法。因此,你需要:
  1. 创建表单时,使用loadRecord()将表单绑定到一个模型。
  2. 在任何时候需要时,使用getValues()检索表单字段的值。
  3. 提交表单时,使用getRecord()getValues()同步记录。

Ext.define('MyApp.model.Login',{
  fields : [{
    name: 'username',
    type: 'string'
  },{
    name: 'password',
    type: 'string'
  }]
});

Ext.define('MyApp.controller.Login',{
  ...
  refs : [{
    selector: 'window form',
    ref: 'formPanel'
  }],
  ...
  openForm : function() {
    //load your form and then bind the new record
    var formPanel = this.getFormPanel(), //Ext.form.Panel
        form = formPanel.getForm(); //Ext.form.Basic

    form.loadRecord(Ext.create('MyApp.model.Login'));

  },
  save : function() {
    //get the values in the view
    var form = this.getFormPanel().getForm(),
        vals = form.getValues(),
        record = form.getRecord();

    console.log(vals); //see the object representation of your view here
    record.set(vals); //update your model

    //do whatever you need with your model

  }
  ...
});

这是一个很好的示例,当您需要保存表单数据时可以使用。在登录中,我认为您可以直接使用 getValues() 而无需将其绑定到 Ext.data.Model

请看更新...不确定这是否更清晰或更令人困惑,请告诉我。 - incutonez

0

说实话,我不太确定你想解决什么问题。

如果你不喜欢控制器监听窗口内的按钮,你可以在视图定义中使用按钮处理程序触发自定义事件,然后控制器可以监听它们。使用fireEventmethod。顺便说一下,initConfig是设置视图的推荐方式。如果你愿意,你可以将其拆分成方法,'this'引用可用,并且是被实例化的View组件。

如果你需要在视图中查找内部组件,有许多可用的方法,从up/downnextSiblingquery

For Components:
    • Ext.getCmp(id)
    • Ext.ComponentQuery.query()
    • up() 
    • down() 
    • nextSibling() 
    • previousSibling()
    • child()
    • previousNode()
plus various find.. Methods

编辑

我认为我理解了你所说的getter和setter。Ext表单有字段查找器,以使获取和设置数据到个别字段变得容易。请参见这些SO问题:最佳方式访问相邻组件/字段 EXT.JS从字段集中获取项目列表

另外像Sergio所说,表单上有getRecord、getValues和setRecord方法来处理数据绑定。就是这样。

编辑2

最好的起点指南显示清晰和明确的MVC模式以及表单处理。 http://docs.sencha.com/extjs/4.1.3/#!/guide/application_architecture


上/下/下一个兄弟节点/上一个兄弟节点/子节点/上一个节点都显得很局限...你需要知道自己相对于父节点的位置。这似乎不是好的面向对象编程。请问您的说法“顺便说一句,initConfig是设置视图的推荐方式”来自哪里?Sencha是否建议以此方式操作?如果是这样,您是否意味着在LoginWindow的initConfig中创建我的实际按钮?只是好奇。另外,我在我的初始问题中添加了一个更新。 - incutonez
1
请查看您原始问题的更新。回答您关于推荐方法的问题:config 只在 Sencha Touch 产品中真正使用。在 extjs 中,除非您正在创建一个不扩展 extjs 组件的类,否则根本不需要它。这是初始化组件的好方法:http://mitchellsimoens.com/?p=59 - dbrin
有趣的是...从那篇博客中,看起来我应该在initComponent中创建我的按钮和项目...如果我这样做了,我可以在实际类中设置对每个组件的引用,这将使得我的getter/setter非常容易访问。 - incutonez
我觉得这样可能会更加昂贵... 我想在将项目推送到LoginWindow的items数组之前,我必须先调用父级,这将迫使我在LoginWindow上调用doLayout,以便它的items/buttons能够显示。我明天会试验一下。 - incutonez
不,这并不是建议你做的事情。容器将所有子组件保存在items数组中。您可以使用上面描述的方法来查找这些项。而且,不再调用doLayout - 您可能看到的那些示例都已过时。 - dbrin
如果您需要更多不同类型的示例,可以查看这些网址:http://jsfiddle.net/user/dbrin/fiddles/ - dbrin

0

我的想法大致如下:

...
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;
}

所以,现在我不再让Ext自己处理了,而是手动实例化对象,这样我就可以存储它的引用,方便在getter中轻松访问。我只是想知道这是否会对性能造成任何影响。看起来并不会更糟...实际上似乎会更好,因为我不是通过ID引用此对象,并且在需要时也不必搜索它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接