Welcome Guest, Not a member yet? Register   Sign In
Flexigrid - Lightweight but rich data grid

[eluser]koriolis[/eluser]
Hi guys,

To whoever needs it here's 3 simple plugins that I built for myself but can be also useful to anyone. The code probably is not so elegant, but it gets the job done.

Note that if you have 2 flexigrids on screen (as I have) and use pagination, when you delete one row from a table, for some weird reason, the other grid's item display gets updated, sometimes with strange results. I'm not sure is it's my DeleteRows plugin that is firing some event, something in my other pieces of code that is messing it, or even if it's something on Paulo's code doing it, but I'm sure some helpful soul will enlighten me if at all possible.

Here's the code:

Get selected rows
Code:
$.fn.flexGetSelectedRows = function()
{
    if($(this).get(0).grid) return $('tbody tr.trSelected',$(this).get(0).grid.bDiv);
  
};//end flexGetSelectRows

Unselect All Rows
Code:
$.fn.flexUnselectAll = function()
{
    if($(this).get(0).grid) $('tbody tr.trSelected',$(this).get(0).grid.bDiv).removeClass("trSelected");
        
};//end flexUnselectAll

Delete Selected Rows
Code:
$.fn.deleteSelectedRows = function(){
        
    var obj = $(this).get(0);
    var grid = obj.grid;
    var params = obj.p;
    var colModel = params.colModel;
    var colData = params.colData;
        
    //Get Select Rows
    var rows = $(this).flexGetSelectedRows();
        
    if (rows.length > 0) {            
            
        var ids = new Array();
            
        //Get Selected Row Ids
        rows.each(function(){
            ids.push(parseInt($(this).attr("id").split("row").join("")));
        });
                                    
        //Remove rows with selected ids from ColData
        var temp = new Array();
        $.each(colData.rows,function(idx){
            if(($.inArray(this.id,ids)<0)) temp.push(colData.rows[idx]);
        });
        colData.rows = temp;            
                        
        //Update total and rp props @ colData
        colData.total = colData.rows.length;
        colData.rp = colData.total;
            
        //Pass data to the grid API
        $.extend(params,{dataType:'json',colData: colData});
    
        //Reload grid
        grid.addData(params.colData);
    }
}//end flexUnselectAll

[eluser]skaimauve[/eluser]
First of all, thanks Paulo for sharing Flexigrid! A contribution to your coffee fund is on the way!

I came across the following bug: if the ajax call fails, the spinner keeps going and flexigrid gets disabled.

It looks like $.ajax is missing an error callback function. It's quite common in jQuery when you move from $.post to $.ajax to only supply a success callback because you are used to see the $.post callback triggered whether or not you get an error.

In Flexigrid, the addData callback is quite able to handle errors, but it is never called when an error occurs. The solution is simple, just attach it to the error callback.

The following code makes it clear. Replace:
Code:
$.ajax({
                   type: p.method,
                   url: p.url,
                   data: param,
                   dataType: p.dataType,
                   success: function(data){g.addData(data);}
                 });
With:
Code:
$.ajax({
                   type: p.method,
                   url: p.url,
                   data: param,
                   dataType: p.dataType,
                   success: function(data){g.addData(data);},
                   error: function(){g.addData();}
                 });

This allows you to set a global timer for your ajax calls. For example, to make Flexigrid "move-on" after waiting for 3 seconds for an answer to a call, just add to your $(document).ready function:
Code:
$.ajaxSetup({timeout:3000});

[eluser]mrpaul[/eluser]
[quote author="mrpaul" date="1215343843"]And one more thing.

When I use onSuccess to call a function called tips which is basically just an alert box for testing, and reload the grid after making changes to a form, the alert is displayed as many times as the grid is reloaded. Is there anyway to make it just call the function once and stop after reloading?


Thanks.[/quote]

OK I got this fixed using Live Query.

Now I need to figure out how to append new rows to the tbody instead of getting rid of the existing rows and showing new ones. Basically instead of having a "Next Page" button, I need to make it "Add More." I dont know if I'm making sense.

I love the Flexigrid and the power of jQuery. Paulo, thanks to you, I picked up a new favorite. Btw, I love your name.

[eluser]skaimauve[/eluser]
Here is a mod to allow button click events to receive the button object and the flexigrid object.

Currently, this does not work:
Code:
function button_click(name,grid) {
    $(name).css({property:value});
    $(grid).flexOptions({option:value})
}

And you had to use something like this:

Code:
function button_click(name,grid) {
    $('#button_id').css({property:value});
    $('#grid_id').flexOptions({option:value})
}

Which ties-up the button onpress function to a specific table, not very practical on a page with several tables.

The reason lies in the code:

Code:
$(btnDiv).click
                            (    
                                function ()
                                {
                                this.onpress(this.name,g.gDiv);
                                }
                            );

which sends only the b.name and the g.gDiv to the function, but if you cange it to:

Code:
$(btnDiv).click
                            (    
                                function ()
                                {
                                this.onpress(this,t);
                                }
                            );

With this, the first example above works, and you can call any Flexigrid method (like paging), without having to specify the div, and without having to resort to all kind of branching logic based on b.name. You can still get the same info as before, using somehting like this:

Code:
function button_click(button,flex) {
    name = button.name;
}

[eluser]skaimauve[/eluser]
There is an issue involving resizing columns: initially, the resize indicator is positioned vertically outside of the grid.

This happens because the function g.rePosDrag() is called during initialization before the title is added (you'll find it just before the "//add strip" comment):

Code:
);
                        }
                    }
            );
        
        g.rePosDrag();
                            
        }
        

        //add strip        
        if (p.striped)
            $('tbody tr:odd',g.bDiv).addClass('erow');

Cut it and paste it at the end, right before the "//make grid functions accessible" comment:

Code:
// THIS MUST BE LAST
        g.rePosDrag();

        //make grid functions accessible
        t.p = p;
        t.grid = g;

[eluser]condev2008[/eluser]
skaimauve: Thanks for all the additional info and tweaks!

About the "g.rePosDrag" call move:
actually moving the call to the end of flexigrid makes it redundant in case autoload is active.
"populate -> addData" will call it, too.
My suggestion would be to move it to an ELSE branch of the "load data" block a few lines below where you suggested it:
Code:
// load data
    if (p.url && p.autoload)
    {
        g.populate();
    }
    else if (cdcol != null)
    {
        g.rePosDrag();
    }
The initial column header sizing works fine for me in IE7 and FF3 (jQuery 1.2.6), but Safari 3.1 doesn't (all on WinXP) and I havent found a solution to this yet. Sad
EDIT: never mind, column resizing issue was a problem with the column widths having a "px" - which didn't work, i.e. now just use integer value for width.

Thanks,
Tobias

[eluser]skaimauve[/eluser]
condev2008: Thanks! I've made the change.

Another issue: when the table is initialized inside a hidden div, you can't drag the table when it is showed, and if a load error occured while the table was hidden, the table is not dimmed.


This is because the initialization process needs to peek at the position and size of DOM elements such as hDiv in other to define the size and the position of the cDrag and block elements. But when Flexigrid is hidden, some the properties of its DOM are zeroed by the browser.

For example, in the rePosDrag routine, the hDiv.offsetTop is set to 0 when Flexigrid is placed inside a hidden element, and the top of g.cDrag is initialized to 1:

Code:
rePosDrag: function () {

            var cdleft = 0 - this.hDiv.scrollLeft;
            if (this.hDiv.scrollLeft>0) cdleft -= Math.floor(p.cgwidth/2);
            $(g.cDrag).css({top:g.hDiv.offsetTop+1});
            [..]
            },

Same with the fixHeight routine, both bDiv.height and hDiv.height are 0 when Flexigrid is placed inside a hidden element, and all the cDrag get initialized with a zero height.

Code:
fixHeight: function (newH) {
                
                    if (!newH) newH = $(g.bDiv).height();
                    var hdHeight = $(this.hDiv).height();
                    $('div',this.cDrag).each(
                        function ()
                            {
                                $(this).height(newH+hdHeight);
                            }
                    );
                    [...]
            },

The easiest way I found to solve this issue is to attach the following flexShow routine to the onShow callback of the procedure responsible of showing the Flexigrid:

Code:
$.fn.flexShow = function(){
    return this.each(function() {
        if (this.grid) {
            this.grid.fixHeight();
            this.grid.rePosDrag();
        }
    });
}

For example, if you are using the jQuery.tabs pluging, you can initialize it with:

Code:
$('#content').tabs({
     onShow:function(t,s,h){
          $('.flexigrid .bDiv table',s).flexShow();
    }
});

[eluser]skaimauve[/eluser]
We really need a repository and a bug tracker for Flexigrid... but meanwhile I'll keep posting as some might need this!


Some people have requested a "one row per click" behaviour, and many solutions have been posted. Here is one very simple implementation that preserve the shift-click.

It is tricky to understand because both mousedown and click are called then a row gets clicked. The changes involved are:
1. if the row is clicked without a shift, then deselect all
AND THEN
2. if the row is clicked without a shift, then toggle the row

So change this:

Code:
addRowProp: function()
{
        $('tbody tr',g.bDiv).each
        (
            function ()
                {
                $(this)
                .click(
                    function (e)
                        {
                            var obj = (e.target || e.srcElement); if (obj.href || obj.type) return true; //enable default behaviour for links and form elements
                            $(this).toggleClass('trSelected');
                        }
                )
                .mousedown(
                    function (e)
                        {
                            if (e.shiftKey)
                            {
                            $(this).toggleClass('trSelected');
                            g.multisel = true;
                            this.focus();
                            $(g.gDiv).noSelect();
                            }
                        }
                )

with this:

Code:
addRowProp: function()
{
        $('tbody tr',g.bDiv).each
        (
            function ()
                {
                $(this)
                .click( // this is called second
                    function (e)
                        {
                            var obj = (e.target || e.srcElement); if (obj.href || obj.type) return true; //enable default behaviour for links and form elements
                            if (!e.shiftKey)
                            {
                            $(this).toggleClass('trSelected'); // flip the switch only if no shift, cause mousedown took care of us
                            }
                        }
                )
                .mousedown( // this is called first
                    function (e)
                        {
                            if (e.shiftKey)
                            { // this is shit-click and shit-drag
                            $(this).toggleClass('trSelected');
                            g.multisel = true;
                            this.focus();
                            $(g.gDiv).noSelect();
                            } else { // no shift, then clear
                            $(this).siblings('.trSelected').removeClass('trSelected');    
                            }
                        }
                )

[eluser]JUANITO26[/eluser]
somebody knows as it is possible to be made several fields search? to see example
http://www.solured.es/5/prueba.jpg
Mucha Gracias Amigos.

[eluser]paulopmx[/eluser]
Updates:

Hi guys, new release 1.0b3 on the website, some of your concerns where answered (like the often requested single row select, some where not.

Another great news!

I've been invited to join the jQuery UI core team and create a jQuery UI version of my grid. This will allow me to accelerate development be leveraging the expertise of the other members of the jQuery UI core team.

Paulo




Theme © iAndrew 2016 - Forum software by © MyBB