存档

‘ExtJS’ 分类的存档

Extjs compositefield bug 定宽的form中compositefield消失

2012年1月4日 没有评论

问题是这样的,Extjs 3.3.1版本中,在定宽的form中compositefield的label显示,但是field不显示,我试了一下发现非定宽的form就显示的, 原因是非定宽的form中 compositefield的 element的其中一个position relative的div 是设置高度的,在定宽的form中这个高度是没有被设置的,这个position relative的div的子元素全部是position absolute 的,这样子这个元素就失去高度了,而恰恰这个div又有overflow hidden 而且他父元素也是 overflow hidden   

有个解决办法

Ext.getCmp(‘your_compositefield’).doLayout(); 

是否有其他重现的条件不清楚,遇到此问题可以如上解决

分类: ExtJS 标签:

Extjs Combobox displayField有相同值造成的经典bug

2012年1月4日 没有评论

今天同事说combobox有两个选项选出来的id是一样的,看了一下还确实是两个选项选出来的id一样(store里面这两个record的值确实不一样),头一次遇见这种诡异的bug,但是有个特征就是这两个选项的字是一样的,就是displayField的值相同才会出现这种bug。

查了一下源码(Combo.js)里面没有太特殊的实现,有几处值得怀疑的

 

    // private
    onSelect : function(record, index){
        if(this.fireEvent('beforeselect', this, record, index) !== false){
            this.setValue(record.data[this.valueField || this.displayField]);
            this.collapse();
            this.fireEvent('select', this, record, index);
        }
    },
    assertValue  : function(){
        var val = this.getRawValue(),
            rec = this.findRecord(this.displayField, val);

        if(!rec && this.forceSelection){
            if(val.length > 0 && val != this.emptyText){
                this.el.dom.value = Ext.value(this.lastSelectionText, '');
                this.applyEmptyText();
            }else{
                this.clearValue();
            }
        }else{
            if(rec){
                // onSelect may have already set the value and by doing so
                // set the display field properly.  Let's not wipe out the
                // valueField here by just sending the displayField.
                if (val == rec.get(this.displayField) && this.value == rec.get(this.valueField)){
                    return;
                }
                val = rec.get(this.valueField || this.displayField);
            }
            this.setValue(val);
        }
    },

来分析一下,onSelect的时候是先setValue然后fireEvent select事件,我让同事实验了一下,发现在select事件响应函数中取得的选择是对的,那是不是setValue的时候出错了,很有可能,因为getValue就是返回之前setValue设置的值

看一下setValue的实现:

    setValue : function(v){
        var text = v;
        if(this.valueField){
            var r = this.findRecord(this.valueField, v);
            if(r){
                text = r.data[this.displayField];
            }else if(Ext.isDefined(this.valueNotFoundText)){
                text = this.valueNotFoundText;
            }
        }
        this.lastSelectionText = text;
        if(this.hiddenField){
            this.hiddenField.value = Ext.value(v, '');
        }
        Ext.form.ComboBox.superclass.setValue.call(this, text);
        this.value = v;
        return this;
    },

setValue里面最可疑的就是那个this.findRecord,

    findRecord : function(prop, value){
        var record;
        if(this.store.getCount() > 0){
            this.store.each(function(r){
                if(r.data[prop] == value){
                    record = r;
                    return false;
                }
            });
        }
        return record;
    },

findRecord使用record中的一个字段做循环比较,是不是哪里弄错了误用了displayField做为比较的字段,这里面displayField是有相同值的,那肯定findRecord的结果是第一个匹配的record了,但是查了一下这个过程,确实没有误用的地方。

这个时候我同事说在 combobox的blur事件之后 再调用这个combobox的getValue就不对了,之前提到的可疑点assertValue 在beforeBlur的时候有调用,而且就只有这一个地方调用,firebug调试了一下果然是这个函数的问题,这个函数的实际运行结果是走到了函数中setValue那一行,而setValue设置的值却是用getRawValue的结果去findRecord,之前说了,如果findRecord用displayField作为比较字段,取出来的肯定是displayField所有相同值中排在最前面的那个值。  让同事又增加了一个相同的displayField值试验了一下,果然如此。

但是有个疑问:assertValue这个函数从名字上看不出什么作用,那beforeBlur中为什么要调用这个校验函数呢,结合这个函数中一个if语句判断了this.forceSelection 突然明白了:

如果forceSelection为false,Extjs的combobox是既可以选择,又可以手动输入值的,这个时候它就需要校验你手动输入的值,是否在displayField中已经出现,如果已经出现,那提交的时候需要提交这个displayField对应的valueField,如果没有出现,那么直接提交手动输入的内容。这个时候,如果displayField中有两个相同的值,这个combobox的value 就被设为第一个相同值的id了,由此导致了这个bug

但是想想,这真的算个bug吗,当用户点开下拉框,看到两个相同的选项,他应该选哪个?在Extjs出bug之前,我们已经犯了错误。

分类: ExtJS 标签: ,

让Extjs combobox form submit 提交valueField,而不是displayField

2012年1月4日 没有评论

如果用form.submit() 或者form.doAction(‘submit’)

是不是遇到过提交到后台的值,是combobox选中的那个显示的值

这个问题是这样的

ExtJS的ComboBox是它自己通过n多html标签绘制出来的,作为一个纯粹的html的<form>,需要一个类似<input>的标签才是可提交的值

Extjs的表单中ComboBox默认是没有这个对应的<input>的,虽然你getValue()可以获取正确的值

需要设置一个hiddenName
,这样Extjs会给Combobox增加一个<input>,这个<input>会被设置为valueField对应的值,这样你form.submit() 或者form.doAction(‘submit’)就可以传递value给后台了

Extjs文档里是这么描述的

hiddenName

: String

If specified, a hidden form field with this name is dynamically generated to store the field’s data value (defaults to the underlying DOM element’s name).
Required for the combo’s value to automatically post during a form submission(表单提交过程中如果combo的值自动提交,hiddenName是需要设置的). See also valueField
.

分类: ExtJS 标签: ,

Ext.data.Store.find,你了解他的功能吗?

2012年1月4日 没有评论

今天遇到了一个勾选GridPanel里面某行总是不对的问题,研究了store的数据结构发现没什么问题,猜测是不是Ext的代码出bug了?看源代码分析了一番……

Ext.data.Store.find的匹配模式,使用的是test方法,源代码片段是

value.test(r.data[property]);

也就是说,store.find(‘find’, ‘a’);

如果store里面有两行record,一行的find列是’a', 一行的find列是’ab’,那么会返回先匹配到的那一行,而不是你想要的’a',如果你想用find方法获得你给定的值相等的行,那就错了

如果要用精确匹配,使用Ext.data.Store.findExact()方法

这个方法是这样实现的

findExact: function(property, value, start){
        return this.data.findIndexBy(function(rec){
            return rec.get(property) ===
value;
        }, this, start);
    },

 

注意这里面的匹配使用的是恒等===,
所以你要注意你store的fields配置了,如果你配置了int,那么用数字字符串去匹配的返回值永远是-1,这时先做个parseInt处理一下你的数字字符串

在Ext官网的手册里面,上面提到的两个函数的说明,都是下面这句,

Finds the index of the first matching Record in this store by a specific field value.

Finds the index of the first matching Record in this store by a specific field value.

这里Ext可能疏忽了

分类: ExtJS 标签: ,

Extjs tree 如何获得选中的节点

2012年1月4日 没有评论

这里说的选中是指鼠标点击一个节点后,节点那一行出现浅蓝色背景的选中,而非checkbox的勾选

方法

 

Ext.tree.TreePanel.getSelectionModel().getSelectedNode();

Ext.tree.TreePanel.getSelectionModel()获得的是一个TreeSelectionModel对象,

这个TreeSelectionModel目前在Ext中有两个Ext.tree.DefaultSelectionModel和Ext.tree.MultiSelectionModel

 

Ext.tree.MultiSelectionModel的获取选中节点的方法是getSelectedNodes
(),这个返回的是节点数组,Ext.tree.DefaultSelectionModel.getSelectedNode()返回的是单个节点对象。

分类: ExtJS 标签: ,

ExtJS Grid中文字链接点击事件的更合理的处理办法

2012年1月4日 没有评论

我们经常会给GridPanel中的某一个column加一个renderer,让它的内容可以变成一个链接,例如:

    resultRenderer: function (value) {
        return ‘<a href=”http://www.example.com/” onclick=”some_function()”
>查看</a>’;
    }

这样在Grid中,查看那两个字就变成链接了

如果点击这个查看的时候,想弹出窗口,那么我们最普通的方式,就是给链接加一个onclick响应函数,

onclick这里调用的函数,必然是通过全局的方式了,这样做有个缺点,就是全局函数的扩散,造成可维护性下降

其实,有一种更合理的处理办法,不论renderer中生成的是链接,还是其他的内容比如button,都是通用的

代码如下

首先给grid添加一个cellclick事件的响应函数

grid.on(‘cellclick’, grid.onCellClick, grid);

响应函数中做如下处理

    onCellClick: function (grid, rowIndex, columnIndex, e) {
        if (e.getTarget().innerHTML === ‘查看’
) { //借助事件的target来判断,这里是链接可以这样判断,其他方式亦可
            var record = grid.getStore().getAt(rowIndex);  // Get the Record
            var fieldName = grid.getColumnModel().getDataIndex(columnIndex); // Get field name
            var data = record.get(fieldName);//这个data就是点击的单元格的数据了,一定有用的
           
            if (fieldName == ‘this_column’) {
                //如果是这一列,做这个事
            }
           
            if (fieldName === ‘that_column’) {
                //如果是另外一列,做另外的事
            }
        }
    }

这个方法,不仅可以处理链接,简化一下就是处理某个单元格点击,onCellClick的作用域还是grid,这个是重点,
onCellClick还是在grid这个组件之内,而没有产生全局调用
,另外点击onclick的响应函数,只能接收字面参数,想传递一个对象是不可能的,如果应用上述方法,即可解决

分类: ExtJS 标签: ,

ExtJS编程思想和开发方式|ExtJS单页面系统|ExtJS单页面应用

2012年1月4日 没有评论

唠叨几句:不要认为 EXTJS 就是一个界面改良,在项目中,我仍然用 N 张页面,在 N 张页面部署 EXTJS .这个我不用多讲,效率问题大家都看得出来, EXTJS 是一个集成开发工具,注定他的开发包很大,一个 600 多 K 的 JS 文件,打算让它下载多少次呢?应该说, EXTJS 不仅是一个 AJAX 开发框架,也是一个富客户端开发平台, AJAX 是可以部署到多个页面,而完整的 EXTJS 是不能这样的做的,但是,他却能和 FLEX 一样,在一张页面中,完成项目中所有事件。

一、单页面

目前的应用方式:一个 Viewport ,点击每个菜单在 Viewport 的 center 区域生成一个 tab ,这个 tab 就是一个 panel , panel 中用 html 属性放置一个 iframe ,用 iframe 去加载另外一个全新的页面。

单页面方式:还是一个 Viewport ,点击每个菜单在 Viewport 的 center 区域生成一个 tab ,这个 tab 就是一个 panel ,但是 panel 中不使用 iframe ,而是将原来用 iframe 方式加载的内容,直接“画”在 panel 中。

目前的应用方式的问题:
1.  占用内存超高:每个 tab 都会用 iframe 加载一个全新的页面,每个页面都会载入一套完整的 ExtJS 的运行环境,由于浏览器的原因,这些 tab 关闭的时候内存不会完全释放,这样随着 tab 的开关,内存占用越来越多,占用几百 M 都没问题。
2.  center 区域内部的宽高,无法随浏览器宽高变化,无法自适应
3.  iframe 内外相互控制,内外沟通非常困难
4. 需要消耗额外的 js 解析时间,速度慢,重新加载要消耗解析 js 的时间
5.  用 iframe 有时候会导致一些莫名其妙的变形问题,滚动条问题

 

单页面方式:
1. 不用 iframe 加载, ExtJS 自己会释放无用的对象、事件占用的内存,一般一个应用只占用几十 M 内存
2.  由于是在一个页面内, ExtJS 自己可以掌控宽高自适应
3. 单一页面无此问题
4. 只需要第一次载入页面的时候加载 ExtJS 运行库
5.  很容易控制,无此问题
二、组件化

编写 ExtJS 程序,应该像搭积木一样,在 Viewport 这样一个框架中,我们添加各种积木块进去得到我们想要的形状。 Extjs 给我们提供了很多最小块的积木,每一块都是一个组件,我们可以将几个最小的组件组合成一个稍微大一点的组件,我们不可能每个功能都从最小的组件从头搭建,我们可以收集一些更大一些的组件,实现这个层面的组件复用,组件是可大可小的,组件的复用也是可大可小的。组件化编程是一个思想,而不是一门技术,这个思想可以用在任何地方。

三、 UI 与逻辑分离

可能大家都已近习惯了将 handler 和 listeners 与一大堆 Config Options 写在一起了。不能说这是一种错误的用法,但是这绝对不是好用法。类似下面这种代码是不是随处可见呢?
不好的写法

这种写法,再加上全集变量泛滥,就会导致整个 js 文件混乱不堪,一个 js 文件 3000 行代码

3000行
全局变量满天飞,想要的时候找不到,我想大家都遇到过吧。
再看一下下面这段代码,不会不感觉清爽很多呢
清爽
UI 与逻辑分离,就是在设计一个组件的时候,将 UI 写成一个类,将事件处理和其他逻辑写成另外一个类,两个类存放在两个不同的 js 文件中 ( 非必须 ) 。这样子的好处:
1.  改动 UI 和逻辑,几乎不会相互影响
2.  代码清晰规范,提高开发速度,降低维护成本
3.  组件可以重用,界面可以重用
4.  有利于开发规范的统一
5.  因为使用继承,内存开销减少,运行速度加快

分类: ExtJS 标签: ,

overflow bug ie6 & ie7, also ExtJS checkboxgroup

2012年1月4日 没有评论

overflow bug ie6 & ie7, also ExtJS checkboxgroup

是这样遇到问题的,做了一个items是一个checkboxgroup的Ext的Window

结果在ie6和ie7下,会出现checkbox超出(溢出Ext.Window的body),而且滚动条不起作用的bug,

麻痹的,好顿查

http://snook.ca/archives/html_and_css/position_relative_overflow_ie

这是解决ie overflow bug的原文,

用firebug看了一下, checkboxgroup的外层,也就是x-window-body,他的position是static的,没办法,想办法改掉试试吧

Ext.select(‘.x-window-body’, false, that.getEl().id).first().applyStyles(‘position:relative’);

试了一下竟然ok了,就是ie overflow的bug

again fuck ie6 & ie7

分类: ExtJS 标签: ,

Extjs Form 设置初始值的时候确保reset正确值

2012年1月4日 没有评论

有些时候Ext.form.FromPanel中的组件都写好了,但是初始化的时候需要给组件填写初始值,例如combobox,textarea等。

可以使用Ext.getCmp(‘combobox’).setValue(‘value’);来设置初始值。

但是这样设置初始值有个问题,就是如果form.reset();
设置初始值的combobox就会被清空,因为form最初被实例化的时候,combobox是没有值的。

此时在setValue后,增加一句话,即可保证reset到正确的值:
Ext.getCmp(‘combobox’).originalValue = value;

分类: ExtJS 标签: