通过会话存储获取所有表行值

时间:2022-02-05 12:42:09

I have an HTML table with one column having checkboxes. If you check a checkbox then press the "Checkout" button, it will take the specified rows and display them in the body of an email.

我有一个HTML表,其中一列有复选框。如果选中一个复选框,则按“结帐”按钮,它将获取指定的行并将其显示在电子邮件正文中。

The top 100 rows are displayed on page load. I also have a search functionality where the user can search for specific rows. The user can maneuver throughout different searches and still keep all of the checkboxes checked with session storage. However, when a user hits "Checkout," the body of the email only displays the table rows that are checked and currently visible on the page.

前100行显示在页面加载上。我还有一个搜索功能,用户可以搜索特定的行。用户可以在不同的搜索中进行操作,并且仍然使用会话存储来检查所有复选框。但是,当用户点击“Checkout”时,电子邮件的正文仅显示已检查且当前在页面上可见的表行。

So, if a user searches for a table row and checks it, but then navigates back to the original top 100 rows, that checked row would not display on the email because it is not displayed on the page at that current moment.

因此,如果用户搜索表行并进行检查,然后导航回原始的前100行,则该检查行将不会显示在电子邮件上,因为它在当前时刻未显示在页面上。

How can I fix this and show ALL rows that have been checked, whether they are visible on the page or not?

如何修复此问题并显示已检查的所有行,无论它们是否在页面上可见?

I have been told that I am storing the checkboxes in a session but then going back to the UI to read the list of selected items. However, I am unsure how exactly to fix this and would really appreciate some help! Thanks!

我被告知我将复选框存储在会话中,然后返回UI以读取所选项目列表。但是,我不确定如何解决这个问题,并且非常感谢一些帮助!谢谢!

JavaScript that includes code to keep all checkboxes checked throughout session:

包含代码的JavaScript,用于在整个会话期间检查所有复选框:

$(function(){
    $(':checkbox').each(function() {
        // Iterate over the checkboxes and set their "check" values based on the session data
        var $el = $(this);
        //console.log('element id: ',$el.prop('id'),' sessionStorage[id]: ',sessionStorage[$el.prop('id')]);
        $el.prop('checked', sessionStorage[$el.prop('id')] === 'true');
        if ($el.prop('checked')) {          
            //show the quantity cell in the column under header with class num
            $el.closest('tr').find('td.quantity_num').toggle(this.checked);
            var quantity = sessionStorage['value_'+$el.prop('id')];
            if (quantity) {
                $el.closest("tr").find(".spinner" ).spinner( "value", quantity );
            }
        }
    });

    $('input:checkbox').on('change', function() {
        // save the individual checkbox in the session inside the `change` event, 
        // using the checkbox "id" attribute
        var $el = $(this);
        sessionStorage[$el.prop('id')] = $el.is(':checked');
    });
});

JavaScript that sends information to email body:

将信息发送到电子邮件正文的JavaScript:

function sendMail() {
    var dataItems = [
        { 'clss':'.loc',         'prop':'loc' },
        { 'clss':'.rp-code',     'prop':'rpCode' },
        { 'clss':'.sku',         'prop':'sku' },
        { 'clss':'.special-id',  'prop':'specialId' },
        { 'clss':'.description', 'prop':'description' },
        { 'clss':'.quantity',    'prop':'quantity' },
        { 'clss':'.unit',        'prop':'unit' }
    ];
    var link = "mailto:me@example.com" + "?subject=" + encodeURIComponent("Order") + "&body=";
    link += $('#merchTable tr input[name="check"]:checked').closest('tr').get().map(function(tr) {
            var str = dataItems.map(function(item) {
                return encodeURIComponent($(tr).find(item.clss).data(item.prop)) + '\xa0\xa0';
            }).join('');
            str += encodeURIComponent($(tr).find('.spinner').spinner('value')) + '%0D%0A';
            return str;
        }).join('') + '%0D%0A';
    console.log(link);
    window.location.href = link;
}

HTML Table:

HTML表格:

<section id="checkout-btn"> 
<button id="checkout" name="order" onclick="sendMail(); return false">Checkout</button>
</section>

<br>

<table id="merchTable" cellspacing="5" class="sortable">
    <thead>
        <tr class="ui-widget-header">
            <th class="sorttable_nosort"></th>
            <th class="sorttable_nosort">Loc</th>
            <th class="merchRow">Report Code</th>
            <th class="merchRow">SKU</th>
            <th class="merchRow">Special ID</th>
            <th class="merchRow">Description</th>
            <th class="merchRow">Quantity</th>
            <th class="sorttable_nosort">Unit</th>
            <th style="display: none;" class="num">Quantity #</th>
        </tr>
    </thead>
    <tbody>

        <?php foreach ($dbh->query($query) as $row) {?>

        <tr>
            <td class="ui-widget-content"><input type="checkbox" class="check" name="check" id="checkid-<?php echo intval ($row['ID'])?>"></td>
            <td class="loc ui-widget-content" data-loc="<?php echo $row['Loc'] ?>"><input type="hidden"><?php echo $row['Loc'];?></td>
            <td class="rp-code ui-widget-content" align="center" data-rp-code="<?php echo $row['Rp-Code'] ?>" id="rp-code-<?php echo intval ($row['Rp-Code'])?>"><?php echo $row['Rp-Code'];?></td>
            <td class="sku ui-widget-content" data-sku="<?php echo $row['SKU'] ?>" id="sku-<?php echo intval ($row['SKU'])?>"><?php echo $row['SKU'];?></td>
            <td class="special-id ui-widget-content" data-special-id="<?php echo $row['Special-ID'] ?>" align="center" id="special-id-<?php echo intval ($row['Special-ID'])?>"><?php echo $row['Special-ID'];?></td>
            <td class="description ui-widget-content" data-description="<?php echo htmlspecialchars($row['Description']) ?>" id="description-<?php echo intval ($row['Description'])?>"><?php echo $row['Description'];?></td>
            <td class="quantity ui-widget-content" data-quantity="<?php echo $row['Quantity'] ?>" align="center" id="quantity-<?php echo intval ($row['Quantity'])?>"><?php echo $row['Quantity'];?></td>
            <td class="unit ui-widget-content" data-unit="<?php echo $row['Unit'] ?>" id="unit-<?php echo intval ($row['Unit'])?>"><?php echo $row['Unit'];?></td>
            <td style="display: none;" class="quantity_num ui-widget-content"><input disabled="true" type="textbox" style="width: 100px;" class="spinner" id="spin-<?php echo intval ($row['ID'])?>"></td>
        </tr>

    <?php } ?>

    </tbody>
</table>

EDIT:

编辑:

Function that display the Quantity # column when a row is checked:

检查行时显示Quantity#列的函数:

$(function () {
    $(".check").change(function(){
        $(this).closest('tr').find('td.quantity_num').toggle(this.checked);
        setupSpinner(this);
        console.log('input - checked: ',$('input.check').is(':checked'));
        //var quantity = $(this).closest('tr').find('td.quantity').data('quantity');

        if($('input.check').is(':checked'))
            $(this).closest('table').find('th.num').toggle(true);
        else
            $(this).closest('table').find('th.num').toggle(false);

    });
});

Function for the spinner:

微调器的功能:

function setupSpinner(checkbox) {
     var quantity = $(checkbox).closest('tr').find('td.quantity').data('quantity');
    console.log('quantity: ',quantity);
    $(checkbox).closest("tr").find(".spinner" ).spinner({
      spin: function( event, ui ) {          
        if ( ui.value > quantity ) {
          $( this ).spinner( "value", quantity );
          return false;
        } else if ( ui.value <= 1 ) {
          $( this ).spinner( "value", 1 );
          return false;
        }
          //store value
        var test = ui.value;
        sessionStorage.setItem('value_'+$(checkbox).prop('id'), JSON.stringify(test));
        var testtrue = sessionStorage.getItem('value_'+$(checkbox).prop('id'));
          console.log('testtrue: ', JSON.parse(testtrue));
      }
    });        
}

Function that gets values from each cell in checked table row:

从已检查表行中的每个单元格获取值的函数:

$(function () {
  $(document).on("click", "#merchTable .check", function () {
  var $this = $(this);
  var tds = $this.closest('tr').find('td').filter(function () {
    return $(this).find('.check').length === 0;
  });
    var isValid = true;
    var errors = '';
    var elements = tds;
    if (tds.find('td').length > 0) {
      elements = tds.find('td');
    }
    var dict = {}; 
    elements.each(function (index, element) {
      var type = $(this).attr('class');
      var value = (element.tagName == 'td') ? $(this).val() : $(this).text();
      console.log(type);
      // ----- Switch statement that provides validation for each table cell -----
      switch (type) {
        case "loc ui-widget-content":
              dict["Loc"] = value;
          break;
        case "rp-code ui-widget-content":
              dict["Rp-Code"] = value;
          break;
        case "sku ui-widget-content":
              dict["SKU"] = value;
          break;
        case "special-id ui-widget-content":
              dict["Special-ID"] = value;
          break;
        case "description ui-widget-content":
              dict["Description"] = value;
          break;
        case "quantity ui-widget-content":
              dict["Quantity"] = value;
          break;
        case "unit ui-widget-content":
              dict["Unit"] = value;
          break;
        case "quantity_num ui-widget-content":
              dict["spinner"] = value;
          break;
      }
    })
    if (isValid) {
        console.log(dict);
    } else {
      alert(errors);
    }
});
});

1 个解决方案

#1


1  

Based on this and earlier questions, I understand that you need something that :

根据这个和之前的问题,我知道你需要一些东西:

  • stores the state of checked rows in window.sessionStorage.
  • 在window.sessionStorage中存储已检查行的状态。
  • restores the state of checked rows after pagination/search.
  • 在分页/搜索后恢复已检查行的状态。
  • allows the composition of an email body, reflecting all checked rows whether they are currently displayed or not.
  • 允许电子邮件正文的组成,反映所有已检查的行,无论它们当前是否显示。

Without discipline the code could get really messy. I recommend a singleton object with a simple API, and ended up with the code below.

没有纪律,代码可能会变得非常混乱。我推荐使用简单API的单例对象,最后得到以下代码。

$(function($) {
    // **************************************************************
    // RowData acts as an interface beteween high level 
    // application code and sessionStorage.
    // *************************
    // RowData is phrased as a singleton object with private data,
    // and a bunch of functions, some of which are exposed as methods.
    // *************************
    // Inner member `rowData` is a javascript representation of all 
    // checked rows in the session.
    // A JSON-encoded version of `rowData` is stored in sessionStorage.
    // **************************************************************
    var RowData = (function(storage, storageKey) {
        var rowData = readFromSession();
        var dataItems = ['loc', 'rp-code', 'sku', 'special-id', 'description', 'quantity', 'unit'];
        var emailDelimiters = {
            'row': '%0D%0A',
            'dataItem': '\xa0\xa0'
        };

        function readFromSession() {
            return JSON.parse(storage.getItem(storageKey) || '{}');
        }
        function writeToSession() {
            storage.setItem(storageKey, JSON.stringify(rowData));
        }
        function writeRow(tr) {
            var $tr = $(tr),
                id = $tr.prop('id');
            if($tr.find('.check').is(':checked')) {
                rowData[id] = {};
                for(var i=0; i<dataItems.length; i++) {
                    rowData[id][dataItems[i]] = $tr.find('.' + dataItems[i]).text();
                }
                // rowData[id].quantity_num = $tr.find('.spinner').spinner('value'); // if using spinner widget
                rowData[id].quantity_num = $tr.find('.spinner').val(); // if using HTML5 <input type="number">
            } else {
                delete rowData[id];
            }
            writeToSession();
        }
        function readRow(tr) {
            // restore tr's checkbox and spinner value from stored data
            var $tr = $(tr),
                id = $tr.prop('id'),
                row = rowData[id];
            if(row) {
                $tr.find('.check').prop('checked', true).end()
                     // .find('.spinner').spinner('value', row.quantity_num); // if using spinner widget
                     .find('.spinner').val(row.quantity_num); // if using HTML5 <input type="number">
            }
        }
        function toEmailString() {
            return $.map(rowData, function(row, id) {
                return $.map(row, window.encodeURIComponent).join(emailDelimiters.dataItem);
            }).join(emailDelimiters.row);
        }
        // selectively expose functions as methods of RowData
        return {
            'writeRow': writeRow,
            'readRow': readRow, 
            'toEmailString': toEmailString
        };
    })(window.sessionStorage, 'checkedRowData');

    // **********************************************************************************************
    // With RowData in place to do the hard stuff, the high level application code is really simple
    // **********************************************************************************************
    $('#merchTable').on('change', '.check', function() { // on changing a table row ...
        RowData.writeRow($(this).closest('tr').get(0)); // ... set the corresponding row object in RowData and sessionStorage
    }).on('blur', '.spinner', function() { // on leaving a spinner widget
        RowData.writeRow($(this).closest('tr').get(0));
    });
    $('#checkout').on('click', function() { // on clicking the [Checkout] button
        var link = "mailto:me@example.com" + "?subject=" + encodeURIComponent("Order") + "&body=" + RowData.toEmailString();
        console.log(link);
        window.location.href = link;
    });

    // Call this function on completion of every pagination/search
    function restoreVisibleRows() {
        $('#merchTable tbody tr').get().forEach(RowData.readRow);
    }

    // ...
    // here, set up table pagination/search, and spinners.
    // ...


    restoreVisibleRows();
});

minimally tested

最低限度的测试

Note, everything above relies on table rows being served as follows :

注意,上面的所有内容都依赖于表行如下:

<tr id="<?php echo intval ($row['ID'])?>">
    <td class="ui-widget-content"><input type="checkbox" class="check" name="check" /></td>
    <td class="loc ui-widget-content"><input type="hidden"><?php echo $row['Loc'];?></td>
    <td class="rp-code ui-widget-content" align="center"><?php echo $row['Rp-Code'];?></td>
    <td class="sku ui-widget-content"><?php echo $row['SKU'];?></td>
    <td class="special-id ui-widget-content" align="center"><?php echo $row['Special-ID'];?></td>
    <td class="description ui-widget-content"><?php echo $row['Description'];?></td>
    <td class="quantity ui-widget-content" align="center" ><?php echo $row['Quantity'];?></td>
    <td class="unit ui-widget-content" ><?php echo $row['Unit'];?></td>
    <td style="display: none;" class="quantity_num ui-widget-content"><input disabled="true" type="number" min="1" max="<?php echo $row['Quantity'];?>" step="1" style="width: 100px;" class="spinner" /></td>
</tr>

Here, I :

我在这 :

  • added id="<?php echo intval ($row['ID'])?>" to the <tr> tag - the RowData interface won't work without it.
  • 添加了id =“<?php echo intval($ row ['ID'])?>”到标签 - 如果没有它,RowData接口将无法工作。
  • removed data-*** and id attributes from the <td> tags - they appear not to be necessary but can be reintroduced if needed for other purposes.
  • 从标签中删除了数据 - ***和id属性 - 它们似乎没有必要,但如果需要用于其他目的,可以重新引入。

#1


1  

Based on this and earlier questions, I understand that you need something that :

根据这个和之前的问题,我知道你需要一些东西:

  • stores the state of checked rows in window.sessionStorage.
  • 在window.sessionStorage中存储已检查行的状态。
  • restores the state of checked rows after pagination/search.
  • 在分页/搜索后恢复已检查行的状态。
  • allows the composition of an email body, reflecting all checked rows whether they are currently displayed or not.
  • 允许电子邮件正文的组成,反映所有已检查的行,无论它们当前是否显示。

Without discipline the code could get really messy. I recommend a singleton object with a simple API, and ended up with the code below.

没有纪律,代码可能会变得非常混乱。我推荐使用简单API的单例对象,最后得到以下代码。

$(function($) {
    // **************************************************************
    // RowData acts as an interface beteween high level 
    // application code and sessionStorage.
    // *************************
    // RowData is phrased as a singleton object with private data,
    // and a bunch of functions, some of which are exposed as methods.
    // *************************
    // Inner member `rowData` is a javascript representation of all 
    // checked rows in the session.
    // A JSON-encoded version of `rowData` is stored in sessionStorage.
    // **************************************************************
    var RowData = (function(storage, storageKey) {
        var rowData = readFromSession();
        var dataItems = ['loc', 'rp-code', 'sku', 'special-id', 'description', 'quantity', 'unit'];
        var emailDelimiters = {
            'row': '%0D%0A',
            'dataItem': '\xa0\xa0'
        };

        function readFromSession() {
            return JSON.parse(storage.getItem(storageKey) || '{}');
        }
        function writeToSession() {
            storage.setItem(storageKey, JSON.stringify(rowData));
        }
        function writeRow(tr) {
            var $tr = $(tr),
                id = $tr.prop('id');
            if($tr.find('.check').is(':checked')) {
                rowData[id] = {};
                for(var i=0; i<dataItems.length; i++) {
                    rowData[id][dataItems[i]] = $tr.find('.' + dataItems[i]).text();
                }
                // rowData[id].quantity_num = $tr.find('.spinner').spinner('value'); // if using spinner widget
                rowData[id].quantity_num = $tr.find('.spinner').val(); // if using HTML5 <input type="number">
            } else {
                delete rowData[id];
            }
            writeToSession();
        }
        function readRow(tr) {
            // restore tr's checkbox and spinner value from stored data
            var $tr = $(tr),
                id = $tr.prop('id'),
                row = rowData[id];
            if(row) {
                $tr.find('.check').prop('checked', true).end()
                     // .find('.spinner').spinner('value', row.quantity_num); // if using spinner widget
                     .find('.spinner').val(row.quantity_num); // if using HTML5 <input type="number">
            }
        }
        function toEmailString() {
            return $.map(rowData, function(row, id) {
                return $.map(row, window.encodeURIComponent).join(emailDelimiters.dataItem);
            }).join(emailDelimiters.row);
        }
        // selectively expose functions as methods of RowData
        return {
            'writeRow': writeRow,
            'readRow': readRow, 
            'toEmailString': toEmailString
        };
    })(window.sessionStorage, 'checkedRowData');

    // **********************************************************************************************
    // With RowData in place to do the hard stuff, the high level application code is really simple
    // **********************************************************************************************
    $('#merchTable').on('change', '.check', function() { // on changing a table row ...
        RowData.writeRow($(this).closest('tr').get(0)); // ... set the corresponding row object in RowData and sessionStorage
    }).on('blur', '.spinner', function() { // on leaving a spinner widget
        RowData.writeRow($(this).closest('tr').get(0));
    });
    $('#checkout').on('click', function() { // on clicking the [Checkout] button
        var link = "mailto:me@example.com" + "?subject=" + encodeURIComponent("Order") + "&body=" + RowData.toEmailString();
        console.log(link);
        window.location.href = link;
    });

    // Call this function on completion of every pagination/search
    function restoreVisibleRows() {
        $('#merchTable tbody tr').get().forEach(RowData.readRow);
    }

    // ...
    // here, set up table pagination/search, and spinners.
    // ...


    restoreVisibleRows();
});

minimally tested

最低限度的测试

Note, everything above relies on table rows being served as follows :

注意,上面的所有内容都依赖于表行如下:

<tr id="<?php echo intval ($row['ID'])?>">
    <td class="ui-widget-content"><input type="checkbox" class="check" name="check" /></td>
    <td class="loc ui-widget-content"><input type="hidden"><?php echo $row['Loc'];?></td>
    <td class="rp-code ui-widget-content" align="center"><?php echo $row['Rp-Code'];?></td>
    <td class="sku ui-widget-content"><?php echo $row['SKU'];?></td>
    <td class="special-id ui-widget-content" align="center"><?php echo $row['Special-ID'];?></td>
    <td class="description ui-widget-content"><?php echo $row['Description'];?></td>
    <td class="quantity ui-widget-content" align="center" ><?php echo $row['Quantity'];?></td>
    <td class="unit ui-widget-content" ><?php echo $row['Unit'];?></td>
    <td style="display: none;" class="quantity_num ui-widget-content"><input disabled="true" type="number" min="1" max="<?php echo $row['Quantity'];?>" step="1" style="width: 100px;" class="spinner" /></td>
</tr>

Here, I :

我在这 :

  • added id="<?php echo intval ($row['ID'])?>" to the <tr> tag - the RowData interface won't work without it.
  • 添加了id =“<?php echo intval($ row ['ID'])?>”到标签 - 如果没有它,RowData接口将无法工作。
  • removed data-*** and id attributes from the <td> tags - they appear not to be necessary but can be reintroduced if needed for other purposes.
  • 从标签中删除了数据 - ***和id属性 - 它们似乎没有必要,但如果需要用于其他目的,可以重新引入。