A.Farzin
جمعه 01 خرداد 1394, 18:40 عصر
با سلام
در Viewهای Create و Edit با هلپر DropDownList برای لیستهای طولانی (مثلاً لیست مشاغل، لیست شهرها و ...) مشکل داشتم.
هر کدام این لیستها باید از جدولی در دیتابیس خوانده میشد که تعداد رکورد بالایی داشتند و وصل کردن آن با DropDownList باعث لود شدن تمام رکوردها همراه view میشد. گذشته از سنگین شدن صفحه، لیست به این بزرگی اصلاً مناسب انتخاب کاربر نیست و باید به جای آن این امکان فراهم شود که کاربر بتواند با جستجوی بین اقلام دامنه لیست را کمتر و کمتر کرده و آیتم مورد نظر خود را انتخاب کند.
میخواستم که این کار بدون استفاده از کنترلهای آماده انجام شود و تنها از امکانات موجود در خود ASP.NET MVC استفاده شود.
باید به جای DropDownList از یک EditFor استفاده میشد با نمایش یک Popup به کاربر امکان جستجو بین رکوردها و دسترسی به آیتم دلخواه را به کاربر داد.
پس از کلی تلاش، بالاخره موفق به پیادهسازی آن به شکل زیر شدم. سناریوی این کار با یک اشکال مواجهه شد و آن اینکه وقتی کاربر میخواهد بین مقادیر جستجو داشته باشد، برخلاف انتظار فقط Child Action انجام نمیشود و با اجرای مجدد کل صفحه، اجرای @Html.Action دچار مشکل میشود.
چگونه میتوانم فقط همان قسمت از صفحه که مربوط به اکشن بوده و مشابه یک پارشیال ویو است را مجدداً Get کنم؟
کاری که برای انتخاب شغل انجام دادهام اینه:
(۱) برای جدول مشاغل کلاسی به نام Job به به شکل زیر دارم:
public partial class Job
{
public int JobID { get; set; }
public Nullable<int> JobCode { get; set; }
public string JobName { get; set; }
}
(۲) یک Child Action با فیلتر [ChildActionOnly] ساختم که قابلیت جستجوی بین فیلدهای سه گانه جدولم را فراهم میکند.
[HttpGet]
[ChildActionOnly]
public PartialViewResult JobSelect(string JobID, string JobCode, string JobName)
{
var tmp = from j in db.Job
select j;
if (!String.IsNullOrEmpty(JobID))
{
tmp = tmp.Where(s => s.JobID.ToString().Contains(JobID));
}
if (!String.IsNullOrEmpty(JobCode))
{
tmp = tmp.Where(s => s.JobCode.ToString().Contains(JobCode));
}
if (!String.IsNullOrEmpty(JobName))
{
tmp = tmp.Where(s => s.JobName.ToString().Contains(JobName));
}
tmp = tmp.OrderBy(s => s.JobID);
tmp = tmp.Take(20);
return PartialView("~/Views/Lookup/JobSelect.cshtml", tmp.ToList());
}
(۳) یک View با نام JobSelect و از نوع List ساختم که به مدل Job وصل است.
@model IEnumerable<MyProject.Models.Job>
@using (Html.BeginForm("JobSelect", "Lookup", FormMethod.Get))
{
<table class="table" id="TblJobSelect">
<tr>
<th>
@Html.DisplayNameFor(model => model.JobID)
</th>
<th>
@Html.DisplayNameFor(model => model.JobCode)
</th>
<th>
@Html.DisplayNameFor(model => model.JobName)
</th>
</tr>
<tr>
<th>
@Html.TextBox("SearchString_JobID", ViewBag.CurrentFilter_JobID as string, new { @class = "search FilterBar" })
</th>
<th>
@Html.TextBox("SearchString_JobCode", ViewBag.CurrentFilter_JobCode as string, new { @class = "search FilterBar" })
</th>
<th>
@Html.TextBox("SearchString_JobName", ViewBag.CurrentFilter_JobName as string, new { @class = "search FilterBar" })
</th>
</tr>
@foreach (var item in Model)
{
<tr id="@item.JobID">
<td>
@Html.DisplayFor(modelItem => item.JobID)
</td>
<td>
@Html.DisplayFor(modelItem => item.JobCode)
</td>
<td>
@Html.DisplayFor(modelItem => item.JobName)
</td>
</tr>
}
</table>
}
(۴) در View مربوط به Create با کمک کد زیر ویوی JobSelect را از کنترلی به نام Lookup فراخوانی شده است.
<div class="popup" ondblclick="closepopup()">
@Html.Action("JobSelect", "Lookup", new { area = "" })
</div>
(۵) با کمک CSSها، ویوی JobSelect مخفی شده و در زمان نیاز کاربر با jQuery به شکل یک Popup نمایش داده میشود.
css مربوط به popup
.offdiv{
width:100%;
height:100%;
background:#000;
opacity:0.7;
position:fixed;
top:0;
right:0;
z-index:200;
display:none;
}
.popup{
padding:20px;
width:76%;
height:75%;
background:#fff;
position:fixed;
top:100px;
right:200px;
z-index:201;
display:none;
overflow:scroll;
border-radius:4px;
}
توابع jQuery مربوطه
function openpopup(){
$('.offdiv').fadeIn('slow',function(){
$('.popup').css('right','12%');
$('.popup').css('top','10%');
$('.popup').slideDown('slow');
});
}
function closepopup(){
$('.popup').slideUp('slow',function(){
$('.offdiv').fadeOut('slow');
});
}
(۶) انتخاب رکورد دلخواه کاربر و دابل کلیک روی آن منجر به بسته شدن Popup و درج مقدار مورد نظر در EditFor مورد نظر که id آن با JobID نامگذاری شده است میگردد.
$(document).ready(function () {
$('#TblJobSelect tr').dblclick(function (event) {
$("#JobID").val($(this).attr('id'));
});
});
در view نمایش داده شده روی popup میتوان با دادن پارامترها و Render شدن مجدد این قسمت، بین مقادیر جدول دیتابیس جستجو کرده و به مقدار دلخواه رسید ولی مشکلی که پیش آمده این است که وقتی پارامتر جستجو را میدهیم به جای Render شدن مجدد فقط ویوی JobSelect تمام Viewی اصلی (Create View) هم رندر میشود. و وقتی که به به اجرای مجدد @Html.Action() میرسد با خطای زیر مواجه میشود.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: A public action method 'JobSelect' was not found on controller 'MyProject.Controllers.LookupController'.
Source Error:
<div class="popup" ondblclick="closepopup()">
@Html.Action("JobSelect", "Lookup", new { area = "" })
</div>
چگونه میتوانم فقط همان قسمت از صفحه که مربوط به اکشن بوده و مشابه یک پارشیال ویو است را مجدداً Get کنم؟
در Viewهای Create و Edit با هلپر DropDownList برای لیستهای طولانی (مثلاً لیست مشاغل، لیست شهرها و ...) مشکل داشتم.
هر کدام این لیستها باید از جدولی در دیتابیس خوانده میشد که تعداد رکورد بالایی داشتند و وصل کردن آن با DropDownList باعث لود شدن تمام رکوردها همراه view میشد. گذشته از سنگین شدن صفحه، لیست به این بزرگی اصلاً مناسب انتخاب کاربر نیست و باید به جای آن این امکان فراهم شود که کاربر بتواند با جستجوی بین اقلام دامنه لیست را کمتر و کمتر کرده و آیتم مورد نظر خود را انتخاب کند.
میخواستم که این کار بدون استفاده از کنترلهای آماده انجام شود و تنها از امکانات موجود در خود ASP.NET MVC استفاده شود.
باید به جای DropDownList از یک EditFor استفاده میشد با نمایش یک Popup به کاربر امکان جستجو بین رکوردها و دسترسی به آیتم دلخواه را به کاربر داد.
پس از کلی تلاش، بالاخره موفق به پیادهسازی آن به شکل زیر شدم. سناریوی این کار با یک اشکال مواجهه شد و آن اینکه وقتی کاربر میخواهد بین مقادیر جستجو داشته باشد، برخلاف انتظار فقط Child Action انجام نمیشود و با اجرای مجدد کل صفحه، اجرای @Html.Action دچار مشکل میشود.
چگونه میتوانم فقط همان قسمت از صفحه که مربوط به اکشن بوده و مشابه یک پارشیال ویو است را مجدداً Get کنم؟
کاری که برای انتخاب شغل انجام دادهام اینه:
(۱) برای جدول مشاغل کلاسی به نام Job به به شکل زیر دارم:
public partial class Job
{
public int JobID { get; set; }
public Nullable<int> JobCode { get; set; }
public string JobName { get; set; }
}
(۲) یک Child Action با فیلتر [ChildActionOnly] ساختم که قابلیت جستجوی بین فیلدهای سه گانه جدولم را فراهم میکند.
[HttpGet]
[ChildActionOnly]
public PartialViewResult JobSelect(string JobID, string JobCode, string JobName)
{
var tmp = from j in db.Job
select j;
if (!String.IsNullOrEmpty(JobID))
{
tmp = tmp.Where(s => s.JobID.ToString().Contains(JobID));
}
if (!String.IsNullOrEmpty(JobCode))
{
tmp = tmp.Where(s => s.JobCode.ToString().Contains(JobCode));
}
if (!String.IsNullOrEmpty(JobName))
{
tmp = tmp.Where(s => s.JobName.ToString().Contains(JobName));
}
tmp = tmp.OrderBy(s => s.JobID);
tmp = tmp.Take(20);
return PartialView("~/Views/Lookup/JobSelect.cshtml", tmp.ToList());
}
(۳) یک View با نام JobSelect و از نوع List ساختم که به مدل Job وصل است.
@model IEnumerable<MyProject.Models.Job>
@using (Html.BeginForm("JobSelect", "Lookup", FormMethod.Get))
{
<table class="table" id="TblJobSelect">
<tr>
<th>
@Html.DisplayNameFor(model => model.JobID)
</th>
<th>
@Html.DisplayNameFor(model => model.JobCode)
</th>
<th>
@Html.DisplayNameFor(model => model.JobName)
</th>
</tr>
<tr>
<th>
@Html.TextBox("SearchString_JobID", ViewBag.CurrentFilter_JobID as string, new { @class = "search FilterBar" })
</th>
<th>
@Html.TextBox("SearchString_JobCode", ViewBag.CurrentFilter_JobCode as string, new { @class = "search FilterBar" })
</th>
<th>
@Html.TextBox("SearchString_JobName", ViewBag.CurrentFilter_JobName as string, new { @class = "search FilterBar" })
</th>
</tr>
@foreach (var item in Model)
{
<tr id="@item.JobID">
<td>
@Html.DisplayFor(modelItem => item.JobID)
</td>
<td>
@Html.DisplayFor(modelItem => item.JobCode)
</td>
<td>
@Html.DisplayFor(modelItem => item.JobName)
</td>
</tr>
}
</table>
}
(۴) در View مربوط به Create با کمک کد زیر ویوی JobSelect را از کنترلی به نام Lookup فراخوانی شده است.
<div class="popup" ondblclick="closepopup()">
@Html.Action("JobSelect", "Lookup", new { area = "" })
</div>
(۵) با کمک CSSها، ویوی JobSelect مخفی شده و در زمان نیاز کاربر با jQuery به شکل یک Popup نمایش داده میشود.
css مربوط به popup
.offdiv{
width:100%;
height:100%;
background:#000;
opacity:0.7;
position:fixed;
top:0;
right:0;
z-index:200;
display:none;
}
.popup{
padding:20px;
width:76%;
height:75%;
background:#fff;
position:fixed;
top:100px;
right:200px;
z-index:201;
display:none;
overflow:scroll;
border-radius:4px;
}
توابع jQuery مربوطه
function openpopup(){
$('.offdiv').fadeIn('slow',function(){
$('.popup').css('right','12%');
$('.popup').css('top','10%');
$('.popup').slideDown('slow');
});
}
function closepopup(){
$('.popup').slideUp('slow',function(){
$('.offdiv').fadeOut('slow');
});
}
(۶) انتخاب رکورد دلخواه کاربر و دابل کلیک روی آن منجر به بسته شدن Popup و درج مقدار مورد نظر در EditFor مورد نظر که id آن با JobID نامگذاری شده است میگردد.
$(document).ready(function () {
$('#TblJobSelect tr').dblclick(function (event) {
$("#JobID").val($(this).attr('id'));
});
});
در view نمایش داده شده روی popup میتوان با دادن پارامترها و Render شدن مجدد این قسمت، بین مقادیر جدول دیتابیس جستجو کرده و به مقدار دلخواه رسید ولی مشکلی که پیش آمده این است که وقتی پارامتر جستجو را میدهیم به جای Render شدن مجدد فقط ویوی JobSelect تمام Viewی اصلی (Create View) هم رندر میشود. و وقتی که به به اجرای مجدد @Html.Action() میرسد با خطای زیر مواجه میشود.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: A public action method 'JobSelect' was not found on controller 'MyProject.Controllers.LookupController'.
Source Error:
<div class="popup" ondblclick="closepopup()">
@Html.Action("JobSelect", "Lookup", new { area = "" })
</div>
چگونه میتوانم فقط همان قسمت از صفحه که مربوط به اکشن بوده و مشابه یک پارشیال ویو است را مجدداً Get کنم؟