1. #1
    Ext Premium Member
    Join Date
    Mar 2007
    Posts
    175
    Vote Rating
    0
    SteveEisner is on a distinguished road

      0  

    Default Dynamic grid columns?

    Dynamic grid columns?


    Hi, two quick questions:

    1) Is it possible to set up a grid so that its columns are based on the contents of the records you pass it? In other words, if the records are {X:1,Y:2} the columns will be X and Y.

    2) Is it possible to configure the "start" and "limit" parameters to change them to "startIndex" and "endIndex" (or does limit = "length"?)

  2. #2
    Sencha Premium Member
    Join Date
    Mar 2007
    Posts
    171
    Vote Rating
    1
    mike1993 is on a distinguished road

      0  

    Default


    I started using yui-ext recently and I am facing the very same problems.
    dynamic grid and paging params names (they are clashing w/ current code I have in place).

    and one more question:
    How can I force "auto-size" for cell content w/o specifying its 'width'?
    " 123 " vs "123"

    Thanks!

  3. #3
    Ext JS Premium Member
    Join Date
    Mar 2007
    Location
    Virginia, USA
    Posts
    220
    Vote Rating
    0
    dfenwick will become famous soon enough

      0  

    Default Re: Dynamic grid columns?

    Re: Dynamic grid columns?


    Quote Originally Posted by SteveEisner
    Hi, two quick questions:

    1) Is it possible to set up a grid so that its columns are based on the contents of the records you pass it? In other words, if the records are {X:1,Y:2} the columns will be X and Y.

    2) Is it possible to configure the "start" and "limit" parameters to change them to "startIndex" and "endIndex" (or does limit = "length"?)
    I don't think so, and for many reasons. One reason is that the data model provides a set of data that you can then provide a view of. The column model is that view. The column model says "With these 12 data elements returned per row, which ones do I want to display in my viewport and which ones are there for support purposes?"

    There's nothing preventing you from flattening the view to match the data source though. You could just write a mini adapter that goes out and discovers your column model and dynamically creates it for your grid.

  4. #4
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,505
    Vote Rating
    52
    Animal has a spectacular aura about Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    Well, if you fist find out what the records are going to contain, you can create an appropriate ColumnModel programatically by simply assembling a column config Array.

    My wrapper of the Grid sends an encoded query to the server, receives back info about the columns, builds the ColumnModel and Record definition on the fly from this recieved info, creates the Grid and loads it.

    I only have one Grid class which will handle all my possible queries.

  5. #5
    Sencha User genius551v's Avatar
    Join Date
    Mar 2007
    Posts
    287
    Vote Rating
    0
    genius551v is on a distinguished road

      0  

    Default t puede dar una pista

    t puede dar una pista


    esta grilla se construye onfly vacia y se re-construyen tambien onfly con datos del # de columnas despues de una consulta del numero de elementos

    Code:
    grid_editor_modelo_medidas = function(){
        var myData;
        var dataModel;
        var colModel;
        var sm;
        var grid;
        var contenedor = 'editor-grid-modelo-medidas-confeccion';
    
        var responseText;
    
        return {
            init : function(){
                responseText = '';
    
                myData = [];
                dataModel = new YAHOO.ext.grid.DefaultDataModel(myData);
                colModel = new YAHOO.ext.grid.DefaultColumnModel([
                    {header: "id_caracteristica", width: 30, hidden: true},
                    {header: "id_stcaracteristica", width: 30, hidden: true},
        			{header: "Subtipo Caracteristica", width: 200},
        			{header: "Tallas de la Familia", width: 464}
        		]);
        		//sm = new YAHOO.ext.grid.EditorAndSelectionModel();
                grid = new YAHOO.ext.grid.Grid(contenedor,dataModel,colModel/*,sm*/);
                grid.render();
            },
    
            reRenderGrid : function(id_fam_talla){
                //tstart = new Date().getTime();
                var cb = {success: function(o){
                                               responseText = o.responseText;
    
                                               var vec_tallas = responseText.split(',');
    
                                               var myColumns = new Array();
                                               myColumns[0] = new Objeto('id_caracteristica',30,true);
                                               myColumns[1] = new Objeto('id_stcaracteristica',30,true);
                                               myColumns[2] = new Objeto('Subtipo Caracteristica',200,false);
                                               myColumns[3] = new Objeto('Margen (+/-)',70,false,'NumberEditor');
    
                                               var c=4;
                                               for(var i=0; i<vec_tallas.length; i++){
                                                      myColumns[c] = new bjeto(vec_tallas[i],30,false,'NumberEditor');
                                                      c++;
                                               }
                                               grid.destroy();
    
                                               colModel = new YAHOO.ext.grid.DefaultColumnModel(myColumns);
    
                                               dataModel = new YAHOO.ext.grid.DefaultDataModel(myData);
    
                                               sm = new YAHOO.ext.grid.EditorAndSelectionModel();
    
                                               grid_editor_modelo_medidas.reFullgrid(); //convierte algunos datos de la grilla a 0
    
                                               grid = new YAHOO.ext.grid.Grid(contenedor,dataModel,colModel,sm);
    
                                               grid.render();
    
                                               //var tend = new Date().getTime();
                                               //alert('Rendered in: ' + ((tend-tstart)/1000) + ' seconds');
                                   },
                          failure: function(o){
                                               alert('Fail...'+o.responseText);
                                   }
                         };
                YAHOO.util.Connect.asyncRequest('POST','AjaxGetColumns.php',cb,'id_familia_talla='+id_fam_talla);
            },
    
            addrow : function(valor2,valor3,valor4){
                grid.stopEditing();
    
                var row = new Array();
    
                row[0] = valor2;
                row[1] = valor4;
                row[2] = valor3;
    
                if(responseText!=''){
                    row[3] = '0';
                    var vec_col = responseText.split(',');
                    var c=4;
                    for(var i=0; i<vec_col.length; i++){
                           row[c] = '0';
                           c++;
                    }
                }else{
                    row[3] = '<span style="color:red;">- Debe escoger para crear las columnas y poder adicionar datos a la grilla -</span>';
                }
                dataModel.addRow(row);
            },
    
            addData : function(id_fam_talla,cadData){
                //tstart = new Date().getTime();
    
                grid.stopEditing();
    
                myData = [];
    
                if(cadData){
                    var vec_medidas_mod = cadData.split('#');
    
                    for(var i=0; i<vec_medidas_mod.length; i++){
                        var vec_data_row = vec_medidas_mod[i].split(',');
    
                        var row1 = new Array();
    
                        var c1=0;
    
                        for(var j=0; j<vec_data_row.length; j++){
                                        row1[c1] = vec_data_row[j];
                                        c1++;
                        }
                        myData[i] = row1;
                    }
                }
    
                var cb = {success: function(o){
                                               responseText = o.responseText;
    
                                               var vec_tallas = responseText.split(',');
    
                                               var myColumns = new Array();
                                               myColumns[0] = new Objeto('id_caracteristica',30,true);
                                               myColumns[1] = new Objeto('id_stcaracteristica',30,true);
                                               myColumns[2] = new Objeto('Subtipo Caracteristica',200,false);
                                               myColumns[3] = new Objeto('Margen (+/-)',70,false,'NumberEditor');
    
                                               var c=4;
                                               for(var i=0; i<vec_tallas.length; i++){
                                                   myColumns[c] = new Objeto(vec_tallas[i],30,false,'NumberEditor');
                                                   c++;
                                               }
                                               grid.destroy(false,true);
    
                                               colModel = new YAHOO.ext.grid.DefaultColumnModel(myColumns);
    
                                               dataModel = new YAHOO.ext.grid.DefaultDataModel(myData);
    
                                               sm = new YAHOO.ext.grid.EditorAndSelectionModel();
    
                                               grid = new YAHOO.ext.grid.Grid(contenedor,dataModel,colModel,sm);
    
                                               grid.render();
    
                                               //var tend = new Date().getTime();
                                               //alert('Rendered in: ' + ((tend-tstart)/1000) + ' seconds');
                                   },
                          failure: function(o){
                                               alert('Fail...'+o.responseText);
                                   }
                         };
                YAHOO.util.Connect.asyncRequest('POST','domain/AjaxGetColumns.php',cb,'id_familia_talla='+id_fam_talla);
            },
    
            reFullgrid : function(){
                grid.stopEditing();
    
                var rows = dataModel.getRowCount();
    
                for(var i=0; i<rows; i++){
                    var row = dataModel.getRow(i);
                    row[3] = '0';
                    var vec_col = responseText.split(',');
                    var c=4;
                    for(var j=0; j<vec_col.length; j++){
                           row[c] = '0';
                           c++;
                    }
                }
            },
    
            savedm : function(){
                var rows = dataModel.getRowCount();
               	var col = colModel.getColumnCount();
               	var vec_tallas = responseText.split(',');
                var medidas_modelo = '';
                
                for(var i=0; i<rows; i++){
                    var row1 = dataModel.getRow(i);
                    var value = '';
                    
                    value = row1[0]+','+row1[1]+','+row1[2]+','+row1[3]+',';
                    
                    for(var j=4; j<col; j++){
                        value = value+row1[j];
    
                        if(j+1<col)
                           value=value+',';
                    }
                    if(i+1<rows)
                       value = value+'~';
                    medidas_modelo = medidas_modelo+value;
                }
                return medidas_modelo;
            }
        };
    }();
    
    function Objeto(header, width, hidden, editor)
    {
      this.header = header;
      this.width = width;
      this.hidden = hidden;
      if(editor){
         if(editor=='NumberEditor'){
            this.editor = new YAHOO.ext.grid.NumberEditor({allowBlank: false, blankText: 'Este campo no puede ser vacĂ­o!', allowNegative: false, allowDecimals: true});
         }
      }
    }
    YAHOO.ext.EventManager.onDocumentReady(grid_editor_modelo_medidas.init, grid_editor_modelo_medidas, true);
    con algunos cambios porque esta funcion yo la utilizo para crear 2 grillas iguales simultaneamente, espero t ayude en algo.

    recomendaciones y sugerencias

    ext 0.33

    tnks

  6. #6
    Ext Premium Member
    Join Date
    Mar 2007
    Posts
    175
    Vote Rating
    0
    SteveEisner is on a distinguished road

      0  

    Default


    I was looking through the code and it seems like this might also be done generically by:
    1) Creating a "DynamicColumnModel" that, after receiving a record, uses that record to respond to column queries [this would be hard to do for rich field types but could pretty easily build an all-string table]
    2) Creating a "DynamicRecord" that, in combination with a Reader, is able to store all the columns of the returned JSON.
    After that both the grid and the reader would have to be modified slightly to send the recordset to the columnmodel, but other than the difficult work of building those two classes, I think it wouldn't take much modification of the base code. I'll see if I can take this on.

    Other than that, dfenwick/Animal I agree your method for loading is a good one as long as you can make a schema query (unfortunately, we don't have a way to do that, because it's calling methods that return arbitrary data)

  7. #7
    Ext Premium Member
    Join Date
    Mar 2007
    Posts
    175
    Vote Rating
    0
    SteveEisner is on a distinguished road

      0  

    Default


    Here's what I came up with:

    Dynamic Json Reader: this will read whatever data comes back from the JSON call. It doesn't take a record definition because it builds it on the fly. Unfortunately it only has any record information *after* the JSON call has completed, so you can't simply pass it into a Grid, etc. because it won't be initialized at that time.

    Code:
    Ext.data.DynamicJsonReader = function(config){
        Ext.data.DynamicJsonReader.superclass.constructor.call(this, config, []);
    };
    Ext.extend(Ext.data.DynamicJsonReader, Ext.data.JsonReader, {
        getRecordType : function(data) {
            var i = 0, arr = [];
            for (var name in data[0]) { arr[i++] = name; } // is there a built-in to do this?
            
            this.recordType = Ext.data.Record.create(arr);
            return this.recordType;
            },
            
        readRecords : function(o){ // this is just the same as base class, with call to getRecordType injected
            this.jsonData = o;
            var s = this.meta;
        	var sid = s.id;
        	
        	var totalRecords = 0;
        	if(s.totalProperty){
                var v = parseInt(eval("o." + s.totalProperty), 10);
                if(!isNaN(v)){
                    totalRecords = v;
                }
            }
        	var root = s.root ? eval("o." + s.root) : o;
        	
        	var recordType = this.getRecordType(root);
        	var fields = recordType.prototype.fields;
        	
            var records = [];
    	    for(var i = 0; i < root.length; i++){
    		    var n = root[i];
    	        var values = {};
    	        var id = (n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
    	        for(var j = 0, jlen = fields.length; j < jlen; j++){
    	            var f = fields.items[j];
    	            var map = f.mapping || f.name;
    	            var v = n[map] !== undefined ? n[map] : f.defaultValue;
    	            v = f.convert(v);
    	            values[f.name] = v;
    	        }
    	        var record = new recordType(values, id);
    	        record.json = n;
    	        records[records.length] = record;
    	    }
    	    return {
    	        records : records,
    	        totalRecords : totalRecords || records.length
    	    };
        }
    });
    DynamicColumnModel: this takes a Store as a parameter, and from that it will build a default ColumnModel where all the fields are included and have width: 300.

    Code:
    Ext.grid.DynamicColumnModel = function(store){
        var cols = [];
        var recordType = store.recordType;
        var fields = recordType.prototype.fields;
        
        for (var i = 0; i < fields.keys.length; i++)
        {
            var fieldName = fields.keys[i];
            var field = recordType.getField(fieldName);
            cols[i] = {header: field.name, dataIndex: field.name, width:300};
        }
        Ext.grid.DynamicColumnModel.superclass.constructor.call(this, cols);
    };
    Ext.extend(Ext.grid.DynamicColumnModel, Ext.grid.ColumnModel, {});

    Here's how I use it -

    Code:
    function showGrid(container, url)
    {
        // create the Data Store
        var ds = new Ext.data.Store({
            proxy: new Ext.data.HttpProxy({url: url}),
            reader: new Ext.data.DynamicJsonReader({root: '...my root, yours will be different...'}),
            remoteSort: true
            });
        ds.on('load', function() {
            // Reset the Store's recordType
            ds.recordType = ds.reader.recordType;
            ds.fields = ds.recordType.prototype.fields;
    
            // Create the grid
            var grid = new Ext.grid.Grid(container, {
               ds: ds,
               cm: new Ext.grid.DynamicColumnModel(ds),
               selModel: new Ext.grid.RowSelectionModel({singleSelect:true}),
               enableColLock:true
            });
               
            // render it
            grid.render();
        });
        ds.load();
    }
    I haven't really put it through its paces yet but it seems to work for whatever JSON calls I try. If this were more generic I'd want to add some things like:
    * Some way to provide column widths and types for known columns - merge with the unknowns. Maybe a callback function of some sort.
    * A better way to declare this type of grid that has to wait until the data has been fetched before rendering.
    * A DynamicXmlReader to match the JSON reader
    * etc.

    Note if Jack reads this: the DynamicJsonReader code could be even smaller if you adopt the change I made to the readRecords() method...

    Steve

  8. #8
    Sencha Premium Member
    Join Date
    Mar 2007
    Posts
    171
    Vote Rating
    1
    mike1993 is on a distinguished road

      0  

    Default


    Thanks guys!

  9. #9
    Ext User Mohammed's Avatar
    Join Date
    Mar 2007
    Location
    Brisbane, Qld, Australia
    Posts
    34
    Vote Rating
    0
    Mohammed is on a distinguished road

      0  

    Default dreaming for dynamic grid...

    dreaming for dynamic grid...


    plz... Steve,

    if you can provide some sample or atleast js and html code...it will help a lot for new bees....dreaming for dynamic grid...

  10. #10
    Ext Premium Member staticboy's Avatar
    Join Date
    Aug 2007
    Posts
    19
    Vote Rating
    0
    staticboy is on a distinguished road

      0  

    Talking


    SteveEisner, I love you!

    Well, maybe not love, but an extreme amount of respect and appreciation for your DynamicJsonReader extension. It's solved so many of my problems! I've been trying to find a way to get a handle on a number of dynamic paragraph elements that are returned as part of the response to retrieve a news article. Here's a snippet of the JSON:

    JSON snippet
    PHP Code:

        
    "tailParagraphs": {
            
    "paragraph": [
                
    "The company also hopes its [...] organizations.",
                
    "Oracle is a proponent of [...] SaaS.",
                
    "Phillips foresees gradations [...] and SaaS.",
                
    "\"We have been doing [...] said Phillips.",
                
    "Conventionally, SaaS [...] multi tenant."
            
    ]
        }, 
    My problem was that the number of elements in the paragraph array is variable (as you might expect for a news article) and I couldn't find a way to setup a Record to handle this (I tried stuff with mapping: and convert:), but your DynamicJsonReader solves this problem perfectly.

    It even solved the other problem I had http://extjs.com/forum/showthread.php?p=54791#post54791. This concerns the problem the JsonReader has if the root isn't specified as an array when there is only one object, e.g., if there is only one news article. DynamicJsonReader handles this anomoly in the JSON I am having to work with.

    So, thank you once again, SteveEisner for sharing your work. I only hope I'll be able to eventually give as much back to these forums one day.

Similar Threads

  1. Max columns limitation in grid?
    By jarrod in forum Ext 1.x: Bugs
    Replies: 9
    Last Post: 26 Jun 2010, 4:52 AM
  2. Dynamic Columns for Grid
    By kinky_lizzard in forum Ext 1.x: Help & Discussion
    Replies: 7
    Last Post: 24 May 2010, 11:20 PM
  3. Grid - Double Header Columns
    By FuryVII in forum Ext 2.x: Help & Discussion
    Replies: 0
    Last Post: 23 Feb 2007, 7:21 AM
  4. Nested Grid Columns
    By dlibby00 in forum Community Discussion
    Replies: 4
    Last Post: 29 Jan 2007, 9:53 AM

Thread Participants: 30