3

Free jqgrid contains button in each row. Clicking in button makes ajax call which returns customer list based on clicked row column value.

User can select customer from this data. Selected customer name and id should written to jqgrid row.

I tried code below but I got:

Uncaught TypeError: Cannot read property 'rowIndex' of undefined

This error happens on this line of code:

var clickedId = $(this).closest('tr')[0].rowIndex,

when clicked in any place in selection form.

How to fix this ? Application contains number of such selects from different data. Which is best way to implement them to avoid code repetition?

Table is created in javascript. Is it resonable/how to use some MVC partial view or other template for this?

Can this code improved/refactored?

Free jqgrid 4.13.3-pre, .NET 4.6, ASP.NET MVC, Bootstrap 3, jQuery, jQuery UI are used.

Selection form is copied from bootstrap modal sample:

<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            </div>
            <div class="modal-body">
                <table class='table table-hover table-striped'>
                    <thead>
                        <tr><td>Customer name</td><td>Customer Id</td></tr>
                    </thead>
                    <tbody></tbody>
                </table>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">close without selection</button>
            </div>
        </div>
    </div>
</div>

jqgrid colmodel:
    formatter: "showlink",
    formatoptions: {
        onClick: function (options) {
            var nimeosa = getColumnValue('customername', options.rowid);
            if (nimeosa == null) {
                return false;
            }
            $.ajax('api/Customers/FromRegister?' + $.param({ namepart: nimeosa }), {
                type: 'GET',
                dataType: 'json',
                contentType: "application/json",
                async: false
            }).done(function (data, textStatus, jqXHR) {
                var valik = "";
                for (var i = 0; i < data.customerlist.length; i++) {
                    valik += '<tr><td>' + data.customerlist[i].customerName + '</td><td>' +
                        data.customerlist[i].customerId + '</td></tr>';
                }
                $('#exampleModal').on('show.bs.modal', function (event) {
                    $('.modal-body tbody').html(valik);
                });

                $('#exampleModal').on('click.bs.modal', function (event) {
                    // how to fix Uncaught TypeError: Cannot read property 'rowIndex' of undefined in this line:
                    var clickedId = $(this).closest('tr')[0].rowIndex,                                    clickedElem = data.customerlist[clickedId];
                    $('#' + options.rowid + '_customername').val(clickedElem.customerName);
                    $('#' + options.rowid + '_customerid').val(clickedElem.customerId);
                });
                $('#exampleModal').modal();
            );
            return false;
        }
    }

// gets column value from jqgrid row
function getColumnValue(valjaNimi, rowId) {
    var
        iNimi = getColumnIndexByName($grid, valjaNimi),
        $nimi = $('#' + rowId + '>td:nth-child(' + (iNimi + 1) + ')'),
        nimiVal;

    if ($nimi.find('>input').length === 0) {
        // the cell is not in editing mode 
        nimiVal = $nimi.text();
    }
    else {
        nimiVal = $nimi.find('>input').val();
    }

    if (nimiVal === undefined || nimiVal.trim() === '') {
        alert('No value');
        return null;
    }
    return nimiVal;
}

Update

I tried code from answer. Rows are wider than bootstrap modal width. Wide rows become wider than form:

enter image description here

How to fix this ? How to force force rows to appear inside modal ? How to create scrollbar if there are more rows than fits to screen ?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Andrus
  • 26,339
  • 60
  • 204
  • 378
  • You have not shown the html, but `$(this).parent('tr')` gets the immediate parent of the button which would not be a `` element unless you had invalid html. You probably want `var clickedId = $(this).closest('tr')[0].rowIndex;` –  Aug 20 '16 at 07:14
  • I changed line to `var clickedId = $(this).closest('tr')[0].rowIndex` but same error still occurs. How to fix this ? html is generated in done method code in question. It contains simple tr elements. – Andrus Aug 20 '16 at 07:22
  • Its a bit hard to understand what the final html your generating is but `$(this)` is the parent element (your appear to be adding the row to the `` element within the ` –  Aug 20 '16 at 07:33
  • Using `$(this).find('tbody tr')[0].rowIndex` always selects second row in table if clicked in any place. How to select clicked row ? Maybe it is reasonable to add click handler for every tr element ? – Andrus Aug 20 '16 at 07:40
  • All your handling currently is a click event of the parent div. If you want to get the values from a specific row, then you would need to handle the click event of that row - e.g. `$('exampleModal tbody').on('click', 'tr', function() { var row = $(this); // returns the row you clicked });` and then `row.children('td').eq(0).text();` would return the `customerName` and `row.children('td').eq(1).text();` would return the `customerId` (I assume thats what your trying to get?) –  Aug 20 '16 at 07:46
  • Thank you very much. It worked. You can wrote this as answer. How to close selecion form after click ? – Andrus Aug 20 '16 at 07:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121407/discussion-between-stephen-muecke-and-andrus). –  Aug 20 '16 at 07:55

1 Answers1

1

In order to get the values of the customer from the rows, you need to handle the click event of the <tr> element, not its parent modal. Since the rows are dynamically added, you need to handle this using event delegation.

$('#exampleModal tbody').on('click', 'tr', function() {
    var cells = $(this).children('td');
    $('#' + options.rowid + '_customername').val(cells.eq(0).text());
    $('#' + options.rowid + '_customerid').val(cells.eq(1).text());
    $('exampleModal').hide(); // assuming you want to close the modal
});

Note the above should be a separate script, but its not clear what options.rowid is and if that can be stored in a global variable or passed to the modal so it can be accessed in the above function (see following suggestion)

As a side note, some of your functions seem unnecessary (you keep reattaching the same events each time) and I believe the code can be just

// declare rowID as a global var and then in the above script you can use
// $('#' + rowID + '_customername').val(cells.eq(0).text());
var rowID;
var table = $('#exampleModal tbody'); // cache it

....
onClick: function (options) {
    rowID = options.rowid; // set the row ID
    ....
    $.ajax('api/Customers/FromRegister?' + $.param({ namepart: nimeosa }), {
        type: 'GET',
        dataType: 'json',
        contentType: "application/json",
        async: false
    }).done(function (data, textStatus, jqXHR) {
        table.empty(); // clear any existing rows
        $.each(data, function(index, item) {
            var row = $('<tr></tr>');
            row.append($('<td></td>').text(item.customerName ));
            row.append($('<td></td>').text(item.customerId));
            table.append(row);
        });
        $('#exampleModal').modal(); // display the mpday
    );
    return false;
}
  • Thank you. Rows appear outside of bootstrap modal.How to fix this ? I updated question with this issue. – Andrus Aug 20 '16 at 18:03
  • Note edit to set the row ID. That would surely be a css issue. Unless you can produce a fiddle to reproduce it, its not really possible to help you with that –  Aug 20 '16 at 21:50
  • This adds two global variables `rowID` and `table`. Application has lot of js libraries and js code. Some library may also use variables with same names and so collision occurs. Why those variables are not defined in onClick method. Why they are global? – Andrus Aug 20 '16 at 22:25
  • It looks like bootstrap modal form width is defined when html page is created using thead element widths. If it is shown by $.ajax , its width is not changed. Is there some simpley way to force enable scrollbars or text wrap for content wider than modal window in Bootstrap modal ? – Andrus Aug 20 '16 at 22:43
  • You should be able to style that using css by setting the [overflow](https://developer.mozilla.org/en/docs/Web/CSS/overflow) property - e.g `overflow: scroll;` But you might need to play around with which element to apply that to (probably on ` –  Aug 20 '16 at 22:49
  • Adding `overflow: scroll` to ` – Andrus Aug 20 '16 at 23:02
  • Try adding a `max-height: ##px;` style (I don't use bootstrap modal so I'm not sure what the default styles are but I assume that should work) –  Aug 20 '16 at 23:11