This article shares a small problem I encountered when using sessionStorage, and I will avoid this pitfall in the future.
The requirement is cell editing in easyui tables. When you click save, the editing of the current row will end, and then the editingId (the ID of the current editing row record) will be modified.
Table of Contents
1. Problems to be solved
2. Complete page code
3. Specific business logic
adding data
save data
Edit data
4. Problem analysis
5. Problem solving
1. Problems to be solved
As shown in the picture, there is no response when clicking the modify button, and no error is reported.
2. Complete page code
menu_list.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="/css/themes/icon.css"/> <link rel="stylesheet" href="/css/themes/default/easyui.css" /> <title>System Management>>Menu List</title> <script src="/js/public/jquery.min.js"></script> <script src="/js/easyui/jquery.easyui.min.js"></script> <script src="/js/easyui/easyui-lang-zh_CN.js"></script> <script src="/js/public/util.js"></script> <script src="/js/public/public.js"></script> <script src="/js/public/sessionStorage.js"></script> <script src="/js/menu_list.js"></script> </head> \t <body> <div> <a href="javascript:" class="easyui-linkbutton" onclick="insert()">Add</a> <a href="javascript:" class="easyui-linkbutton" onclick="edit()">Edit</a> <a href="javascript:" class="easyui-linkbutton" onclick="save()">Save</a> <a href="javascript:" class="easyui-linkbutton" onclick="cancel()">Cancel</a> <a href="javascript:" class="easyui-linkbutton" onclick="expandAll()">Expand all</a> <a href="javascript:" class="easyui-linkbutton" onclick="collapseAll()">Collapse All</a> </div> <div id="mm" class="easyui-menu" style="width:120px;"> <div onclick="append()" data-options="iconCls:'icon-add'">Add</div> <div onclick="removeIt()" data-options="iconCls:'icon-remove'">Remove</div> <div class="menu-sep"></div> <div onclick="collapse()">Collapse</div> <div onclick="expand()">Expand</div> </div> \t <table id="menu_treegrid"></table> </body> </html>
menu_list.js
let parentId; let data = { id: "", name: "xxx", url: "", icon: "icon-xxx" }; /** * Add to */ function insert() { let menuId = new Date().getTime(); let treegrid = $("#menu_treegrid"); treegrid.treegrid("append",{ data: [{ id: menuId, name: "xxx", url: "/html/xxx", icon: "icon-xxx" }] }); //Save editingId to sessionStorage storage("editingId", menuId); \t // Enable line editing treegrid.treegrid("beginEdit", menuId); } /** * Revise */ function edit() { let editingId = getStorage("editingId"); console.log(editingId); if (editingId) { $("#menu_treegrid").treegrid("select", editingId); } else { let row = $("#menu_treegrid").treegrid("getSelected"); console.log("Start editing line:"); console.log(row); if (row) { storage("editingId", row.id); $("#menu_treegrid").treegrid("beginEdit", row.id); } } } /** * save */ function save() { let editingId = getStorage("editingId"); if (editingId) { let treegrid = $("#menu_treegrid"); if (editingId) { // Only when editing is completed can the latest value be obtained treegrid.treegrid("endEdit", editingId); let postData = { id: editingId, name: data.name, url: data.url, icon: data.icon, parentId: parentId }; console.log(postData); storage("editingId", undefined); // post("/menu/updateById", postData, function () { // storage("editingId", undefined); // }, error); } } } /** * Cancel */ function cancel() { let editingId = getStorage("editingId"); if (editingId) { $("#menu_treegrid").treegrid("cancelEdit", editingId); storage("editingId", undefined); } } /** *Collapse all */ function collapseAll() { $("#menu_treegrid").treegrid("collapseAll"); } /** * Expand All */ function expandAll() { $("#menu_treegrid").treegrid("expandAll"); } /** * Add to */ function append() { let menuId = new Date().getTime(); let treegrid = $("#menu_treegrid"); let node = treegrid.treegrid("getSelected"); parentId = node.id; storage("editingId", menuId); treegrid.treegrid("append",{ parent: node.id, data: [{ id: menuId, name: "xxx", url: "", icon: "icon-xxx" }] }); let editingId = getStorage("editingId"); treegrid.treegrid("beginEdit", editingId); } /** * delete */ function removeIt() { let node = $("#menu_treegrid").treegrid("getSelected"); if (node) { $("#menu_treegrid").treegrid("remove", node.id); } } /** * fold */ function collapse() { let node = $("#menu_treegrid").treegrid("getSelected"); if (node) { $("#menu_treegrid").treegrid("collapse", node.id); } } /** * Expand */ function expand() { let node = $("#menu_treegrid").treegrid("getSelected"); \t if (node) { $("#menu_treegrid").treegrid("expand", node.id); } } $(document).ready(function() { $("#menu_treegrid").treegrid({ url: "/menu/listTreeGrid", method: "get", idField: "id", treeField: "name", fitColumns: true, pagination: true, pageSize: 10, pageList: [10, 20, 50, 100], columns:[[ {title: "menu number", field: "id", hidden: true}, {title: "menu name", field: "name", align: "left", editor: "textbox", width: 100}, {title: "icon style", field: "icon", align: "left", editor: "textbox", width: 100}, {title: "page address", field: "url", align: "left", editor: "textbox", width: 200, formatter: function(value) { if (value) { return "<a href='" + value + "'>" + value + "</a>"; } else { return "<div>/</div>"; } } } ]], onAfterEdit: function (row, changes) { console.log(changes); data = { id: row.id, name: row.name ? row.name : changes.name, url: row.url ? row.url : changes.url, icon: row.icon ? row.icon : changes.icon };; }, onContextMenu: function (e, row) { e.preventDefault(); $(this).treegrid("select", row.id); $("#mm").menu("show",{ left: e.pageX, top:e.pageY }); } }).treegrid("clientPaging"); }); (function($) { function pagerFilter(data) { if ($.isArray(data)) { // is array data = { total: data.length, rows: data } } let dg = $(this); let state = dg.data("treegrid"); let opts = dg.treegrid("options"); let pager = dg.treegrid("getPager"); pager.pagination({ onSelectPage:function(pageNum, pageSize) { opts.pageNumber = pageNum; opts.pageSize = pageSize; pager.pagination("refresh",{ pageNumber:pageNum, pageSize:pageSize }); dg.treegrid("loadData",state.originalRows); } }); if (!state.originalRows){ state.originalRows = data.rows; } let topRows = []; let childRows = []; $.map(state.originalRows, function(row){ row._parentId ? childRows.push(row) : topRows.push(row); }); data.total = topRows.length; let start = (opts.pageNumber-1)*parseInt(opts.pageSize); let end = start + parseInt(opts.pageSize); data.rows = $.extend(true,[],topRows.slice(start, end).concat(childRows)); return data; } let appendMethod = $.fn.treegrid.methods.append; let loadDataMethod = $.fn.treegrid.methods.loadData; $.extend($.fn.treegrid.methods, { clientPaging: function(jq) { return jq.each(function() { let state = $(this).data("treegrid"); let opts = state.options; opts.loadFilter = pagerFilter; let onBeforeLoad = opts.onBeforeLoad; opts.onBeforeLoad = function(row,param) { state.originalRows = null; onBeforeLoad.call(this, row, param); } $(this).treegrid("loadData", state.data); $(this).treegrid("reload"); }); }, loadData: function(jq, data) { jq.each(function() { $(this).data("treegrid").originalRows = null; }); return loadDataMethod.call($.fn.treegrid.methods, jq, data); }, append: function(jq, param) { return jq.each(function() { let state = $(this).data("treegrid"); if (state.options.loadFilter == pagerFilter){ $.map(param.data, function(row) { row._parentId = row._parentId || param.parent; state.originalRows.push(row); }); $(this).treegrid("loadData", state.originalRows); } else { appendMethod.call($.fn.treegrid.methods, jq, param); } }) } }); })(jQuery);
3. Specific business logic
Add data
When the Add button is clicked, a row of records will be added at the end of the table, row editing will be enabled, and sessionStorage will be used to save the ID of the row data being edited.
/** * Add to */ function insert() { let menuId = new Date().getTime(); let treegrid = $("#menu_treegrid"); treegrid.treegrid("append",{ data: [{ id: menuId, name: "xxx", url: "/html/xxx", icon: "icon-xxx" }] }); //Save editingId to sessionStorage storage("editingId", menuId); \t // Enable line editing treegrid.treegrid("beginEdit", menuId); }
Save data
Clicking save will modify the value of editingId to undefined, which is equivalent to deletion.
/** * save */ function save() { let editingId = getStorage("editingId"); if (editingId) { let treegrid = $("#menu_treegrid"); if (editingId) { //Only after editing can the latest value be obtained treegrid.treegrid("endEdit", editingId); let postData = { id: editingId, name: data.name, url: data.url, icon: data.icon, parentId: parentId }; console.log(postData); // Modify the value of editingId to undefined, which is equivalent to deletion storage("editingId", undefined); // post("/menu/updateById", postData, function () { // storage("editingId", undefined); // }, error); } } }
Edit data
Select a row in the table and click the edit button. It will determine whether there is currently a row being edited based on the value of editingId. If so, the current row will be selected, but the row being edited will not end. If there is no data row being edited, editing of the currently selected row is started.
/** * Revise */ function edit() { let editingId = getStorage("editingId"); console.log(editingId); if (editingId) { $("#menu_treegrid").treegrid("select", editingId); } else { let row = $("#menu_treegrid").treegrid("getSelected"); console.log("Start editing line:"); console.log(row); if (row) { storage("editingId", row.id); $("#menu_treegrid").treegrid("beginEdit", row.id); } } }
Four. Problem Analysis
There is no response when clicking the modify button, but no error is reported. The problem is obviously that the if branch keeps selecting the current line.
Therefore, the key to the problem lies in the value of editingId. The value printed by the browser above is undefined, which is obviously not a problem.
However, the fatal thing is here. The undefined printed here is not undefined, but “undefined” of the string.
If you print undefined directly, it will be gray, as shown in the figure. The one below is really undefined.
5. Problem Solving
Solution 1: Since undefined cannot be stored directly, just store an empty string in it, and the problem is perfectly solved~
/** * save */ function save() { let editingId = getStorage("editingId"); if (editingId) { let treegrid = $("#menu_treegrid"); if (editingId) { // Only when editing is completed can the latest value be obtained treegrid.treegrid("endEdit", editingId); let postData = { id: editingId, name: data.name, url: data.url, icon: data.icon, parentId: parentId }; storage("editingId", ""); } } }
Solution 2: Delete data from localStorage
/** * save */ function save() { let editingId = getStorage("editingId"); if (editingId) { let treegrid = $("#menu_treegrid"); if (editingId) { // Only when editing is completed can the latest value be obtained treegrid.treegrid("endEdit", editingId); let postData = { id: editingId, name: data.name, url: data.url, icon: data.icon, parentId: parentId }; localStorage.removeItem("editingId"); } } }