Restore Form Value
前言
在多年前本人寫過一篇文章[ASP.net MVC / Html5] WebStorage - localStorage 進階實務應用
如何利用HTML5的localStorage達到「查詢過的值和結果,在切換頁面回來後要保留」的需求
如今相同客戶維護不同系統又遇到同樣需求XD
只不過這次是ASP.net WebForm,須留意的部份為自動產生的hidden欄位:__ViewState、__VIEWSTATEGENERATOR、__EVENTVALIDATION…等等
這幾個欄位如果把值重新回填,ASP.net會報錯
2017.11.16追記
目前已知issue:如果畫面有Ajax連動下拉選單的話,第二層以後的選單可能無法填回資料
2018.4.8 追記:修正checkbox無法還原回勾選問題
1.要先到此文章:JQuery Serialize Method and Checkboxes 把該作者改寫的jQuery serialize方法複製到自己的專案引用
取名為jquery.MySerialize.js
//出處:https://tdanemar.wordpress.com/2010/08/24/jquery-serialize-method-and-checkboxes/
(function ($) {
$.fn.serialize = function (options) {
return $.param(this.serializeArray(options));
};
$.fn.serializeArray = function (options) {
var o = $.extend({
checkboxesAsBools: false
}, options || {});
var rselectTextarea = /select|textarea/i;
var rinput = /text|hidden|password|search/i;
return this.map(function () {
return this.elements ? $.makeArray(this.elements) : this;
})
.filter(function () {
return this.name && !this.disabled &&
(this.checked
|| (o.checkboxesAsBools && this.type === 'checkbox')
|| rselectTextarea.test(this.nodeName)
|| rinput.test(this.type));
})
.map(function (i, elem) {
var val = $(this).val();
return val == null ?
null :
$.isArray(val) ?
$.map(val, function (val, i) {
return { name: elem.name, value: val };
}) :
{
name: elem.name,
value: (o.checkboxesAsBools && this.type === 'checkbox') ? //moar ternaries!
(this.checked ? 'true' : 'false') :
val
};
}).get();
};
})(jQuery);
實作
1.先新增一個RestoreFormValues.js檔
//出處:http://www.developerdrive.com/2013/08/turning-the-querystring-into-a-json-object-using-javascript/
function QueryStringToJSONObject(queryString) {
let pairs = queryString.split('&');
let result = {};
pairs.forEach(function(pair) {
pair = pair.split('=');
//jQuery .serialize()方法會做encodeURIComponent編碼,所以在此用decodeURIComponent,把資料還原回來
let key = decodeURIComponent(pair[0]);
let value = decodeURIComponent(pair[1] || '');
result[key] = value;
});
return JSON.parse(JSON.stringify(result));
}
//出處:http://stackoverflow.com/questions/9807426/use-jquery-to-re-populate-form-with-json-data
function RestoreFormValues(jsonObj) {
// reset form values from jsonObject
$.each(jsonObj, function(name, val) {
let $el = $('[name="' + name + '"]');
let type = $el.attr("type");
switch (type) {
case 'checkbox':
val = (val==="true")?true:false;
$el.prop("checked", val).attr("checked",val);
break;
case 'radio':
$el.filter('[value="' + val + '"]').prop("checked", true).attr('checked', true);
break;
default://可能是<input type='text'>或undefined的<textarea>、<select>
$el.val(val);
break;
}//end switch
});
}
//把表單查詢過的條件值填回去,並再查詢
function RestoreForm(name , HttpMethod) {
//此localStorage[name] 有存在
if (localStorage[name] !== undefined && HttpMethod === "GET")//只要Get Method填回查詢條件即可,post不用
{
//encodeURIComponent過的queryString
let queryString = String(localStorage[name]);
let jsonObj = QueryStringToJSONObject(queryString);
RestoreFormValues(jsonObj);//把值填回表單
//找「查詢」按鈕
let $searchBtn = $("form:first #btnQuery");
if ($searchBtn.length > 0)
{ //有抓到查詢按鈕
$searchBtn.click();//點擊它,顯示資料
}//end if
}//end if
}//end function
2.在網頁的Code-Behind寫下PageTitle
public partial class MyDemo : System.Web.UI.Page
{
protected string PageTitle = "此網頁標題";
protected void Page_Load(object sender, EventArgs e)
{
}//end Page_Load Event
}
3. .aspx網頁寫法↓
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="MyDemo.aspx.cs"
Inherits="MyDemo" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title><%= PageTitle %></title>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form id="form1" runat="server">
<!--兩個查詢條件-->
<asp:TextBox runat="server" ID="txtProduct" /><br/>
<asp:CheckBox runat="server" ID="cbState_Active_1" Text="啟用" /><br/>
<!--加上OnClientClick-->
<asp:Button ID="btnQuery" runat="server"
OnClientClick="return myConfirm();"
OnClick="btnQuery_Click" Text="查詢"
/><br/>
<!--依自己實際工作需求設定GridView-->
<asp:GridView ID="gvResult" runat="server"
AllowPaging="True" AllowSorting="True"
AutoGenerateColumns="False" DataKeyNames="Sysid"
>
</asp:GridView>
<!--引用jQuery核心-->
<script type="text/javascript" src="JS/jquery-3.2.1.js"></script>
<!-- 改寫過的jQuery serialize() -->
<script type='text/javascript' src='JS/jquery.MySerialize.js' ></script>
<!--把localStorage裡的表單值填回表單-->
<script type="text/javascript" src="JS/RestoreFormValues.js"></script>
<script type="text/javascript">
//把網頁標題當做此頁localStorage的Key,才不會和其他頁面衝突
let localStorageName = "<%= PageTitle %>";
function myConfirm()
{
//查詢參數表單
let myForm = $("form:first :not([type=hidden][name^=__])").serialize({ checkboxesAsBools: true });//queryString字串
//排除ASP.net WebForm自動產生的hidden欄位(__VIEWSTATE,__VIEWSTATEGENERATOR,__EVENTVALIDATION)
//因為 不可回填給原本欄位,否則ASP.net WebForm會報錯
localStorage[localStorageName] = myForm;//把QueryString存入localStorage
return true;//提交表單
}
$(function () {
RestoreForm(localStorageName,"<%= Request.HttpMethod %>");
});//end function
</script>
</form>
</body>
</html>
然後登出時↓
//表單驗證登出
FormsAuthentication.SignOut();
//清空Session
Session.Clear();
//取得登入頁Url
//視Web.config裡<forms>的設定
string loginUrl = FormsAuthentication.LoginUrl;
//清除此網站的localStorage
string js = @"localStorage.clear();";
//window.location.href也可以,視自己網站有沒有嵌入iframe狀況來調整
js += " top.location.href='" + loginUrl + "';";//導回登入頁
ClientScript.RegisterStartupScript(Page.GetType(),Guid.NewGuid().ToString(),js, true);
Web.config裡的loginUrl要設定
<system.web>
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx" name="MyDemoWebSite"
defaultUrl="~/Index.aspx"
timeout="60"
slidingExpiration="true"/>
</authentication>
</system.web>