3 * Copyright(c) 2008-2011 Alan Knowles
10 * @class Roo.form.ComboNested
11 * @extends Roo.form.ComboBox
12 * A combobox for that allows selection of nested items in a list,
27 * Create a new ComboNested
28 * @param {Object} config Configuration options
30 Roo.form.ComboNested = function(config){
31 Roo.form.ComboCheck.superclass.constructor.call(this, config);
32 // should verify some data...
34 // hiddenName = required..
35 // displayField = required
36 // valudField == required
37 var req= [ 'hiddenName', 'displayField', 'valueField' ];
39 Roo.each(req, function(e) {
40 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
41 throw "Roo.form.ComboNested : missing value for: " + e;
48 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
51 list : null, // the outermost div..
52 innerLists : null, // the
56 onRender : function(ct, position)
58 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
61 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
63 this.hiddenField.value =
64 this.hiddenValue !== undefined ? this.hiddenValue :
65 this.value !== undefined ? this.value : '';
67 // prevent input submission
68 this.el.dom.removeAttribute('name');
74 this.el.dom.setAttribute('autocomplete', 'off');
77 var cls = 'x-combo-list';
79 this.list = new Roo.Layer({
80 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
83 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
84 this.list.setWidth(lw);
85 this.list.swallowEvent('mousewheel');
89 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
90 this.assetHeight += this.header.getHeight();
95 for (var i =0 ; i < 3; i++) {
96 this.onRenderList( cls, i);
99 // always needs footer, as we are going to have an 'OK' button.
100 this.footer = this.list.createChild({cls:cls+'-ft'});
101 this.pageTb = new Roo.Toolbar(this.footer);
112 if ( this.allowBlank && !this.disableClear) {
114 this.pageTb.add(new Roo.Toolbar.Fill(), {
115 cls: 'x-btn-icon x-btn-clear',
121 _this.onSelect(false, -1);
126 this.assetHeight += this.footer.getHeight();
130 onRenderList : function ( cls, i)
134 ((this.listWidth * 3 || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / 3
137 this.list.setWidth(lw); // default to '1'
139 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
140 //il.on('mouseover', this.onViewOver, this, { list: i });
141 //il.on('mousemove', this.onViewMove, this, { list: i });
143 il.setStyle({ 'overflow-x' : 'hidden'});
146 this.tpl = new Roo.Template({
147 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
148 isEmpty: function (value, allValues) {
149 var dl = typeof(value.data) != 'undefined' ? value.data.total : value.length; ///json is a nested response..
150 return dl ? 'has-children' : 'no-children'
155 var store = this.store;
157 store = new Roo.data.SimpleStore({
158 //fields : this.store.reader.meta.fields,
159 reader : this.store.reader,
163 this.stores[i] = store;
167 var view = this.views[i] = new Roo.View(
173 selectedClass: this.selectedClass
176 view.getEl().setWidth(lw);
177 view.getEl().setStyle({
178 position: i < 1 ? 'relative' : 'absolute',
180 left: (i * lw ) + 'px',
181 display : i > 0 ? 'none' : 'block'
183 view.on('selectionchange', this.onSelectChange, this, {list : i });
184 view.on('dblclick', this.onDoubleClick, this, {list : i });
185 //view.on('click', this.onViewClick, this, { list : i });
187 store.on('beforeload', this.onBeforeLoad, this);
188 store.on('load', this.onLoad, this, { list : i});
189 store.on('loadexception', this.onLoadException, this);
191 // hide the other vies..
196 onResize : function() {},
198 restrictHeight : function()
201 Roo.each(this.innerLists, function(il,i) {
202 var el = this.views[i].getEl();
203 el.dom.style.height = '';
205 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
206 // only adjust heights on other ones..
209 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
210 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
211 mh = Math.max(el.getHeight(), mh);
217 this.list.beginUpdate();
218 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
219 this.list.alignTo(this.el, this.listAlign);
220 this.list.endUpdate();
225 // -- store handlers..
227 onBeforeLoad : function()
232 this.innerLists[0].update(this.loadingText ?
233 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
234 this.restrictHeight();
235 this.selectedIndex = -1;
238 onLoad : function(a,b,c,d)
245 if(this.store.getCount() > 0) {
247 this.restrictHeight();
249 this.onEmptyResults();
252 this.stores[1].loadData([]);
253 this.stores[2].loadData([]);
262 onLoadException : function()
265 Roo.log(this.store.reader.jsonData);
266 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
267 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
275 onSelectChange : function (view, sels, opts )
277 var ix = view.getSelectedIndexes();
282 this.setFromData(ix.length ? view.store.getAt(ix[0]).data : {});
287 this.setFromData({});
288 this.stores[opts.list+1].loadData( [] );
292 var rec = view.store.getAt(ix[0]);
293 this.setFromData(rec.data);
296 ((this.listWidth * 3 || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / 3
298 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
299 var dl = typeof(data.data.cn) != 'undefined' ? data.data.total : data.length; ///json is a nested response..
300 this.stores[opts.list+1].loadData( data );
301 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
302 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
303 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
304 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
306 onDoubleClick : function()
308 this.collapse(); //??
313 findRecord : function (prop,value)
315 return this.findRecordInStore(this.store, prop,value);
319 findRecordInStore : function(store, prop, value)
321 var cstore = new Roo.data.SimpleStore({
322 //fields : this.store.reader.meta.fields, // we need array reader.. for
323 reader : this.store.reader,
328 if(store.getCount() > 0){
329 store.each(function(r){
330 if(r.data[prop] == value){
334 if (r.data.cn && r.data.cn.length) {
335 cstore.loadData( r.data.cn);
336 var cret = _this.findRecordInStore(cstore, prop, value);
337 if (cret !== false) {