Серия руководств по MVC, jQuery, JSON, пагинации и mapRoute

Скачать исходный код
Введение
Из-за большого объема данных в системах баз данных работа на стороне клиента стала очень важной. В подходе code-behind классического ASP.NET естественным способом является кодирование большей части работы в файлах code-behind с использованием компонентов ASP.NET. Более того, рендеринг компонентов ASP.NET и механизм viewstate теперь считаются слабыми сторонами классического ASP.NET.
Поэтому появилась новая парадигма. Согласно этой новой парадигме, разработчик может работать с чистым HTML и JavaScript без viewstate, снижающего производительность, и с меньшим рендерингом.
MVC известен как старый шаблон проектирования или архитектуры, но стал особенно популярным после упомянутых выше узких мест классического ASP.NET. В MVC, где jQuery и JSON эффективно используются, можно разрабатывать высокопроизводительные приложения.
Предварительные знания
Эта статья может быть полезной после прочтения нескольких вводных статей о MVC, jQuery и JSON. Следующие ссылки могут быть полезны для начинающих:
- Руководство по MVC для начинающих
- Руководство по jQuery для начинающих
- Руководство по JSON для начинающих
Использование кода
В этой статье мы нацелены на "серию руководств". Поэтому все скрипты предоставлены из приложенного исходного кода. Фактически, каждое "руководство" могло бы стать отдельной статьей. В любом случае, все возможные ответы собраны в одном примере. В этой статье больше практических подходов, чем теоретической информации. Например, для простоты вместо базы данных использованы некоторые статические списки.
Ответы на следующие вопросы:
- Как выполнить CRUD с хорошей производительностью в MVC?
- Как использовать диалог jQuery вместо JavaScript confirm или alert?
- Как сделать пагинацию в списке MVC?
- Как сделать ссылку "показать еще" в MVC с помощью jQuery?
- Как использовать атрибут (attribute) со ссылкой?
- Как сделать вызов AJAX в jQuery?
- Как использовать коллекцию Form в MVC?
- Как удалить несколько записей за раз?
- Как использовать partial action в MVC?
- Как использовать формат JSON в приложении MVC?
- Как заполнить master-detail combobox?
- Как использовать jQuery datepicker?
- Как загрузить изображение в MVC с помощью диалога jQuery?
- Как создать строку таблицы на стороне клиента?
- Как настроить mapRoute в Global.asax?
- Как сделать checkALL и uncheckALL для всех строк таблицы?
- Как сделать "Loading Data"?
- Как сделать master-detail grid с jQuery?
1) Как выполнить CRUD с хорошей производительностью в MVC?
Грубо говоря, все бизнес-решения имеют функцию Create-Read-Update-Delete (Создание-Чтение-Обновление-Удаление). Если возможно, использование одной и той же "формы сохранения" для "insert" и "update" может быть экономичным для разработчика. Использование одной формы возможно через управление параметрами, отправляемыми в action.
Предположим, у вас есть список в виде таблицы (фактически HTML-таблица) и отдельная кнопка "new". Каждая строка таблицы имеет кнопки "edit" и "delete", связанные с этой строкой.
Перенаправление на новую страницу - здесь называемую view - после нажатия "New" не является эффективным способом. Потому что после сохранения данных на перенаправленной странице, пользователю нужно нажать "показать список", чтобы увидеть данные, добавленные в базу данных. Это означает перенаправление на страницу списка и выбор данных из базы с переменными затратами!
Вместо сценария "нажать new и снова список", описанного выше, можно применить более эффективный способ.
Create (Создание):
- В списке view после нажатия "New" может появиться "jQuery Save dialog".
- Create view рендерится в jQuery dialog.
- Заполняется форма create и нажимается "Save".
- При нажатии кнопки Save данные могут быть отправлены в соответствующий controller через AJAX post.
- У Ajax-формы есть JavaScript-функция
onSuccess. - В методе "
onSuccess" JavaScript добавленная новая строка, JSON, приходящий как параметр в "onSuccess", добавляется (prepend) в начало списка без обновления всего списка.
Read (Чтение):
Это операция списка. Если возможно, в форме списка должны отображаться только необходимые данные. Можно использовать следующие техники:
- пагинация с combobox или номерами,
- реализация "показать еще",
- список с фильтрацией.
Update (Обновление):
- В списке view после нажатия "Edit" на любой строке списка может появиться тот же "jQuery Save dialog" с данными выбранной строки.
- Все шаги такие же, как в "Create", поэтому только метод "
onSuccess" изменяется в соответствии с операцией "update". - В этом случае после обновления базы данных обновляются только данные редактируемой строки в view. Таким образом, нет необходимости обновлять весь список, чтобы увидеть последнюю отредактированную запись.
Delete (Удаление):
- После подтверждения в красивом jQuery dialog, после удаления из базы данных только выбранная строка удаляется из списка. Опять же, нет необходимости обновлять весь список.
Один и тот же dialog используется для insert и edit.

Ссылки в view PersonList.cshtml следующие:
HTML
@Html.ActionLink("New", "Save",
new { personNo = 0 }, new { @class = "newLink" })
...
@Html.ActionLink("Edit", "Save", new { personNo = item.PersonNo }, new { @class = "editLink" })
- New: Отображаемый текст.
- Save: action в Controller.
- personNo: Параметр, отправляемый в action "Save". Если 0, диалог открывается пустым, если больше 0 - данные этого id отображаются в диалоге.
- newLink: Виртуальный className, используемый в следующем jQuery.
JavaScript
<div id="saveDialog" title="Person Information"></div>
<script type="text/javascript">
var linkObj;
//.....
$(document).ready(function () {
//...
$('#saveDialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
modal: true,
buttons: {
"Save": function () {
$("#update-message").html('');
$("#savePersonForm").submit();
},
"Cancel": function () {
$(this).dialog("close");
}
}
});
//....
setLinks();
});
// ....
function setLinks()
{
$(".editLink, .newLink, uploadPicLink").unbind('click');
$(".editLink, .newLink").click
(
function ()
{
linkObj = $(this);
var dialogDiv = $('#saveDialog');
var viewUrl = linkObj.attr('href');
$.get(viewUrl, function (data)
{
dialogDiv.html(data);
//validation
var $form = $("#savePersonForm");
$form.unbind();
$form.data("validator", null);
$.validator.unobtrusive.parse(document);
$form.validate($form.data("unobtrusiveValidation").options);
dialogDiv.dialog('open');
});
return false;
}
);
//...
} //end setLinks
</script>
action Save в
PersonController следующий:C#
// ...
[HttpGet]
public ActionResult Save(int personNo)
{
Person person= new Person();
person.BirthDate = DateTime.Today;
person.PersonNo = 0;
if (personNo > 0)
{
person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
}
return PartialView(person);
}
// ...
[HttpPost]
public JsonResult Save(Person p)
{
//...
}
// ...
2) Как использовать диалог jQuery вместо JavaScript confirm или alert?
Настраиваемые окна сообщений возможны в Windows-приложениях. В вебе это возможно при использовании сторонних библиотек компонентов. Также возможно использовать диалог jQuery вместо следующих JavaScript-окон:

Ссылка Delete в view
PersonList следующая:HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo =
item.PersonNo }, new { @class = "deleteLink", @pkNo = item.PersonNo })
Код HTML и jQuery следующий:
JavaScript
<div id="confirmDialog" title="Warning"></div>
<script type="text/javascript">
//...
$(".deleteLink").live("click", function (e) {
e.preventDefault();
// ..
$("#confirmDialog").html('<br/><br/>sure?');
$("#confirmDialog").dialog({
resizable: false,
height: 200,
width: 300,
modal: true,
buttons: {
"Yes": function () {
// ..
}, // end of yes button
"No": function () {
$(this).dialog("close");
}
} //end buttons
}); //end modal
}); //end delete
//...
</script>
3) Как сделать пагинацию в списке MVC?
Пагинация - это один из хороших подходов для минимизации списка данных и затрат на передачу данных. Для отображения данных можно применить много способов. В этом "Руководстве" для пагинации используется combobox. Однако, при необходимости возможна нумерация внизу страницы. Это зависит от приложения и разработчика. Пагинацию с combobox можно разработать следующим образом.

Сначала подготавливаем место для метаданных пагинации следующим образом:
HTML
@model AddressBook_mvc3_jQuery.Models.Paginginfo
...
<div id="paginginfo">
<hr />
<select id="PageSelect"></select>
<span class="pagingPersonNo" style="visibility:hidden">@Model.id</span>
<span class="pagingTotalCount" style="visibility:hidden">@Model.TotalCount</span>
<span class="pagingPageSize" style="visibility:hidden">@Model.PageSize</span>
<span class="pagingSummary">aaa</span>
<hr/>
</div>
<div id="content"></div>
...
Когда страница загружается впервые, div с id "
paginginfo" заполняется, и с помощью следующего скрипта отображается первая страница записей.JavaScript
<script type="text/javascript">
//...
function initializePaging()
{
var PersonNo = $("#paginginfo .pagingPersonNo").text();
var TotalCount = $("#paginginfo .pagingTotalCount").text();
var PageSize = $("#paginginfo .pagingPageSize").text();
var PageSelect = $("#PageSelect");
if (TotalCount==0)
{
PageSelect.html("");
$("#paginginfo").hide();
}
else
{
PageSelect.html("");
var num = Math.ceil(TotalCount/PageSize);
for (var i = 1; i <= num; i++)
{
if (i==1)
PageSelect.append($("<option selected></option>").val(i).text(i));
else
PageSelect.append($("<option></option>").val(i).text(i));
}
}
fillData(PersonNo, 1);
}
//..
function fillData(parPersonNo, parPageNo)
{
if (parPageNo)
{
$.ajax({
type: "POST",
url: "@Url.Action("GetAddressList", "Address")",
data: { personNo: parPersonNo, pageNo: parPageNo },
cache: false,
dataType: "json",
success: function (data)
{
if (data.Html)
{
$("#content").html(data.Html);
buttonizeALL();
setLinkAbilites();
setPagingSummary(parPageNo);
}
else
{
alert('opps!');
}
},
error: function(exp)
{
alert('Error address : ' + exp.responseText);
}
}); //end ajax call
} // if (parPageNo)
}//fillData
//...
</script>
Код action в Controller следующий. Как видно, список результатов частично рендерится методом
RenderPartialView и помещается в объект JSON.C#
public class AddressController : Controller
{
//..
public JsonResult GetAddressList(int personNo, int pageNo)
{
int pageSize = 5; //it could be parameter
int skipCnt = ((pageNo - 1) * pageSize);
List<Address> list = (from x in Repository.GetAddressList() where x.PersonNo ==
personNo orderby x.AddressNo descending select x).Skip(skipCnt).Take(pageSize).ToList();
JsonResult jr = Json(new
{
Html = this.RenderPartialView("AddressList", list),
Message = "OK"
}, JsonRequestBehavior.AllowGet);
return jr;
}
//..
}
Когда
selecteditem combobox с id "PageSelect" изменяется, выполняется следующий jQuery скрипт.JavaScript
//..
$("#PageSelect").change(function ()
{
var $this = $(this);
var parPageNo = $this.val();
var parPersonNo = $("#paginginfo .pagingPersonNo").text();
fillData(parPersonNo,parPageNo);
});//PageSelect
//..
4) Как сделать ссылку "показать еще" в MVC с помощью jQuery?
Эта техника используется на многих популярных веб-сайтах. Ее нужно применять к большим спискам. "Показать еще" можно реализовать следующим образом:

В списке view есть ссылка "more".
HTML
//
<table id="NoteTable"></table>
<br />
<a href="#" style="display:none" id="more">more</a>
<div id="saveDialog" title="Notes Information"></div>
<div id="confirmDialog" title="Warning"></div>
//
Когда нажимается "more", выполняется следующий jQuery скрипт.
JavaScript
//..
//load more results
$(function ()
{
$("#more").click(function (e)
{
e.preventDefault();
var lastNoteNo = $("#NoteTable tr:last .noteNo").text();
if (lastNoteNo)
{
var PersonNo = $("#paginginfo .pagingPersonNo").text();
fillData(PersonNo, lastNoteNo);
}
//--- scroll to bottom of page ---
var $target = $('html,body');
$target.animate({scrollTop: $target.height()}, "slow");
//--- /scroll to bottom of page ---
return false;
});
});
//..
function fillData(parPersonNo, parLastNoteNo)
{
if (parPersonNo)
{
$.ajax({
type: "POST",
url: "@Url.Action("GetNoteList", "Note")",
data: { personNo: parPersonNo, lastNoteNo: parLastNoteNo} ,
cache: false,
dataType: "json",
success: function (data)
{
if (data.Html)
{
$("#NoteTable").append(data.Html);
buttonizeALL();
setLinkAbilites();
if (data.HasMore)
$("#more").show();
else
$("#more").hide();
}
else
{
alert('opps!');
}
},
error: function(exp)
{
alert('Error address : ' + exp.responseText);
}
}); //end ajax call
} // if
}//func
// ..
Следующий action в Controller возвращает результат JSON.
C#
public class NoteController : Controller
{
//...
public JsonResult GetNoteList(int personNo, int lastNoteNo)
{
int pageSize = 5; //it could be parameter
bool hasMore = false;
List<Note> list = null;
if (lastNoteNo == 0)
{
list = (from x in Repository.GetNoteList() where x.PersonNo == personNo
orderby x.NoteNo descending select x).Take(pageSize).ToList();
hasMore = (from x in Repository.GetNoteList() where x.PersonNo ==
personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
}
else
{
list = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo &&
x.PersonNo == personNo orderby x.NoteNo descending select x).Take(pageSize).ToList();
hasMore = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo &&
x.PersonNo == personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
}
JsonResult jr = Json(new
{
Html = this.RenderPartialView("_NoteList", list),
Message = "OK",
HasMore = hasMore
}, JsonRequestBehavior.AllowGet);
return jr;
}
// ...
}
5) Как использовать атрибут (attribute) со ссылкой?
Это хорошая функция, особенно для кнопок редактирования, удаления, детального просмотра и т.д.
Когда создается список, соответствующий ключ добавляется в ссылку как атрибут. В событии click ссылки этот ключ используется, и операция выполняется легко.
Например, предположим, в каждой строке списка есть ссылка удаления. Когда нажимается ссылка удаления строки, можно использовать ключ как параметр "delete action" в controller.
HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo = item.PersonNo },
new { @class = "deleteLink", @pkNo = item.PersonNo })
Когда вы проверите исходный код на клиенте, вы увидите следующую строку.
HTML
<a role="button" class="deleteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"
href="/Person/DeletePerson/1" pkno="1"><span class="ui-button-text">Delete</span></a>
В jQuery-скрипте атрибут используется следующим образом. Например, pkno используется со значением 1.
JavaScript
$(".deleteLink").live("click", function (e)
{
e.preventDefault();
var pkNo = $(this).attr("pkNo");
//..
});
6) Как сделать вызов AJAX в jQuery?
Вызов AJAX - это очень хорошая функция для ускорения приложения. В некоторых приложениях с большим объемом данных в базе данных разработчики должны обращать внимание на передачу небольшого количества данных по двум линиям данных. Первая линия - между базой данных и приложением, вторая - между приложением и браузером клиента. Вызов AJAX очень удобен для таких требований.
JavaScript
//..
$.ajax({
type: "POST",
url: "/Person/DeletePerson",
data: { personNo: pkNo },
cache: false,
dataType: "json",
success: function ()
{
//..
},
error: function (jqXHR, exception)
{
alert('Uncaught Error.\n' + jqXHR.responseText);
}
}); //end ajax call
//..
URL также можно использовать следующим образом.
JavaScript
//..
url: "@Url.Action("DeletePerson", "Person")",
// ..
7) Как использовать коллекцию Form в MVC?
Когда форма отправляется, все элементы формы отправляются в соответствующий action в controller как коллекция. В controller можно использовать каждую пару ключ-значение. Предположим, есть следующая форма сохранения:
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "saveSuccess"
}, new { @id = "saveForm" }))
{
@Html.ValidationSummary(true)
<input style="visibility:hidden" type="text" name="TBPersonNo"
id="idTBPersonNo" value="@Model.PersonNo"/>
<input style="visibility:hidden" type="text" name="TBAddressNo"
id="idTBAddressNo" value="@Model.AddressNo"/>
<br />
<fieldset>
<table>
<tr>
<td>Address Type</td>
<td>
<select name="CBAddressType" id="idCBAddressType" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>Country</td>
<td>
<select name="CBcountry" id="idCBcountry" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>City</td>
<td>
<select name="CBcity" id="idCBcity" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>AddressText</td>
<td>
<textarea rows="4" cols="25" name="TBAddressText"
id="idTBAddressText">@Model.AddressText</textarea>
</td>
</tr>
</table>
</fieldset>
}
Данные view могут быть отправлены в action в controller как объект модели или FormCollection, как показано ниже:
C#
//..
[HttpPost]
public JsonResult Save(FormCollection fc)
{
object obj = null;
Address addrTmp = new Address();
addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
addrTmp.AddressText = fc["TBAddressText"].ToString();
addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString());
if (ModelState.IsValid)
{
if (addrTmp.AddressNo == 0)
{
//find last person
//if it is database system no need to this line. Probably the AddressNo would be autoincrement
addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;
Data.Repository.GetAddressList().Add(addrTmp);
obj = new { Success = true,
Message = "Added successfully",
Object = addrTmp,
operationType = "INSERT",
Html = this.RenderPartialView("_addressLine", addrTmp )
};
}
else
{
Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
addr.AddressTypeNo = addrTmp.AddressTypeNo;
addr.AddressText = addrTmp.AddressText;
addr.CityNo = addrTmp.CityNo;
addr.PersonNo = addrTmp.PersonNo;
obj = new { Success = true,
Message = "Updated successfully",
Object = addr,
operationType = "UPDATE",
Html = this.RenderPartialView("_addressLine", addr )
};
}
}
else
{
obj = new { Success = false, Message = "Please check form" };
}
return Json(obj, JsonRequestBehavior.DenyGet);
}
//..
8) Как удалить несколько записей за раз?
На некоторых страницах удаление многих записей за раз может облегчить работу. Удаление нескольких записей возможно путем сбора ключей всех выбранных записей. После отправки всех ключей в controller удаление можно выполнить следующим образом.

Сначала нажимается кнопка "Delete Selected" с id "deleteALL". После нажатия Yes можно использовать следующий jQuery скрипт. Конечно, можно разработать альтернативные скрипты.
JavaScript
//..
$("#deleteALL").live("click", function (e)
{
e.preventDefault();
var len = $("#NoteTable tr").length;
$("#confirmDialog").html('<br/><br/>deleting all selecteds.. sure?');
$("#confirmDialog").dialog({
resizable: false,
height: 200,
width: 300,
modal: true,
buttons:
{
"Yes": function ()
{
$(this).dialog("close");
var strSelecteds = '';
var rows = $("#NoteTable tr");
for(var i=0; i< rows.length; i++)
{
var row = $(rows).eq(i);
var span = row.find('span#cboxSpan');
var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
var checked=(cb.is(':checked'));
var pkno = cb.attr("pkno");
if (checked)
{
strSelecteds = strSelecteds + pkno + ',';
}
}//
if (strSelecteds.length>0)
{
strSelecteds = strSelecteds.substring(0,strSelecteds.length-1);
}
if (strSelecteds.length>0)
{
$.ajax({
type: "POST",
url: "/Note/DeleteALL",
data: { noteNOs: strSelecteds },
cache: false,
dataType: "json",
success: function (data)
{
var strSelectedsArr = strSelecteds.split(',');
for (var i = 0; i < strSelectedsArr.length; i++)
{
var rowNo = '#row-' + strSelectedsArr[i];
$(rowNo).remove();
//alert(strSelectedsArr[i]);
}//for
$('#saveDialog').dialog('close');
$('#Message').html(data.Message);
$('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);
},
error: function(jqXHR, exception)
{
alert('Uncaught Error.\n' + jqXHR.responseText);
}
}); //end ajax call
}
else
alert('No row selected');
}, // end of yes button
"No": function ()
{
$(this).dialog("close");
}
} //end buttons
}); //end modal
}); //end deleteALL
//...
Как видно выше, удаление нескольких записей осуществляется с помощью вызова ajax к action "DeleteALL" в контроллере "Note".
9) Как использовать Partial Action в MVC?
В некоторых случаях требуется компонент, который должен использоваться во многих формах. Например, "информационное окно о человеке" может потребоваться в некоторых отдельных формах, как показано ниже.

Представление _personinfo может быть следующим.
HTML
@model AddressBook_mvc3_jQuery.Models.Person
@{ ViewBag.Title = "_personinfo"; }
<fieldset>
<legend>Person info</legend>
<table>
<tr><td><b><span> @Model.FirstName @Model.LastName </span></b>(@String.Format("{0:dd.MM.yyyy}",
Model.BirthDate))</td><td>(@Model.CategoryName)</td></tr>
</table>
</fieldset>
Для использования частичного действия в любом представлении можно использовать следующую строку кода.
HTML
//..
<h2>Address List</h2>
<div>
@Html.Action("_personinfo", "Common")
</div>
//..
10) Как использовать формат JSON в приложении MVC?
Формат JSON может использоваться при отправке параметров в action в контроллере и при получении результатов из action. Как показано ниже, action DeleteNote в контроллере Note имеет параметр noteNo. Здесь pkNo - это параметр, вызываемый со значением.
JavaScript
$(".deleteLink").live("click", function (e)
{
e.preventDefault();
var pkNo = $(this).attr("pkNo");
//..
$.ajax({
type: "POST",
url: "/Note/DeleteNote",
data: { noteNo: pkNo },
cache: false,
dataType: "json",
success: function ()
{
$(rowNo).remove();
},
error: function(jqXHR, exception)
{
alert('Uncaught Error.\n' + jqXHR.responseText);
}
}); //end ajax call
//..
}); //end delete
Из action в контроллере можно получить результат JSON. Следующий скрипт возвращает результат в виде объекта json.
C#
//..
[HttpPost]
public JsonResult DeleteNote(int noteNo)
{
string message = string.Empty;
try
{
Note n = Data.Repository.GetNoteList().Where(c => c.NoteNo == noteNo).FirstOrDefault();
if (n != null)
{
Data.Repository.GetNoteList().Remove(n);
message = "Deleted";
}
else
{
message = "Note not found!";
}
}
catch (Exception ex)
{
message = ex.Message;
}
return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
}
//..
11) Как заполнить master-detail combobox?
На некоторых формах при изменении одного combobox нужно заполнить другой. Например, для пары страна-город можно считать страну master, а город - detail.

HTML view "формы сохранения" следующий.
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "saveSuccess"
}, new { @id = "saveForm" }))
{
@Html.ValidationSummary(true)
<input style="visibility:hidden" type="text" name="TBPersonNo"
id="idTBPersonNo" value="@Model.PersonNo"/>
<input style="visibility:hidden" type="text" name="TBAddressNo"
id="idTBAddressNo" value="@Model.AddressNo"/>
<br />
<fieldset>
<table>
<tr>
<td>Address Type</td>
<td>
<select name="CBAddressType" id="idCBAddressType" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>Country</td>
<td>
<select name="CBcountry" id="idCBcountry" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>City</td>
<td>
<select name="CBcity" id="idCBcity" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>AddressText</td>
<td>
<textarea rows="4" cols="25" name="TBAddressText"
id="idTBAddressText">@Model.AddressText</textarea>
</td>
</tr>
</table>
</fieldset>
}
При первой загрузке combobox idCBCountry заполняется с использованием action "GetCountryList" в контроллере Address. Затем, когда combobox страны изменяется, combobox города заполняется следующим образом.
JavaScript
<script type="text/javascript">
$(document).ready(function () {
//...
//-----------------------------------------------------
$.ajax({
type: "POST",
url: "@Url.Action("GetCountryList", "Address")",
data: {},
cache: false,
dataType: "json",
success: function (data)
{
var idCBcountry = $("#idCBcountry");
idCBcountry.html("");
if (@Model.AddressNo>0)
{
for (var i = 0; i < data.List.length; i++)
{
var item = data.List[i];
if (item.CountryNo == @Model.CountryNo)
{
idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
fillCity(item.CountryNo);
}
else
{
idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
}
} //for
}
else
{
for (var i = 0; i < data.List.length; i++)
{
var item = data.List[i];
if (i==0)
{
idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
fillCity(item.CountryNo);
}
else
{
idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
}
} //for
}//else
},
error: function(exp)
{
alert('ErrorCountry : ' + exp.responseText);
}
});
//-----------------------------------------------------
$("#idCBcountry").change(function () {
var $this = $(this);
var CountryNo = $this.val();
if (CountryNo)
{
fillCity(CountryNo);
}//if
});
//-----------------------------------------------------
});//end of function
function fillCity(parCountryNo)
{
$.ajax({
type: "POST",
url: "@Url.Action("GetCityList", "Address")",
data: {CountryNo: parCountryNo},
cache: false,
dataType: "json",
success: function (data)
{
var idCBcity = $("#idCBcity");
idCBcity.html("");
for (var i = 0; i < data.List.length; i++)
{
var item = data.List[i];
if (item.CityNo == @Model.CityNo)
{
idCBcity.append($("<option selected></option>").val(item.CityNo).text(item.CityName));
}
else
{
idCBcity.append($("<option />").val(item.CityNo).text(item.CityName));
}
}
},
error: function(exp)
{
alert('ErrorCity : ' + exp.responseText);
}
});
}//fillCity
</script>
Коды action следующие. Списки встроены в объект json. Затем, в скрипте jQuery, показанном выше, элементы списка используются по индексу.
C#
public class AddressController : Controller
{
//..
public JsonResult GetCountryList()
{
object obj = null;
List<Country> list = Repository.GetCountryList();
obj = new { Success = true, Message = "OK", List = list };
return Json(obj, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCityList(int CountryNo)
{
object obj = null;
List<City> list = Repository.GetCityList().Where(c => c.CountryNo == CountryNo).ToList(); ;
obj = new { Success = true, Message = "OK", List = list };
return Json(obj, JsonRequestBehavior.AllowGet);
}
//..
}
Эту технику можно использовать для любого html-элемента в форме view.
12) Как использовать jQuery datepicker?
Тип даты используется почти во всех бизнес-приложениях. Из-за культурных различий использование этого типа может создавать проблемы для разработчика. Однако jQuery datepicker упрощает использование типа даты.

Для отображения даты в желаемом формате в списке можно использовать следующую строку.
HTML
<span class="BirthDate"> @String.Format("{0:dd.MM.yyyy}", item.BirthDate) </span>
В форме сохранения используется следующий html-скрипт.
HTML
...
<div class="editor-label">
@Html.LabelFor(model => model.BirthDate)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.BirthDate,
new { @class = "BirthDateSave",
@id = "TBBirthDate",
@Value = Model.BirthDate.ToString("dd.MM.yyyy")
})
</div>
...
jQuery Datepicker может работать с @Html.TextboxFor со следующим скриптом на той же странице.
JavaScript
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$(".BirthDateSave").datepicker({
changeMonth: true,
changeYear: true,
dateFormat: 'dd.mm.yy',
showOn: 'both'
});
});
</script>
Следующие строки должны быть включены в начале соответствующего .cshtml.
HTML
..
<link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
..
13) Как загрузить изображение в MVC с помощью jQuery dialog?
Изображение можно легко загрузить в отдельном представлении. Однако перенаправление в отдельное представление только для загрузки изображения, а затем обратно в представление списка может быть неэффективным с точки зрения затрат. Вместо этого, в представлении списка, при нажатии на ссылку загрузки в каждой строке, можно открыть диалоговое окно jQuery, просмотреть и загрузить изображение.

При нажатии "Upload Pic" выполняется следующий скрипт.
JavaScript
//..
$(".uploadPicLink").click
(
function ()
{
linkObj = $(this);
var dialogDiv = $('#savePicDialog');
var viewUrl = linkObj.attr('href');
$.get(viewUrl, function (data) {
dialogDiv.html(data);
//validation
var $form = $("#savePersonPicForm");
$form.unbind();
$form.data("validator", null);
$.validator.unobtrusive.parse(document);
$form.validate($form.data("unobtrusiveValidation").options);
dialogDiv.dialog('open');
});
return false;
}
);
//..
Форма SavePersonPic, загруженная в jQuery dialog, выглядит следующим образом. Для загрузки файла в jQuery dialog используется iframe.
HTML
@model AddressBook_mvc3_jQuery.Models.Person
@{ViewBag.Title = "Save image";}
@using (Html.BeginForm("SavePersonPic", "Person", FormMethod.Post,
new
{
enctype = "multipart/form-data",
id = "savePersonPicForm",
name = "savePersonPicForm",
target = "UploadTarget"
}))
{
@Html.ValidationSummary(true)
<div id="update-message" class="error invisible"></div>
<fieldset>
<legend>Person Picture</legend>
<div class="editor-label">
<label for="file">Upload Image:</label>
</div>
<div class="editor-field">
<input type="file" name="file" id="file"/>
</div>
</fieldset>
}
<iframe id="UploadTarget"
name="UploadTarget" onload="UploadImage_Complete();"
style="position: absolute; left: -999em; top: -999em;">
</iframe>
Action для загрузки файла в контроллере:
C#
public class PersonController : Controller
{
//..
//-------------- image -----
[HttpGet]
public ActionResult SavePersonPic(int personNo)
{
Person person = new Person();
if (personNo > 0)
{
person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
}
return PartialView(person);
}
[HttpPost]
public JsonResult SavePersonPic(HttpPostedFileBase file, int personNo)
{
string message = string.Empty;
bool success = false;
string imgPath = "";
string fileName = "";
try
{
string path = System.IO.Path.Combine(Server.MapPath("~/Content/images"),
System.IO.Path.GetFileName(file.FileName));
file.SaveAs(path);
Person p = Data.Repository.GetPersonList().Where(r => r.PersonNo == personNo).FirstOrDefault();
p.imgFileName = file.FileName;
ViewBag.Message = "File uploaded successfully";
message = ViewBag.Message;
fileName = file.FileName;
imgPath = Url.Content(String.Format("~/Content/images/{0}", fileName));
success = true;
}
catch (Exception ex)
{
message = ex.Message;
success = true;
imgPath = "";
fileName = "";
}
return Json(
new { Success = success,
Message = message,
PersonNo=personNo,
ImagePath = imgPath,
FileName = fileName
},
JsonRequestBehavior.AllowGet
);
}
//------------- /image --------
// ..
}
Функция JavaScript "onload" iframe'а следующая. Загруженное изображение отображается в соответствующей строке списка без обновления строки.
JavaScript
//..
function UploadImage_Complete()
{
//Check first load of the iFrame
if (isFirstLoad == true)
{
isFirstLoad = false;
return;
}
try
{
//Reset the image form
document.getElementById("savePersonPicForm").reset();
var jsonTxt = ($('#UploadTarget').contents()).text();
var jsonObj = JSON.parse(jsonTxt);
var rowid = '#row-' + jsonObj.PersonNo;
var row = $('#personTable ' + rowid);
var imgid = "#img-" + jsonObj.PersonNo;
var img = row.find(imgid);
$(img).attr("src", jsonObj.ImagePath);
$('#Message').html(jsonObj.Message);
$('#Message').delay(300).slideDown(300).delay(1000).slideUp(300)
$('#savePicDialog').dialog('close');
}
catch (err)
{
alert(err.get_Message());
}
}
//..
14) Как создать строку таблицы на стороне клиента?
Запись, добавленная в базу данных, должна быть отображена в списке на стороне клиента. Это можно сделать несколькими способами. После добавления записи список может быть полностью обновлен из базы данных, но это будет тяжелой операцией. Однако, используя javascript или jquery, новую строку можно добавить в представление без обновления всех элементов в представлении. Здесь упоминаются два способа.
Во-первых, строка и ее ячейки создаются по отдельности с помощью javascript, как показано ниже. Как видно из следующих скриптов, функция JavaScript saveSuccess используется для такого сценария после отправки этой формы.
HTML
..
@model AddressBook_mvc3_jQuery.Models.Person
@{ ViewBag.Title = "Save Person"; }
..
@using (Ajax.BeginForm("Save", "Person", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "saveSuccess"
}, new { @id = "savePersonForm" }))
{
@Html.ValidationSummary(true)
..
}
..
Метод JavaScript saveSuccess следующий. Action возвращает результат json, содержащий тип операции. В зависимости от операции, то есть INSERT или UPDATE, таблица в представлении изменяется. Когда в базу данных добавляется новая запись, в таблицу добавляется новая строка (prepend). Когда существующая запись в базе данных обновляется, изменяется только соответствующая строка в таблице.
JavaScript
function saveSuccess(data)
{
if (data.Success == true)
{
if (data.operationType == 'UPDATE')
{
//we update the table's row info
var parent = linkObj.closest("tr");
$(parent).animate({ opacity: 0.3 }, 200, function ()
{;});
parent.find(".FirstName").html(data.Object.FirstName);
parent.find(".LastName").html(data.Object.LastName);
parent.find(".CategoryName").html(data.Object.CategoryName);
var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
var dateStr = FormatDate(date);
parent.find(".BirthDate").html(dateStr);
$(parent).animate({ opacity: 1.0 }, 200, function () {
;
});
}
else
{ //INSERT
//we add the new row to table
//we do not refresh all records on screen
try
{
var personTable = document.getElementById("personTable");
var row = personTable.insertRow(1); //row 0 is header
row.setAttribute("id", 'row-' + data.Object.PersonNo.toString());
var buttonsLinks =
'<a role="button" class="editLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only ui-state-hover ui-state-focus" href="/Person/Save/' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Edit</span></a> ' +
'<a role="button" class="adressLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Address/Index/' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Addresses</span></a> ' +
'<a role="button" class="noteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Note/Index/' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Notes</span></a> ' +
'<a role="button" class="deleteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="/Person/Delete/' + data.Object.PersonNo.toString() + '" pkno="' + data.Object.PersonNo.toString() + '"><span class="ui-button-text">Delete</span></a>';
var cellButtons = row.insertCell(0);
cellButtons.innerHTML = buttonsLinks;
var cellPersonNo = row.insertCell(1);
cellPersonNo.innerHTML = "<span class=\"PersonNo\">" + data.Object.PersonNo + "</span>";
var cellCategoryName = row.insertCell(2);
cellCategoryName.innerHTML = "<span class=\"CategoryName\">" + data.Object.CategoryName + "</span>";
var cellFN = row.insertCell(3);
cellFN.innerHTML = "<span class=\"FirstName\">" + data.Object.FirstName + "</span>";
var cellLN= row.insertCell(4);
cellLN.innerHTML = "<span class=\"LastName\">" + data.Object.LastName + "</span>";
var cellBirthDate = row.insertCell(5);
var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
var dateStr = FormatDate(date);
cellBirthDate.innerHTML = "<span class=\"BirthDate\">" + dateStr + "</span>";
var cellimgFileName = row.insertCell(6);
cellimgFileName.innerHTML =
"<img id=\"img-" + data.Object.PersonNo.toString() + "\" alt=\"" + data.Object.ImgFileName + "\" src=\"/content/images/" + "noimg.jpg" + "\" height=\"35px\" width=\"50px\"><br><a class=\"uploadPicLink\" href=\"/Person/SavePersonPic/" + data.Object.PersonNo.toString() + "\" pkno=\"" + data.Object.PersonNo.toString() + "\" style=\"font-size:9px;\">Upload Pic</a>";
setLinks();
}
catch (err) {
alert(err.Message);
}
}
$('#saveDialog').dialog('close');
$('#Message').html(data.Message);
$('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);
}
else {
$("#update-message").html(data.ErrorMessage);
$("#update-message").show();
}
}
Первый способ, упомянутый выше, может показаться устаревшим. Поэтому второй способ, описанный ниже, может быть более применимым. В этом способе для добавления или обновления строк в таблице используется отрендеренный html. Предположим, есть следующая таблица.
HTML
@model IEnumerable<AddressBook_mvc3_jQuery.Models.Address>
<table id="AddressTable">
<tr>
<th></th>
<th>
#
</th>
<th>
AddressType
</th>
<th>
City/Country
</th>
<th>
Address Text
</th>
</tr>
@foreach (var item in Model)
{
<tr id="row-@item.AddressNo">
<td>
@Html.ActionLink("Edit", "Save",
new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
@Html.ActionLink("Delete", "DeleteAddress",
new { addressNo = item.AddressNo }, new { @class = "deleteLink", @pkNo = item.AddressNo })
</td>
<td>
<span class="AddressNo">@item.AddressNo</span>
</td>
<td>
<span class="AddressTypeName">@item.AddressTypeName</span>
</td>
<td>
<span class="CityName">@item.CityName/@item.CountryName</span>
</td>
<td>
<span class="AddressText">@item.AddressText</span>
</td>
</tr>
}
</table>
При нажатии "new" следующий скрипт загружается в jQuery dialog.
HTML
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "saveSuccess"
}, new { @id = "saveForm" }))
{
@Html.ValidationSummary(true)
<input style="visibility:hidden" type="text"
name="TBPersonNo" id="idTBPersonNo" value="@Model.PersonNo"/>
<input style="visibility:hidden" type="text"
name="TBAddressNo" id="idTBAddressNo" value="@Model.AddressNo"/>
<br />
<fieldset>
<table>
<tr>
<td>Address Type</td>
<td>
<select name="CBAddressType" id="idCBAddressType" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>Country</td>
<td>
<select name="CBcountry" id="idCBcountry" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>City</td>
<td>
<select name="CBcity" id="idCBcity" style="width:120px">
</select>
</td>
</tr>
<tr>
<td>AddressText</td>
<td>
<textarea rows="4" cols="25" name="TBAddressText"
id="idTBAddressText">@Model.AddressText</textarea>
</td>
</tr>
</table>
</fieldset>
}
Когда форма отправляется, выполняется следующий action в контроллере.
C#
public class AddressController : Controller
{
//..
[HttpPost]
public JsonResult Save(FormCollection fc)
{
object obj = null;
Address addrTmp = new Address();
addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
addrTmp.AddressText = fc["TBAddressText"].ToString();
addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString());
if (ModelState.IsValid)
{
if (addrTmp.AddressNo == 0)
{
//find last person
//if it is database system no need to this line. Probably the AddressNo would be autoincrement
addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;
Data.Repository.GetAddressList().Add(addrTmp);
obj = new { Success = true,
Message = "Added successfully",
Object = addrTmp,
operationType = "INSERT",
Html = this.RenderPartialView("_addressLine", addrTmp )
};
}
else
{
Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
addr.AddressTypeNo = addrTmp.AddressTypeNo;
addr.AddressText = addrTmp.AddressText;
addr.CityNo = addrTmp.CityNo;
addr.PersonNo = addrTmp.PersonNo;
obj = new { Success = true,
Message = "Updated successfully",
Object = addr,
operationType = "UPDATE",
Html = this.RenderPartialView("_addressLine", addr )
};
}
}
else
{
obj = new { Success = false, Message = "Please check form" };
}
return Json(obj, JsonRequestBehavior.DenyGet);
}
// ..
}
Для получения желаемого html-скрипта используется метод RenderPartialView.
C#
//..
public static string RenderPartialView(this Controller controller, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
controller.ViewData.Model = model;
using (var sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
var viewContext = new ViewContext(controller.ControllerContext,
viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
//..
Функция saveSuccess ajax-поста из формы saveAddress выглядит следующим образом:
JavaScript
<script type="text/javascript">
//...
function saveSuccess(data)
{
if (data.Success == true)
{
$("#paginginfo").show();
if (data.operationType == 'UPDATE')
{
var row = linkObj.closest("tr");
// the following line can also be used to get related row
//$('#AddressTable #row-' + data.Object.AddressNo);
row.replaceWith(data.Html);
//..
}
else
{ //INSERT
try
{
$("#AddressTable tr:first").after(data.Html);
//..
}
catch (err)
{
alert(err.Message);
}
}
//..
}
else
{
//..
}
}
//..
</script>
Можно использовать любой из двух описанных выше методов.
15) Как настроить mapRoute в Global.asax?
В классическом приложении asp.net операции urlRewrite легко выполнялись с помощью некоторых сторонних сборок. В приложении MVC можно настроить mapRoute с помощью Global.asax.
Следующий mapRoute является стандартным в Global.asax:
C#
public class MvcApplication : System.Web.HttpApplication
{
//..
public static void RegisterRoutes(RouteCollection routes)
{
// all new customized maproute rules can be put here
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
// ..
}
Согласно следующему скрипту,
**/Save/{addressNo}/{personNo}** используется как ссылка.HTML
@Html.ActionLink("Edit", "Save",
new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
Скриншот вышеуказанной ссылки ниже.

Поэтому можно добавить настраиваемое правило mapRoute в Global.asax следующим образом.
C#
//..
routes.MapRoute(
"AddressSave",
"Address/Save/{addressNo}/{personNo}",
new { controller = "Address", action = "Save",
addressNo = UrlParameter.Optional, personNo = UrlParameter.Optional }
);
//..
Можно использовать любой из двух описанных выше методов.
16) Как отметить все строки таблицы и снять отметку со всех строк таблицы?
Во многих приложениях может потребоваться отметить все флажки в таблице или снять отметку со всех флажков за один раз.

Для такой функции можно использовать следующий скрипт.
HTML
..
<br />
| <a href="#" class="checkALLRecords" id="checkALL">Check ALL</a> | <a href="#" class="unCheckALLRecords" id="unCheckALL">Uncheck ALL</a> |
<br />
..
<table id="NoteTable"></table>
..
JavaScript
//..
//check ALL records
$("#checkALL").live("click", function (e)
{
e.preventDefault();
CheckALL(true);
});
//uncheck ALL records
$("#unCheckALL").live("click", function (e)
{
e.preventDefault();
CheckALL(false);
});
//..
function CheckALL(state)
{
var rows = $("#NoteTable tr");
for(var i=0; i< rows.length; i++)
{
var row = $(rows).eq(i);
var span = row.find('span#cboxSpan');
var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
if (state==true)
cb.attr('checked',true);
else
cb.attr('checked',false);
}
}
//..
17) Как сделать "Загрузка данных"?
При загрузке нескольких строк данных пользователям должно отображаться сообщение "loading data".

Следующий div может быть настроен в соответствии с требуемым сообщением.
HTML
..
<div id="loadMessage"></div>
..
Для настройки области div можно использовать следующую функцию javascript.
JavaScript
..
function showLoader(root, txt) {
$("#loadMessage").html("");
$("#loadMessage").show();
var loader = '<img src="' + root + '/ajax-loader.gif" align="absmiddle">&nbsp;<span><br/>' + txt + '...</span>';
$("#loadMessage").fadeIn(100).html(loader);
}
function hideLoader() {
$("#loadMessage").hide();
}
..
18) Как сделать master-detail сетки с jQuery?
При нажатии на мастер-строку, детальные строки отображаются под мастер-сеткой, как показано ниже.

В качестве сеток используются следующие таблицы.
HTML
..
<table id="CountryTable" class="hovertable2"></table>
<br />
<br />
<table id="CityTable" class="hovertable"></table>
..
Для имитации подхода master-detail используются следующие функции javascript.
JavaScript
..
function setTableRowClick()
{
$("#CountryTable tr td.clickable").unbind('click');
$('#CountryTable tr td.clickable').click(function ()
{
var row = $(this).parent();
setRow(row);
});
//-------------
}//func
function setRow(row)
{
var rowid = row.attr('id'); //current
var higlightedCountryTableRowid = $("#pageinfo .higlightedCountryTableRowid").text();
$("#pageinfo .higlightedCountryTableRowid").html(rowid.toString());
if ((rowid==0) || (rowid!=higlightedCountryTableRowid))
{
//------
row.siblings().removeClass('diffColor');
row.addClass("diffColor");
//-------
fillCityData(rowid);
}
}
..
function fillCountryData()
{
$.ajax({
type: "POST",
url: "@Url.Action("GetCountryList", "Country")",
data: {},
cache: false,
dataType: "json",
success: function (data)
{
if (data.Html)
{
$("#CountryTable").html(data.Html);
buttonizeALL();
setLinkAbilitesCountry();
setLinkAbilitesCity();
setTableRowClick();
}
else
{
alert('opps-- country list error!');
}
},
error: function(exp)
{
alert('Error address : ' + exp.responseText);
}
}); //end ajax call
}//func
function fillCityData(parCountryNo)
{
$.ajax({
type: "POST",
url: "@Url.Action("GetCityList", "Country")",
data: { countryNo: parCountryNo},
cache: false,
dataType: "json",
success: function (data)
{
if (data.Html)
{
$("#CityTable").html(data.Html);
buttonizeALL();
setLinkAbilitesCity();
setTableRowClick();
}
else
{
alert('opps-- city list error!');
}
},
error: function(exp)
{
alert('Error address : ' + exp.responseText);
}
}); //end ajax call
}//func
..
Заключение
Надеюсь, эта статья оказалась полезной.
Услуги облачных вычислений
Мы предоставляем услуги по проектированию инфраструктуры, миграции, управлению и оптимизации на платформах AWS, Azure и Google Cloud.
Изучить наши услугиСвяжитесь с нами
Поговорите с нашей командой, чтобы узнать больше о наших решениях AWS и облачных вычислений.
Контакт