3

I am using MVC 4 + EF 4.1 with jqgrid. I am new with HTML & Javascript and I am trying without success opening a custom edit jquery dialog inside jqgrid. If you have better methods to implement my desired behaviour, they would be welcome.

I have the following jquery dialog script, attached to the class='openDialog', which already works fine for other purposes:

  $.ajaxSetup({ cache: false });

$(document).ready(function () {
    $(".openDialog").live("click", function (e) {
        e.preventDefault();

        $("<div></div>")
            .addClass("dialog")
            .attr("id", $(this).attr("data-dialog-id"))
            .appendTo("body")
            .dialog({
                height: $(this).attr("data-dialog-alt"),
                width: $(this).attr("data-dialog-larg"),
                autoResize: $(this).attr("data-dialog-autosize"),
                position: 'top',
                title: $(this).attr("data-dialog-title"),
                close: function () { $(this).remove() },
                modal: true,
                buttons: { "Ok": function () { $(this).dialog("close"); } }
            })
            .load(this.href);
    });

    $(".close").live("click", function (e) {
        e.preventDefault();
        $(this).closest(".dialog").dialog("close");
    });
});

This is what I'm trying to do. This is just a test with double click event, if it works I will put the code inside a specific button.

jqgrid

    ..........
    { name: 'act', index: 'act', width: 75, sortable: false, search: false }
        ],
        ondblClickRow: function (id) {
            if (id != null) {
               // here I would like to launch the open dialog with a similar code: 
               // "<a class='openDialog' data-dialog-id='myEditDlg' data-dialog-autosize='false' data-dialog-alt='580' data-dialog-larg='740' data-dialog-title='test dialog' href='/mycontroller/EditDlg/myid'>test</a>"
            }
        },
        pager: '#jqpager',
       ....

MORE DETAILS

Basically, now I am using a custom formatter, where I put a button styled anchor for each button/action I need; for example:

         .....
         gridComplete: function () {
            applyZebra("mygrid");
            var ids = grid.jqGrid('getDataIDs');
            var rows = grid.jqGrid('getRowData');
            for (var i = 0; i < ids.length; i++) {

                var row = rows[i];
                var t = row['myrow'];
                var cl = ids[i];

                tst = '<a class="mybuttonclass openDialog" data-dialog-id="tckDetDlg" data-dialog-autosize="false" data-dialog-alt="580" data-dialog-larg="740" data-dialog-title="test dialog" href="/mycontrolller/testDlg/' + t + '"></a>';

                $("#jqTicketgrid").jqGrid('setRowData', ids[i], { act: tst });
            }
        },
        .....

Where mybuttonclass styles the anchors like a button...

Thank you very much for your help! Best Regards

tereško
  • 58,060
  • 25
  • 98
  • 150
Larry
  • 573
  • 5
  • 14
  • 31

1 Answers1

2

I am not sure that I understand correct your requirements. I would recommend you to use jQuery.jqGrid.dynamicLink.js which I described in the answer and which you can download from here or the last version from here (and download here). The usage of formatter: 'dynamicLink' is very easy and you can implement practically every link inside of jqGrid. You can use onClick callback which would create the dialog which you need.

One more remark to your code. On every click you create <div> which represent the dialog and place it in the <body> of the page. The close event only hide the div, but not remove it from the body. So the first problem: your page will be longer and longer on every click. The second problem is the possibility to get id duplicates which are not permitted in HTML and if you do add different elements with the same id you can have many very strange effects. So you should be very careful in the usage of data-dialog-id attribute from your current code.

UPDATED: I wanted to comment the code from gridComplete which you posted. It's not effective and you can use custom formatter to get more clear and effective code. You don't posted the full code of jqGrid which you use, but I suppose that you have at least two columns in the colModel: 'act' and 'myrow'. You cant to place in 'act' column the <a> elements having href which are constructed based on the value from the 'myrow' column.

What the current code do. 1) the grid will be build and placed on the page with empty 'act' column. Then inside of gridComplete you do the following: a) call getDataIDs which goes through the full grid and collect the ids from every row in the array ids. b) call getRowData which goes through the full grid and collect all data from all column in objects and place the objects in array rows. c) get the content of the 'myrow' column, construct <a> and place it in 'act' column *in every row of grid. You should additionally understand that changing of one element on the page follows the web browser have to recalculate the position of every element on the page.

So to improve the performance of the page you should first of all reduce the modifications of the elements on the page. The most effective way to rewrite the code and have the same results is to use custom formatter. In you case you can just include in 'act' from colModel an additional property:

{ name: 'act', index: 'act', width: 75, sortable: false, search: false,
    formatter: function (cellvalue, options, rowObject) {
        return '<a class="mybuttonclass openDialog" data-dialog-id="tckDetDlg" data-dialog-autosize="false" data-dialog-alt="580" data-dialog-larg="740" data-dialog-title="test dialog" href="/mycontrolller/testDlg/' +
            rowObject.myrow + '"></a>';
    }}

You should additionally verify that you use gridview: true option of jqGrid. The modified code will do the following. During constructing the HTML fragment of the body of the grid the full HTML fragment will be build as one string and will be placed to the HTML page in one operation. In the moment the web browser will recalculate position of other elements on the page and all will be done. So the code will be the same, it will be shorter, easy to read and it will work much more effective especially in case of many rows of the grid.

If you would use dynamicLink formatter which I suggested you before the code can be like the following:

{ name: 'act', index: 'act', width: 75, sortable: false, search: false,
    formatter: 'dynamicLink', formatoptions: {
        onClick: function (rowid, iRow, iCol, cellValue, e) {
            var myrow = $(this).jqGrid('getCell', rowid, 'myrow');
            $("<div>", {id: "tckDetDlg"})
                .addClass("dialog")
                .appendTo("body")
                .dialog({
                    height: 580,
                    width: 740,
                    autoResize: false,
                    position: 'top',
                    title: 'test dialog',
                    close: function () { $(this).remove() },
                    modal: true,
                    buttons: { "Ok": function () { $(this).dialog("close"); } }
                })
                .load('/mycontrolller/testDlg/' + myrow);
        }
    }}

The above code will be clear to read and understand in my opinion. The code from onClick will be the same as with you could use inside of ondblClickRow. In both cases you need just know the rowid only. So you can place the code of onClick in a function instead of the usage of anonymous function and call the function in both cases:

// first define the callback function which we will use later
var myClickHandle = function (rowid) {
        var myrow = $(this).jqGrid('getCell', rowid, 'myrow');
        $("<div>", {id: "tckDetDlg"})
            .addClass("dialog")
            .appendTo("body")
            .dialog({
                height: 580,
                width: 740,
                autoResize: false,
                position: 'top',
                title: 'test dialog',
                close: function () { $(this).remove() },
                modal: true,
                buttons: { "Ok": function () { $(this).dialog("close"); } }
            })
            .load('/mycontrolller/testDlg/' + myrow);
    };

...
// define the grid
$("#jqTicketgrid").jqGrid({
    ...
    colModel: [
        ...
        { name: 'act', index: 'act', width: 75, sortable: false, search: false,
            formatter: 'dynamicLink', formatoptions: { onClick: myClickHandle } }
        ...
    ],
    ondblClickRow: function (rowid) {
        myClickHandle.call(this, rowid);
    }
Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thank you very much Oleg! I solved following the suggestions of [this](http://stackoverflow.com/q/9444243/1129461) other question I made. Basically, now I am using a custom formatter, where I put a button styled anchor for each button/action I need. About your remarks, may you tell me how to remove dynamic added code please? Moreover, could you take a look to [this](http://stackoverflow.com/q/9365031/1129461) question too, which is somewhat related to that kind of problems? Thank you very much! – Larry Feb 25 '12 at 14:44
  • 3
    @Larry: You are welcome! You can use [jQuery.remove](http://api.jquery.com/remove/) to remove and existing element from the page. All children will be also removed. For example you can use `$('#tckDetDlg').remove()` to remove old dialog with id="tckDetDlg". If no element with the id exists on the page the code do nothing. So you can include for example the line `$('#' + $(this).attr("data-dialog-id")).remove();` before `$("
    ")...`. [The answer](http://stackoverflow.com/q/9444243/1129461) works, but seems me not nice. Why you not just assign `window.location` to the new URL?
    – Oleg Feb 25 '12 at 15:15
  • 2
    @Larry: Because you wrote, that you are new in JavaScript I appended my answer with "UPDATED" part where I describe how you can rewrite your code to make it more readable and more effective from performance point of view. – Oleg Feb 25 '12 at 16:59
  • THX for your precious help, I am going to put the `$.remove` code, as you suggested. About the `window.location`, please could you tell me why do you think it could be not nice? Assigning `window.location` could not make some problem I cannot imagine, considering that I just want open a dialog, while the main `window.location` it is always the same, until the user does not navigate in the solution? THX – Larry Feb 25 '12 at 17:03
  • 1
    @Larry: I seem later that you use already `$(this).remove();` inside of `close` handle of dialog. The usage of `window.location` is very easy if you want to *go* to some URL. You need just assign the URL to `window.location` : `window.location = '/mycontrolller/testDlg/123';`. I think in the case which described in the question you do don't need that because use used URL only as parameter of `jQuery.load`. – Oleg Feb 25 '12 at 17:15
  • WOW!Thank you SO MUCH Oleg! You are always so accurate and center the problem! It is perfect and have taught me many things,making me understand the various hor...errors.Just a clarification pls (for the rest I will exactly follow your valuable advice):regarding the `act` column,for simplicity I did not specified I have to put **more than one button for each row**.In this case I would be able to use the `onclick` event,or will I leave all in the custom formatter? To use click handlers could I create a column for each action but display them all together inside a single one, for example? THX! – Larry Feb 25 '12 at 17:19
  • 2
    @Larry: "Yes, you can" will be the answer on all your questions I think. It's better if you post more full code which you use. At least two columns like 'act'. You can place many links inside of one cell (column) if you need. You can also use ` – Oleg Feb 25 '12 at 17:26