最近用到ExtJS的row widget控件,踩了一个大坑,具体来说就是参照官网的示例(http://examples.sencha.com/extjs/6.2.0/examples/kitchensink/#row-widget-grid)创建好工程之后,点击表格行展开,不显示子表格,如图:
正确的显示结果:
sencha论坛上也有类似的问题,不过都没有给出正面的解决方法,像这个:
https://www.sencha.com/forum/showthread.php?316582-RowWidget-Plugin-child-Grid-data-is-not-loading
给出的处理方法是:
把orders写到companies中,这可以暂时解决问题,但不是最好的方法,不过这个答案也给了我启发。
下面开始分析问题,首先从基本文件说起:
在官网的示例中,一个有四个类:
View是一个Ext.grid.Panel(1),指定store为Companies(2),包含一个ptype为'rowwidget'的widget plugin(3),这个widget绑定了store为'{record.orders}'(4)。
这个名为Companies的store如下图:
注意proxy的url为‘/KitchenSink/Company’,访问的数据在 ext-x.x.x\build\examples\kitchensink\classic\samples\data 下的Company.js文件里,为什么这个url就可以访问到数据内,看Company.js文件最后的一段:
是因为使用了Ext.ux.ajax.SimManager.register方法注册。
接着来看Company.js中的数据:
Ext.ux.ajax.SimManager.register注册的url返回的即是companies数组。
companies数据对应Company这个model:
由于我需要从web服务器获取数据,所以把Companies这个store改成了:
这个不重要,直接往下:
到这一步,如果文件配置正确的话,显示出父表格是没有问题的。
接着来看Order这个model:
整个工程中只define了一个KitchenSink.model.Order,并没有明确指定出哪一个store的model为Order,那它是如何起作用的呢?
仔细看rowwidget的配置项,红框处的bind:
很容易猜到这个bind会让这个store和Order发生一定的关系,我们来做个测试:
把 store: '{record.orders}' 改成 store: '{record.tests}' ,然后把 'KitchenSink.model.Order' 这个model改成 'KitchenSink.model.test',重新编译执行:
可正确显示(我这个子表数据请求的服务器端没有做处理,所以返回所有的数据,这个后面会讲)。
很容易看出,store: '{record.xxx(ie)s}' 会自动绑定名为xxx的model,然后获得数据,不区分首字母大小写,xxx(ie)s代表xxx的英文复数(写错了是不行的)。
这里还有一个关键的地方,Order的companyId要指定reference,parent为Company:
这个也是有讲究的,parent要设为父表格的model名,name为xxxId,xxx即父对象model名,不区分首字母大小写。
从理论上来说,配置好row widget的store就可以让row widget正常工作了,但是,为什么已经和示例文件一模一样了,Order还是不工作呢?
接下来就来说说在这个工程中最容易踩到的坑,包括上面sencha社区中的那个示例,也出现了这个问题:
注意看示例工程中Company和Order两个model有一个共同的的父类:'KitchenSink.model.Base',如果你不extend这个父类,直接extend Ext.data.Model,像我踩过的坑一样,那子列表怎么都不会显示。
之所以要extend这个父类,是因为需要父类声明一个namespace,Company和Order这两个model都在这个namespace中,像在我这个工程里,model名称前面的xxx.xxx需要和namespace一致。
最后,在View中requires里添加对Order这个model的引用(如果你不是sencha cmd生成的工程,可能不需要这么写)。
ok,现在可以测试是否正常展开子表格了。
另外,补充一下 /KitchenSink/Order 返回数据的一些细节:
同样在 ext-x.x.x\build\examples\kitchensink\classic\samples\data 目录下,Order.js文件:
注意它的register方法:
其中有对filters的处理,那row widget的proxy访问url时的参数是怎样的呢?
把最下面那个GET方法解码一下,结果是:
/Order?_dc=1477308085906&filter=[{"property":"companyId","value":1,"exactMatch":true}]
这个filter以及filter的处理方法就使得返回的orders只包含companyId == (filter中的companyId)的数据,结果就是展开的子表格只包含选中company的数据。
踩了这个坑虽然很郁闷,但是也让我对ExtJS的设计思路有了更深入的理解,我这里就不求甚解地给出解决方法,至于为什么要这样,等我对ExtJS理解更深的时候再更新吧。