Série Como Fazer sobre MVC, jQuery, JSON, Paginação e mapRoute

Baixar Código Fonte
Introdução
Devido à grande quantidade de dados nos sistemas de banco de dados, o trabalho do lado do cliente tornou-se muito importante. Na abordagem code-behind com ASP.NET clássico, o método natural é codificar a maior parte do trabalho em arquivos code-behind usando componentes ASP.NET. Além disso, a renderização de componentes ASP.NET e o mecanismo viewstate são agora considerados capacidades fracas do ASP.NET clássico.
Por isso, um novo paradigma surgiu. De acordo com este novo paradigma, o desenvolvedor pode trabalhar com HTML puro e JavaScript sem viewstate que reduz o desempenho e com menos renderização.
Embora o MVC seja conhecido como um padrão de design ou arquitetura antigo, tornou-se popular especialmente após os gargalos do ASP.NET clássico mencionados acima. Aplicações de alto desempenho podem ser desenvolvidas em MVC onde jQuery e JSON são usados efetivamente.
Conhecimento Prévio
Este artigo pode ser útil após ler alguns artigos de nível iniciante sobre MVC, jQuery e JSON. Os seguintes links podem ser úteis para iniciantes:
Usando o Código
Neste artigo, uma "série como fazer" foi objetivada. Portanto, todos os scripts foram dados a partir do código fonte anexado. Na verdade, cada "como fazer" poderia ser um artigo separado. De qualquer forma, todas as respostas possíveis foram reunidas em um único exemplo. Neste artigo, há mais abordagens práticas do que informações teóricas. Por exemplo, algumas listas estáticas foram usadas em vez de banco de dados para simplicidade.
As seguintes perguntas são respondidas:
- Como fazer CRUD em MVC com bom desempenho?
- Como usar diálogo jQuery em vez de confirm ou alert JavaScript?
- Como fazer paginação em lista MVC?
- Como fazer link "mostrar mais" em MVC usando jQuery?
- Como usar atributo com link?
- Como fazer chamada AJAX em jQuery?
- Como usar coleção de formulário em MVC?
- Como excluir vários registros de uma vez?
- Como usar partial action em MVC?
- Como usar formato JSON em aplicação MVC?
- Como preencher combobox master-detail?
- Como usar jQuery datepicker?
- Como fazer upload de imagem em MVC com diálogo jQuery?
- Como criar linha de tabela no lado do cliente?
- Como personalizar mapRoute em Global.asax?
- Como checkALL e uncheckALL todas as linhas da tabela?
- Como fazer "Loading Data"?
- Como fazer grids master-detail com jQuery?
1) Como fazer CRUD em MVC com bom desempenho?
Pensando grosseiramente, todas as soluções de negócios têm a característica Create-Read-Update-Delete (Criar-Ler-Atualizar-Excluir). Se possível, usar o mesmo "formulário de salvamento" tanto para "insert" quanto para "update" pode ser eficiente em termos de custo para o desenvolvedor. Usar o mesmo formulário é possível gerenciando os parâmetros enviados para a action.
Suponha que você tenha uma lista tipo grid (na verdade uma tabela HTML) no formulário e um botão "new" separado. Cada linha da tabela tem um botão "edit" e "delete" relacionado àquela linha.
Redirecionar para uma nova página - aqui chamada de view - após clicar em "New" não é uma forma eficiente. Porque após os dados serem salvos na página redirecionada, o usuário precisa clicar em "mostrar lista" para ver os dados adicionados ao banco de dados. Isso significa redirecionar para a view de lista e selecionar dados do banco de dados com custo de seleção de variável!
Em vez do cenário "clique em new e liste novamente" expresso acima, uma forma melhor pode ser implementada.
Create (Criar):
- Na view de lista, um "jQuery Save dialog" pode aparecer após clicar em "New".
- A view Create é renderizada no diálogo jQuery.
- O formulário Create é preenchido e "Save" é pressionado.
- No momento em que o botão Save é pressionado, os dados podem ser enviados para o controller relacionado via AJAX post.
- O formulário Ajax tem a função JavaScript
onSuccess. - No método JavaScript "
onSuccess", a nova linha adicionada, o JSON que vem como parâmetro para "onSuccess", é adicionada (prepend) ao início da lista sem atualizar toda a lista.
Read (Ler):
Esta é uma operação de listagem. Se possível, apenas os dados necessários devem ser mostrados no formulário de lista. As seguintes técnicas podem ser usadas:
- paginação com combobox ou números,
- implementação de "mostrar mais",
- listagem com filtragem.
Update (Atualizar):
- Na view de lista, após clicar em "Edit" em qualquer linha da lista, o mesmo "jQuery Save dialog" pode aparecer com os dados da linha selecionada.
- Como todos os passos são os mesmos que "Create", apenas o método "
onSuccess" é alterado de acordo com a operação "update". - Neste caso, após a atualização do banco de dados, apenas os dados na linha editada são atualizados na view. Desta forma, não há necessidade de atualizar toda a lista para ver o último registro editado.
Delete (Excluir):
- Após confirmação com um diálogo jQuery de boa aparência, após a operação de exclusão do banco de dados, apenas a linha selecionada é removida da lista. Novamente, não há necessidade de atualizar toda a lista.
O mesmo diálogo é usado tanto para insert quanto para edit.

Os links na view PersonList.cshtml são os seguintes:
HTML
@Html.ActionLink("New", "Save",
new { personNo = 0 }, new { @class = "newLink" })
...
@Html.ActionLink("Edit", "Save", new { personNo = item.PersonNo }, new { @class = "editLink" })
- New: Texto a ser exibido.
- Save: A action no Controller.
- personNo: O parâmetro enviado para a action "Save". Se for 0, o diálogo abre vazio, se for maior que 0, os dados desse id são mostrados no diálogo.
- newLink: className fictício a ser usado no jQuery abaixo.
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>
A action Save no
PersonController é a seguinte: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) Como usar diálogo jQuery em vez de confirm ou alert JavaScript?
A caixa de mensagem personalizada é possível em aplicação Windows. Para web, é possível quando uma biblioteca de componentes de terceiros é usada. Também é possível usar diálogo jQuery em vez de caixas JavaScript como abaixo:

O link Delete na view
PersonList é o seguinte:HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo =
item.PersonNo }, new { @class = "deleteLink", @pkNo = item.PersonNo })
O código HTML e jQuery é o seguinte:
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) Como fazer paginação em lista MVC?
A paginação é uma das boas abordagens para listar e minimizar o custo de transferência de dados. Muitas formas de exibir dados podem ser implementadas. Neste "como fazer", um combobox foi usado para paginação. No entanto, a numeração na parte inferior da página também é possível se desejado. Isso depende da aplicação e do desenvolvedor. A paginação com combobox pode ser desenvolvida como segue.

Primeiro, o local para metadados de paginação é organizado como segue:
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>
...
Quando a página é carregada pela primeira vez, a div com id "
paginginfo" é preenchida e a primeira página de registros é mostrada usando os seguintes scripts.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>
O código da action no Controller é o seguinte. Como visto, a lista de resultados é parcialmente renderizada usando o método
RenderPartialView e colocada no objeto 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;
}
//..
}
Quando o
selecteditem do combo com id "PageSelect" é alterado, o seguinte script jQuery é executado.JavaScript
//..
$("#PageSelect").change(function ()
{
var $this = $(this);
var parPageNo = $this.val();
var parPersonNo = $("#paginginfo .pagingPersonNo").text();
fillData(parPersonNo,parPageNo);
});//PageSelect
//..
4) Como fazer link "mostrar mais" em MVC usando jQuery?
Esta técnica é usada em muitos sites populares. Deve ser aplicada em grandes listas. "Mostrar mais" pode ser realizado como segue:

Na view de lista, há um link para "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>
//
Quando "more" é clicado, o seguinte script jQuery é executado.
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
// ..
A seguinte action no Controller retorna o resultado 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) Como usar atributo com link?
Esta é uma boa capacidade para usar especialmente para botões como edit, delete, show detail.
Ao criar a lista, a chave relacionada é adicionada ao link como um atributo. No evento click do link, essa chave é usada e a operação é feita facilmente.
Por exemplo, suponha que cada linha de uma lista tenha um link delete. Quando o link delete na linha é clicado, é possível usar a chave como parâmetro para a "delete action" no controller.
HTML
@Html.ActionLink("Delete", "DeletePerson", new { personNo = item.PersonNo },
new { @class = "deleteLink", @pkNo = item.PersonNo })
Quando o código fonte é verificado no cliente, a seguinte linha é vista.
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>
No script jQuery, os atributos são usados como segue. Por exemplo, pkno é 1 e é usado.
JavaScript
$(".deleteLink").live("click", function (e)
{
e.preventDefault();
var pkNo = $(this).attr("pkNo");
//..
});
6) Como fazer chamada AJAX em jQuery?
A chamada AJAX é uma capacidade muito boa para tornar uma aplicação mais rápida. Em algumas aplicações com grande quantidade de dados no banco de dados, o desenvolvedor deve prestar atenção à baixa quantidade de transferência de dados em duas linhas de dados. A primeira linha é entre o banco de dados e a aplicação, a segunda é entre a aplicação e o navegador do cliente. Para tais requisitos, a chamada AJAX é muito útil.
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
//..
A URL também pode ser usada como segue.
JavaScript
//..
url: "@Url.Action("DeletePerson", "Person")",
// ..
7) Como usar coleção de formulário em MVC?
Quando um formulário é postado, todos os elementos do formulário são enviados como uma coleção para a action relacionada no controller. No Controller, cada par chave-valor pode ser usado. Suponha que você tenha um formulário de salvamento como abaixo:
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>
}
Os dados na view podem ser enviados para a action no controller como um objeto model ou como FormCollection como mostrado abaixo:
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)
{
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) Como excluir vários registros de uma vez?
Em algumas páginas, às vezes excluir muitos registros de uma vez facilita o trabalho. Excluir vários registros é possível coletando as chaves de todos os registros selecionados. Após todas as chaves serem enviadas para o controller, a exclusão pode ser realizada como segue.

Primeiro, o botão "Delete Selected" com id "deleteALL" é clicado. Após pressionar Yes, o seguinte script jQuery pode ser usado. Claro, scripts alternativos também podem ser desenvolvidos.
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();
}//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
//...
Como visto acima, a exclusão de muitos registros é feita com uma chamada ajax para a action "DeleteALL" no controller "Note".
9) Como usar Partial Action em MVC?
Em alguns casos, é necessário um componente que deve ser usado em muitos formulários. Por exemplo, uma "caixa de informações de pessoa" pode ser necessária em alguns formulários separados como mostrado abaixo.

A view _personinfo pode ser como segue.
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>
Para usar partial action em qualquer view, a seguinte linha de código pode ser usada.
HTML
//..
<h2>Address List</h2>
<div>
@Html.Action("_personinfo", "Common")
</div>
//..
10) Como usar formato JSON em aplicação MVC?
O formato JSON pode ser usado ao enviar parâmetros para uma action no controller e ao obter resultados de uma action. Como mostrado abaixo, a action DeleteNote no controller Note tem o parâmetro noteNo. Aqui pkNo é um parâmetro chamado com valor.
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
É possível obter o resultado JSON da action no Controller. O seguinte script retorna o resultado como um objeto 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) Como preencher combobox master-detail?
Alguns formulários requerem preencher um combobox quando outro é alterado. Por exemplo, para um par país-cidade, o país pode ser considerado como master e a cidade como detail.

O html na view do "formulário de salvamento" é o seguinte.
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>
}
No primeiro carregamento, o combobox idCBCountry é preenchido usando a action "GetCountryList" no controller Address. Depois, quando o combobox de país é alterado, o combobox de cidade é preenchido como segue.
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>
Os códigos da action são os seguintes. As listas são incorporadas no objeto json. Depois, no script jQuery mostrado acima, os elementos da lista são usados com index.
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);
}
//..
}
Esta técnica pode ser usada para qualquer elemento html no formulário da view.
12) Como usar jQuery datepicker?
O tipo de data é usado em quase todas as aplicações de negócios. Devido à diferença de culturas, às vezes usar esse tipo significa problema para o desenvolvedor. No entanto, o jQuery datepicker facilita o uso do tipo de data.

Para mostrar a data no formato desejado na lista, a seguinte linha pode ser usada.
HTML
<span class="BirthDate"> @String.Format("{0:dd.MM.yyyy}", item.BirthDate) </span>
No formulário de salvamento, o seguinte script html é usado.
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>
...
O jQuery Datepicker pode funcionar com @Html.TextboxFor na mesma página com o seguinte script.
JavaScript
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$(".BirthDateSave").datepicker({
changeMonth: true,
changeYear: true,
dateFormat: 'dd.mm.yy',
showOn: 'both'
});
});
</script>
As seguintes linhas devem ser incluídas no início do .cshtml apropriado.
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) Como fazer upload de imagem em MVC com diálogo jQuery?
Uma imagem pode ser facilmente carregada em uma view separada. No entanto, redirecionar para uma view separada apenas para carregar uma imagem e depois redirecionar para a view de lista pode ser ineficiente em termos de custo. Em vez disso, na view de lista, clicando no link de upload em cada linha, um diálogo jQuery pode ser aberto, uma imagem pode ser navegada e carregada.

Quando "Upload Pic" é clicado, o seguinte script é executado.
JavaScript
//..
$(".uploadPicLink").live("click", function (e) {
e.preventDefault();
linkObj = $(this);
var dialogDiv = $('#savePicDialog');
var viewUrl = linkObj.attr('href');
$.get(viewUrl, function (data) {
dialogDiv.html(data);
dialogDiv.dialog('open');
});
return false;
});//uploadPicLink
//..
A view parcial _uploadPic.cshtml é a seguinte.
HTML
@model AddressBook_mvc3_jQuery.Models.Person
<form id="savePersonPicForm" name="savePersonPicForm" action="/Person/UploadFile/@Model.PersonNo"
method="post" enctype="multipart/form-data" target="UploadTarget">
<table>
<tr><td><b>Select file.. </b></td></tr>
<tr><td><input name="file" type="file" /></td></tr>
</table>
</form>
<iframe id="UploadTarget" name="UploadTarget" onload="UploadImage_Complete();"
style="visibility:hidden"></iframe>
A action UploadFile no PersonController é a seguinte.
C#
public class PersonController : Controller
{
//------------- image upload --------
// ..
[HttpPost]
public JsonResult UploadFile(int? personNo)
{
string message = string.Empty;
string fileName = string.Empty;
string imgPath = string.Empty;
bool success = false;
try
{
foreach (string a in Request.Files)
{
var file = Request.Files[a];
if (file.ContentLength > 0)
{
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 --------
// ..
}
A função JavaScript "onload" do iframe está abaixo. A imagem carregada é mostrada na linha relacionada da lista sem atualizar a linha.
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) Como criar linha de tabela no lado do cliente?
Um registro adicionado ao banco de dados deve ser mostrado na lista no lado do cliente. Isso pode ser feito de várias maneiras. Após adicionar um registro, a lista pode ser completamente atualizada do banco de dados, mas isso seria uma operação pesada. No entanto, usando javascript ou jquery, uma nova linha pode ser adicionada à view sem atualizar todos os elementos na view. Aqui, duas maneiras são mencionadas.
Primeiro, abaixo, a linha e as células da linha são criadas uma a uma com javascript. Como visto nos scripts abaixo, a função JavaScript saveSuccess após o submit deste formulário é usada para tal cenário.
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)
..
}
..
O método javascript saveSuccess é o seguinte. A action retorna um resultado json que inclui o tipo de operação. De acordo com a operação, ou seja, INSERT ou UPDATE, a tabela na view é modificada. Quando um novo registro é adicionado ao banco de dados, uma nova linha é adicionada (prepend) à tabela. Quando um registro existente no banco de dados é atualizado, apenas a linha relacionada na tabela é modificada.
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 ..." href="/Person/Save/' + data.Object.PersonNo.toString() + '">Edit</a> ' +
'<a role="button" class="adressLink ..." href="/Address/Index/' + data.Object.PersonNo.toString() + '">Addresses</a> ' +
'<a role="button" class="noteLink ..." href="/Note/Index/' + data.Object.PersonNo.toString() + '">Notes</a> ' +
'<a role="button" class="deleteLink ..." href="/Person/Delete/' + data.Object.PersonNo.toString() + '" pkno="' + data.Object.PersonNo.toString() + '">Delete</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 ...><br><a class=\"uploadPicLink\" ...>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
{
//..
}
}
O segundo caminho é usar a view parcial com dados html renderizados do controller. Os dados da linha de amostra, html puro, são os seguintes:
HTML
<tr id="row-@item.AddressNo">
<td>
@Html.ActionLink("Edit", "Save", ...)
@Html.ActionLink("Delete", "Delete", ...)
</td>
//...
</tr>
O html acima é construído a partir da seguinte view parcial
_addressLine.cshtml:HTML
@model AddressBook_mvc3_jQuery.Models.Address
<tr id="row-@Model.AddressNo">
<td>
@Html.ActionLink("Edit", "Save", ...)
@Html.ActionLink("Delete", "Delete", ...)
</td>
//...
</tr>
O html é renderizado no controller pela action. O objeto json retornado pela action usa este html.
C#
//..
obj = new { Success = true,
Message = "Added successfully",
Object = addrTmp,
operationType = "INSERT",
Html = this.RenderPartialView("_addressLine", addrTmp )
};
//.
O método RenderPartialView é usado para obter o script html desejado.
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();
}
}
//..
A função saveSuccess do ajax post no formulário saveAddress é a seguinte:
JavaScript
<script type="text/javascript">
//...
function saveSuccess(data)
{
if (data.Success == true)
{
$("#paginginfo").show();
if (data.operationType == 'UPDATE')
{
var row = linkObj.closest("tr");
row.replaceWith(data.Html);
//..
}
else
{ //INSERT
try
{
$("#AddressTable tr:first").after(data.Html);
//..
}
catch (err)
{
alert(err.Message);
}
}
//..
}
else
{
//..
}
}
//..
</script>
Qualquer uma das duas técnicas descritas acima pode ser usada.
15) Como personalizar mapRoute em Global.asax?
Na aplicação asp.net clássica, as operações de urlRewrite eram facilmente realizadas com alguns assemblies de terceiros. Na aplicação MVC, é possível personalizar mapRoutes usando Global.asax.
O seguinte mapRoute é padrão em 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
);
}
// ..
}
O mapRoute "Default" deve ser o último na lista. Novos mapRoutes personalizados devem ser adicionados acima de "Default". A seguir, alguns exemplos de mapRoute:
C#
//..
routes.MapRoute(
"Notes", // Route name
"Notes/{id}", // URL with parameters
new { controller = "Note", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
//..
routes.MapRoute(
"AddressList", // Route name
"AddressList/{id}", // URL with parameters
new { controller = "Address", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
//..
16) Como checkALL e uncheckALL todas as linhas da tabela?
Em muitas aplicações, pode ser desejado marcar ou desmarcar todos os checks em uma tabela de uma vez.

Para tal função, o seguinte script pode ser usado.
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
//..
$(".checkALLRecords").live("click", function (e)
{
e.preventDefault();
var rows = $("#NoteTable tr");
for(var i=0; i< rows.length; i++)
{
var row = $(rows).eq(i);
var cb = row.find('input.cboxDELclass');
cb.attr('checked', true);
}//
});//checkALLRecords
$(".unCheckALLRecords").live("click", function (e)
{
e.preventDefault();
var rows = $("#NoteTable tr");
for(var i=0; i< rows.length; i++)
{
var row = $(rows).eq(i);
var cb = row.find('input.cboxDELclass');
cb.attr('checked', false);
}//
});//checkALLRecords
//..
17) Como fazer "Loading Data"?
Ao carregar várias linhas de dados, a mensagem "loading data" deve ser mostrada aos usuários.

A seguinte div pode ser personalizada de acordo com a mensagem necessária.
HTML
..
<div id="loadMessage"></div>
..
A seguinte função javascript pode ser usada para personalizar a área div.
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) Como fazer grids master-detail com jQuery?
Quando uma linha master é clicada, as linhas detail são mostradas abaixo do grid master como mostrado abaixo.

A estrutura da tabela é a seguinte:
HTML
..
<table id="personTable">
<tr>
<th>Column1</th>
...
<th>Column9</th>
</tr>
</table>
..
Para obter dados master-detail, são usadas duas tabelas. Uma para o grid master e um tr para expandir, como visto no script abaixo.
JavaScript
//..
function getAddresses(aPersonNo, afterRow)
{
$.ajax({
type: "POST",
url: "@Url.Action("GetAddressList4Person", "Address")",
data: { personNo: aPersonNo, pageNo: 1 },
cache: false,
dataType: "json",
success: function (data)
{
if (data.Html)
{
$(afterRow).after('<tr class="addrSubRow" id="subRow-' + aPersonNo + '"><td colspan="9" style="padding-left:30px;">' + data.Html + '</td></tr>');
}
else
{
alert('opps!');
}
},
error: function (exp)
{
alert('Error address : ' + exp.responseText);
}
}); //end ajax call
}//func
..
Conclusão
Espero que tenha sido um artigo útil.
Serviços de Computação em Nuvem
Oferecemos serviços de design de infraestrutura, migração, gerenciamento e otimização nas plataformas AWS, Azure e Google Cloud.
Confira Nossos ServiçosEntre em Contato Conosco
Converse com nossa equipe para obter informações detalhadas sobre nossas soluções AWS e de computação em nuvem.
Contato