ComboBox被完全集成于Extjs 的数据包当中。这就使他在下拉列表中的的数据被限定在数据仓库当中(data store)。在其带来丰富的优点的同时,也带来了许许多多的易发错误的来源。在本部分我会试着阐明一个带有store配置项的combobox。
一:明确的建立一个Store对象。
在之前的一篇文章当中。我介绍了一些常用的combobox的配置选项。但是有一个在每个例子中都用到的配置选项Store我却没有进行介绍。这个配置选项包含了一个包含下拉列表的数据的数组。
Ext.create('Ext.form.field.ComboBox', { store: ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'] });
然而,如果列表中的数据在进行开发的时候并不能预先知晓的话。这样的内置数据的配置方式就会带来非常非常多的不便。对于一个存有大量数据的列表。一次就把他们全部加载进来时相当的不切实际的。这样的话,一些服务器端的过滤和分页就需要被部署。
提供一个内联的数据,会隐式的建立一个完整的Store对象。这里有三种方式来提供对配置store对象的完全控制。
第一种方式就是制定store对象为一个内联的配置项
Ext.create('Ext.form.field.ComboBox', { store: { fields: ['text'], data: [ {text: 'Red'}, {text: 'Yellow'}, {text: 'Green'}, ... ] } });
第二种传递store对象的方式,先建立一个store对象,然后再传递给Combobox对象
var store = Ext.create('Ext.data.Store', { fields: ['text'], data: [ {text: 'Red'}, {text: 'Yellow'}, {text: 'Green'}, ... ] }); Ext.create('Ext.form.field.ComboBox', { store: store });
第三种方式传递的是一个store对象的id
Ext.create('Ext.data.Store', { fields: ['text'], storeId: 'my-store', data: [ {text: 'Red'}, {text: 'Yellow'}, {text: 'Green'}, ... ] }); Ext.create('Ext.form.field.ComboBox', { store: 'my-store' });
虽然以上的三种配置方式当中的数据仍旧是内嵌的。但是现在这些配置已经是store对象的一部分,而不是直接在combobox当中进行配置。 从combobox的视角来看数据是可以来自任何地方的,而combobox看到的仅仅是一个store对象(就是说这些数据只要放在store当中,然后把这个store对象传递给我,我就能够显示数据,而不是非要报数据写在combobox当中我才能显示数据)。数据的格式经过了轻微的改动以适应store的数据格式。每一个store对象都有一个fields配置选项,其默认值为text。
如果你尝试了上面三个例子当中的一个的话,你就会发现他们的表现跟本来的那些例子有所不同。新的表现的方式是相当的奇怪的。而且难以彻底弄清楚其中的缘由。稍后我们会看到一个例子,但是为了更好的理解它,我们就必须先了解combobox是如何处理远程数据的。
三:远程数据
使用store配置选项,而不用内置的数据的一项主要原因就是,这使得加载从服务器而来的远程的数据更加的简单。来让我们先看一些简单的例子吧。这里面还有一些新出现的配置选项需要解释一下。
Ext.create('Ext.form.field.ComboBox', { queryMode: 'local', store: { autoLoad: true, fields: ['text'], proxy: { type: 'ajax', url: 'snooker-balls.json' } } });
其中store的autoLoad配置选项被配置为true,所以啊,他就会在自己被创建的之后尽快的加载数据。然后proxy对象就会利用AJAX方式与给定的服务器和URL交互,以此来获取数据。
JSON从服务器端返回的数据大概是这个样子 [ {"text": "Red"}, {"text": "Yellow"}, {"text": "Green"}, {"text": "Brown"}, {"text": "Blue"}, {"text": "Pink"}, {"text": "Black"} ]
你可以自己试试下面的例子,这些数据会在store被创建之后尽快的加载进来。因此这些数据看起来就像是在本地存储的一样快。
到目前为止我还没有介绍为什么这个神秘莫测的queryMode配置选项被设置为了local数据明明是从远方的服务器加载来的,那么为什么这个配置选项还是被设置成了local模式呢?
在前面的一篇文章当中我们碰到过一个配置选项是这样的triggeraction:'query'正如我们在那篇文章中看到的那样。在combobox的上下文语义中,query的意义实际上指的是过滤下拉列表中的值。
在对queryMode进行翻译的时候如果我们也这样考虑的话, 那么这个配置选项的方式就会有更多的意义。尽管列表中的值是被远程加载进来的。但是过滤这项操作仍然是在本地完成的。当用户输入文本数据的时候,下拉列表的就会在本地被过滤,其并不需要向服务器端进行更进一步的查询操作。
在 ExtJs 4 之前的版本当中。queryMode被简单的指明为mode,这就导致了许许多多的疑惑,因为这个名字没有暗示它实际上到底做了什么。
四:远程过滤
从远程的服务器获取一个列表的数据非常好用。但是这又是远远不够的。要是我们有非常非常多的数据,以至于在浏览器端进行过滤会变得非常的不现实。我们需要做的第一个改变就是更改queryMode:'remote',因为这种配置是默认的,所以我们可以直接把这个配置选项给去掉。同样的,我们也需要把autoLoad;truep 配置选项给去掉,这时store就不会立刻去服务器端加载数据。
Ext.create('Ext.form.field.ComboBox', { store: { fields: ['text'], proxy: { type: 'ajax', url: 'snooker-balls.json' } } });
然而故事讲到这里才讲到了一半,服务器必须被设置为可以用来立刻进行过滤操作利用上面的配置方式,如果我们键入blac的话,combobox会发送一个请求,大概是这个样子。
snooker-balls.json?query=blac&...
为了让这个例子完成其功能。服务器就必须明白如何返回一个被过滤后的数据。请求中的参数query可以被改变,我们只需要设置,queryParam,但是对于这个例子默认的名字就挺好。
对于这个例子还有一些问题,
在键入四个字符之前,什么都不会发生。单击箭头还是会将所有的数据展现出来。在我们假想的情况下这样就会有太多的数据被加载。下面我们按顺序一个个的处理这些问题。首先当使用远程过滤的时候,minchars
配置选项可以设置的范围是0到4.这就可以防止数据在达到四个字符长度之前被传送到服务器。有时候当数据未达到指定的长度的时候我们不希望发送这些字符用来在服务器端进行过滤,但是对于我们本例中较小的数据集合,这个需求就不是那么迫切了。所以我们可以把它下调为1.
Ext.create('Ext.form.field.ComboBox', { minChars: 1, store: { fields: ['text'], proxy: { type: 'ajax', url: 'snooker-balls.json' } } });
禁止下拉箭头触发查询操作被证明是相当简单的。在前面的文章中我们可以看到。设置triggerAction:‘query’将会强制trigger根据当前的值进行过滤查询的操作。这也涉及到了minchar配置选项。因此单击trigger或者按下向下键将不会有任何的功能。
Ext.create('Ext.form.field.ComboBox', { minChars: 1, triggerAction: 'query', store: { fields: ['text'], proxy: { type: 'ajax', url: 'snooker-balls.json' } } });
到目前为止一切看起来都挺好的。下面我们简单的使用前一章中学过的配置信息来配置这个例子。emptyText,hideTrigger,typeahead
Ext.create('Ext.form.field.ComboBox', { emptyText: 'Colour', hideTrigger: true, minChars: 1, triggerAction: 'query', typeAhead: true, store: { fields: ['text'], proxy: { type: 'ajax', url: 'snooker-balls.json' } } });
五:分页
即使使用远程过滤的方式。数据还是有可能因为过于庞大而不能一次显示所有的可选选项。有时候我们有充分的理由只去显示少量的满足条件的数据。但是在其他的情况下提供一个分页的操作是更加明智的选择。
store上最常用的配置选项就是一些最最基本的ExtJs的分页配置信息。这个combobox被配置的宽度width为260.这是为了给分页的工具条提供空间。这里有两个pagesize的配置选项,一个在store中另一个在combobox当中。两个都是必须的,但是在combobox里面的那个做了一些额外的事情,它告诉combobox去展现一个分页的工具条。设置它为true跟将他设置为具体的数值都是一个效果。
Ext.create('Ext.form.field.ComboBox', { minChars: 0, pageSize: true, // This just causes a paging toolbar to show triggerAction: 'query', width: 260, store: { fields: ['text'], pageSize: 5, proxy: { type: 'ajax', url: 'css-colors.json', reader: { root: 'data', // Must match the property in the JSON response type: 'json' } } } });
根据上面的配置信息一个典型的请求大概会是这个样子
css-colors.json?query=b&page=1&start=0&limit=5&...
limit就是page size,start需要显示的页面的第一条数据的索引值从0开始page指的是页号。从1开始。在请求数据中存在一些冗余的信息。
服务器强制完负责分页的功能。如果服务器返回的数据超过五个,他们就会全部的被显示到列表当中。
JSON的返回数据大概就是这个样子: { "total": 8, "data": [ {"text": "Beige"}, {"text": "Bisque"}, {"text": "Black"}, {"text": "BlanchedAlmond"}, {"text": "Blue"} ] }
total的值指明store中有8个结果满足查询然而却只有5个被返回了。对于page size只有5,所以被解析成了两页。
六:明确的建立store,重复访问
在本文刚刚开始的时候。我们看到了怎么把内置的数据转移到一个store当中。让我们再回顾一下前面提到的例子。
Ext.create('Ext.form.field.ComboBox', { store: { fields: ['text'], data: [ {text: 'Red'}, {text: 'Yellow'}, {text: 'Green'}, ... ] } });
很明显这个例子表现的不正确。下拉列表直到第四个字符被输入才显示出来。而且即使他出现了,它也没有被过滤。这个问题我们前面曾经遇到过,当我们使用combobox的queryMode:‘remote’配置选项的时候。
这就能解释为什么过滤的操作会失败了。简而言之当数据在本地的时候使用远程过滤的方式是没有任何的意义的。下一段就尝试这对此进行更加深入的阐述。但是这会需要对ExtJs的数据包的知识有一些了解。
设置queryMode为remote就能防止其本身对数据进行过滤。代替的是,它仅仅告诉store去加载和传递相关的已经被过滤的选项。store并不直接加载数据,而是传递这些选项到proxy当中去。对于一个使用本地数据的store,proxy对象是被隐含建立的。而且是一个包装到数据对象之上的memory proxymemory proxy是相当的纯天然,他总会返回数据集合当中的所有值。它甚至都不能理解分页操作是个怎么回事。
更别说是过滤操作了。因此,当用户进行输入的时候combobox会一直请求store加载数据但是这也没什么分别,因为proxy总会返回所有的数据。
下面的例子中我们需要将我们的例子中使用queryMode;'local'
Ext.create('Ext.form.field.ComboBox', { queryMode: 'local', store: { fields: ['text'], data: [ {text: 'Red'}, {text: 'Yellow'}, {text: 'Green'}, ... ] } });
但是这又带来了其他的一些问题,为什么在使用本地数据的时候就不需要设置queryMode了呢?问题的答案其实很俗,当我们指定内联数据的时候combobox会自动的转变queryMode为local。
七:在不同的combobox之间分享store
一个UI界面经常有好几个combobox使用同一个数据集合,在不同的combobox当中分享store是非常的具有吸引力的。但是这也会带来许许多多的问题。下面的例子就分享了同一个store对象。其中的数据被存放在本地。一开始两个combobox工作的相当好。但是如果多进行一会儿操作的话。就会发现在两个combobox当中的下拉列表被泄露了。(you'll find that the filtering of the drop-downs leaks between the two comboboxes.)一个需要知晓的关键点是,过滤的操作被应用于store而不是combobox因此分享一个store仍然会分享同一个过滤方法。分享store只有在列表不被过滤的情况下才能正确工作。比如当设置editable:false。