mobile data entry - mobile friendly datagrid

2019-05-22 14:03发布

I have the following challenge in my hands. I need to redesign a desktop order entry web application to mobile using html5 and js. I am trying to find a proper way to do order entry, since mobile devices are quite different from desktop. I need to be able to add auto-complete and images into the data grid, that are optional.

Is there such a datagrid component available? Similar to http://datatables.net/release-datatables/examples/basic_init/multi_col_sort.html but more suitable for mobile devices.

Any tips, urls, or advice is highly appreciated.

4条回答
家丑人穷心不美
2楼-- · 2019-05-22 14:52

If you are just looking for a grid, then you can try both of these:

1140 css grid 960 css grid

Both help structure content in a responsive way.

I'm using 1140 quite a lot, because it goes well with Jquery Mobile. It uses classes container, row, span1-12, so you can structure your content in rows up to 12 cells. For example:

 <div.container></div>
    <div.row></div>
      <div.span1>A</div>
      <div.span5>B</div>
      <div.span5>C</div>
      <div.span1>D</div>
    </div>
 </div>

Which on tablet gives you:

 A   B   C   D

And on smartphone

 A
 B
 C
 D

You can mix this very well with JQM collapsibles, or collapsible sets, like so:

 <div class="container">
   <div data-role="collapsible" data-collapsed="true">
      <h3>headline</h3>
       <!-- start grid row --->
       <div class="row">
         <div class="span4"><!-- content --></div>
         <div class="span4"><!-- content --></div>
         <div class="span4"><!-- content --></div>
       </div<
    </div>
    <!-- end collapsible or start next on in set -->
  </div>

Regarding images on tablet and mobile, have a look at adaptive images.

EDIT:
Here is a link to my tableview plugin setup. This is an adaptive table which is enhanced by Jquery Mobile. Click top right at the filter to open a dialog to hide/show rows. Shrink the screen, the table should adapt. If this is what you are looking for, I could try to fiddle out a page I did from my project using tableview with datatables. However it only supports the stuff I need, so it's far from complete (especially the ui).

*========================= EDIT ========================= *
Ok. Here is a quick rundown how to setup datatables with Jquery Mobile.

1) You will need my modified datatables version. This version replaces all JqueryUI with JqueryMobile UI in datatables. So far I have only done the basic stuff I need, feel free to chip in :-)

Here is a link to the file: JQM datatables - search for "XXX" to see what I changed

2) I'm using the regular datatables function call like so:

tblPos = table.dataTable({
    "sDom": '<"S"f>t<"E"lpi>',        /* table layout */
    "bJQueryMobileUI": true,          /* JQM UI */
    "sPaginationType": "full_numbers",/* pagination type */
    "bPaginate": true,                /* pagination active */
    "bRetrieve": true,                /* hide warnings */
    "bCustomFilter":false,            /* use custom filter */
    "bLengthChange": true,            /* number of results */
    "bAutoWidth": false,              /* no auto-width */
    "aaSorting": [[ 0, "asc" ]],      /* default sorting col 0 desc */
    "aoColumns": [ 
        /* Pos */         {"sClass": "jqmSorter"},    /* sortable */
        /* EAN/GTIN */    {"bSortable": false },      /* not sortable */
        /* Style No */    {"sClass": "jqmSorter"},
        /* Desc. */       {"bSortable": false },
        /* Size */        {"bSortable": false },
        /* Color */       {"bSortable": false },
        /* Price */       {"bSortable": false },
        /* Unit */        {"bSortable": false },
        /* Qty */         {"bSortable": false },
        /* Confirmed */   {"bSortable": false },
        /* Total */       {"bSortable": false },
        ],
    "fnHeaderCallback": function( nHead ) {
        sortableHeaderCells( nHead )         /* embed sortable buttons */
        },
    "fnInitComplete": function(oSettings, json) {
        createJQMTable( oSettings, json )    /* run JQM make-over once table is built */
    }

This is from an example I'm using, so all of the used functions should be ok. Here are the fnHeaderCallback and fnInitComplete function, which create sortable headers, where you specificy and JQM the whole table:

function sortableHeaderCells ( nHead ) {
    $(nHead).closest('thead, THEAD').find('.jqmSorter').each( function () {
        var sortTitle = $(this).text(),
        sortButton = 
            $( document.createElement( "a" ) ).buttonMarkup({
                shadow: false,
                corners: false,
                theme: 'a',
                iconpos: "right",
                icon: 'sort'
                })
        sortButton.addClass("colHighTrigger")
            .find('.ui-btn-text').text(sortTitle);

        $(this).html( sortButton )
        });
    }       

This one is easy. If you label a table column as sortable, the function will create a JQM button out of it.

The next one, not so easy ...

function createJQMTable(oSettings, json) {

    $(oSettings.nTable).addClass("enhanced");

    /* toggle columns */
    var persist = "persist",
        thead = $(oSettings.nTHead),
        twrap = thead.closest('.table-wrapper'),
        topWrap = twrap.find('.table-top-wrapper'),
        idprefix = "co-" + twrap.jqmData('rpsv') + "-",
        togSel = $('#toggleCols_' + twrap.jqmData('rpsv')),
        bodyRows = $(oSettings.nTBody).find("tr, TR"),
        footRows = $(oSettings.nTFoot).find("tr, TR"),
        hdrCols = thead.find("tr:first th[rowspan=2], TR:first TH[rowspan=2]").add(thead.find("tr:last-child th, TR:last-child TH")),
        dropSel;

    /* remove top borders if nested table */
    if (thead.closest('.containsTable').length > 0) {
        $(".table-top-wrapper").removeClass('ui-corner-top');
        }

    /* fill remaining 2 slots */
    if (twrap.find(".slot1").length) {
        $(".slot1").prependTo(topWrap).addClass("ui-block-a noIconposSwitcher-div").find('label').addClass('hideLabel');
        }

    if (twrap.find(".slot2").length) {
        $(".slot2").prependTo(topWrap).addClass("ui-block-b noIconposSwitcher-div").find('label').addClass('hideLabel');
        }

    function sortHeaders(a, b) {
        var x = $(a).jqmData('sort');
        var y = $(b).jqmData('sort');

        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        }

    hdrCols.sort(sortHeaders).each(function (i) {

        var classes = "",
            th = $(this),
            id = th.attr("id"),
            allClasses = th.attr("class").split(/\s+/);

        // assign an id to each header, if none is in the markup
        if (!id) {
            id = (idprefix ? idprefix : "col-") + i;
            th.attr("id", id);
            };

        // retrieve toggle classes from header  
        for (var j = 0; j < allClasses.length; j++) {
            if (allClasses[j] === 'persist' || allClasses[j] === 'optional' || allClasses[j] === 'essential') {
                classes = classes + " " + allClasses[j]
                }
            if (classes == "") {
                $(this).addClass('only')
                }
        }

        // assign matching "headers" attributes to the associated cells          
        bodyRows.add(footRows).each(function () {
            var cell = $(this).find("th, td").eq(i);
            cell.attr("headers", id);
            if (classes) {
                cell.addClass(classes);
            } else cell.addClass('only');
            });

        // create the hide/show toggles
        if (!th.is("." + persist)) {
            var toggle = $('<option value="' + id + '">' + th.text() + '</option>');
            $(togSel).append(toggle);
            }

        // listen for column updates
        // $('body').one("updateCheck",$(toggle), function(){       
        $(toggle).bind("updateCheck", function () {
            th.css("display") == "table-cell" || th.css("display") == "inline" ? $(this).attr("selected", "selected") : $(this).removeAttr("selected");
            }).trigger("updateCheck");

    }); // end hdrCols loop 


    // listen for select changes
    // $('body').on('change', $(togSel), function() {  
    $(togSel).on('change', function () {
        $(this).attr('blocked', true);
        togCols($(this));
        })

    // just for iPad
    $(togSel).on('blur', function () {
        if ($(this).attr('blocked') != true) {
            togCols($(this));
            }
        });

    function togCols(SelectElement) {

        var topRow = thead.find('tr').length > 1 ? thead.find("tr:first-child th, TR:first-child TH").not('[rowspan=2]') : "",
            /* not sure why -1 is necessary, otherwise length is always one too hight. Maybe because function runs before visibility is toggled */
            bottomCells = thead.find("tr:last-child th:visible, TR:last-child TH:visible").length - 1;

        SelectElement.find("option").each(function () {
            var val = $(this).val(),
                col = $("#" + val + ", [headers=" + val + "]");

            $(this).is(':selected') ? col.show() : col.hide()
            })

        if (topRow) {
            if (bottomCells === 0) {
                topRow.hide();
            } else {
                topRow.attr('colspan', bottomCells).show();
                }
            }
    $(this).removeAttr('blocked');
    }


    // update the inputs' checked status
    $(window).on("orientationchange resize", function () {
        $('.ui-page-active .updateCols option').trigger("updateCheck");
    });

    // update selectmenu and move it into the table
    $(togSel).selectmenu("refresh");
    dropSel = twrap.find('.table-top-wrapper .ui-block-c').length > 0 ? twrap.find('.table-top-wrapper .ui-block-c') : twrap.find('.table-top-wrapper');
    $(togSel).closest('.ui-select').addClass('togSel slot1').appendTo(dropSel);

    // make sure all elements are enhanced
    $('div.table-top-wrapper').find('div.ui-block-a, div.ui-block-b, div.ui-block-c').trigger('create');
    $('div.table-bottom-wrapper').find('div.ui-block-a, div.ui-block-c').trigger('create');
    $('div.table-bottom-wrapper').trigger('create');

    }

This function creates the responsive table layout. I did this using Filaments RWD-Pattern, plus took some stuff from JQM.

VERY IMPORTANT:
If you want the responsive select to be a JQM custom select you need to add it's variable and an empty select at the beginning of your js file, before anything happens, like so:

var tblPos, your_other_table_variables;

$('.table-wrapper').each(function(i){   
    tableSelectMenu = $('<select data-theme="a" name="toggleCols" class="updateCols" id="toggleCols_'+i+'" multiple="multiple" data-icon="setup" data-iconpos="notext"></select>');        
    $(this).prepend(tableSelectMenu).jqmData('rpsv',i)
    });

This way the select will be created BEFORE the JQM pagecreate event runs, so you could add data-native-menu="false" if you wanted to have a custom select to toggle table columns.

Finally... the table like so:

// create a wrapper
<div class="table-wrapper ui-embedded">
    // to fill available slots in the table header, assign slot1/2/3 to a div
    // these will be changed into JQM elements, too.
    <div data-role="fieldcontain" class="slot2">
        <label class="select">View:</label>
        <select name="ansicht" data-inline="true">
            <option selected="" value="1">1</option>
    <option value="2">2</option>
        </select>    
    </div>
    <table class="tbl_basket_style">
        // double header rows are soso-supported
        <thead>
            <tr>
                // .optional will be hidden if no space
                // .essential will be shown if possible
                // .persist will always be visible
                <th data-sort="0" class="optional">Pos.</th>
                <th data-sort="1" class="essential persist">Style</th>
                <th data-sort="2">Description</th>
                <th data-sort="3" class="optional">Color</th>
                ... 
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>Ultra Shine</td>
                    <td>Product Ultra 10D description</td>
                    <td>200</td>
                    <td></td>
                    <td>4</td>
                    <td>PC</td>     
                    <td>
                        3.00 EUR<input type="hidden" id="preis11" value="3.00">
        </td>
                    ...
                </tr>
            </tbody>
            <tfoot>
                <tr>
                    <td></td>
                    ...
                </tr>
            </tfoot>
        </table>
    </div>

That's all... Once you have the first one working, the remaining ones are much easier :-)

Let me know if you need help in setting this up.

查看更多
仙女界的扛把子
3楼-- · 2019-05-22 14:52

This may help: http://jquerymobile.com/test/docs/content/content-grids.html

You should be able to dynamically add whatever you want to the grid cells.

查看更多
唯我独甜
4楼-- · 2019-05-22 15:08

I would sugest jQuery mobile, or Twitter Bootstrap.

Bootstrap is really good at re-sizing for every device.

http://twitter.github.com/bootstrap/

查看更多
一夜七次
5楼-- · 2019-05-22 15:09

I think you are looking for a table/grid component (that allows pagination, sorting, filtering and in-place editing), not for a CSS grid.

In that case, there are a few options:

For a feature comparison of table components, see http://reactive-table.meteor.com

查看更多
登录 后发表回答