Olá, pessoal

Retornando depois de um mês sumido, já aproveito para desejar um ótimo 2013 a todos. Muita saúde e sucesso!

Neste post, falarei sobre um comportamento inusitado do Firefox, no que diz respeito a consultas AJAX.

Vejamos a situação onde desejamos fazer uma consulta assíncrona e carregar o resultado montado em uma partial view para dentro de uma tag <div>. O código na view de pesquisa seria algo como:

@using(Ajax.BeginForm("Pesquisar", "MeuController", new AjaxOptions() { UpdateTargetId = "resultados", HttpMethod="GET" }))
{
    <input type="submit" value="Pesquisar" />
}
<div id="resultados">
</div>

Agora a action chamada:

public PartialViewResult Pesquisar()
{
    // simulando consulta
    var resultado = new List<string>() { "texto1", "texto2" };
    // troque por este para simular retorno de dados
    // var resultado = new List<string>();

    return PartialView("ResultadosDaPesquisa", resultado);
}

Tudo funciona perfeitamente, inclusive no Firefox, quando a consulta retorna algum resultado, ou seja, quando a partial view retornada possui algum conteúdo.

Agora imaginem que a partial view “ResultadosDaPesquisa.cshtml” só renderize algo se o resultado da pesquisa contiver pelo menos um registro:

@model List<string>
@if (Model.Any())
{
    foreach (var s in Model)
    {
        <span>@s</span>
    }
}
/* final do arquivo! */

Da forma acima, uma partial view totalmente vazia será retornada se a pesquisa não encontrar registros. Nessa situação, o Firefox não entende o resultado “vazio”:

Claro galera, este problema é rapidamente resolvido (e provavelmente, você nem sabia da existência dele) se a partial view acima possuir um “else” com algo como: <span>Nenhum resultado encontrado</span>.

Mas, à título de curiosidade ou caso você queira tratar a exibição da mensagem de registros não-encontrados de outra forma – como por exemplo, usando javascript em um arquivo referenciado na sua layout page – você terá que retornar um objeto JSON vazio:

public ActionResult Pesquisar()
{
    // simulando consulta
    var resultado = new List<string>() { "texto1", "texto2" };
    // troque por este para simular retorno de dados
    // var resultado = new List<string>();

    if (resultado.Any())
        return PartialView("ResultadosDaPesquisa", resultado);

    return Json(string.Empty, JsonRequestBehavior.AllowGet);
}

Notem acima que retorno a partial view somente se há dados, caso contrário retorno um JsonResult com uma string vazia. Vejam que o tipo de retorno da action foi alterado para “ActionResult” para acomodar os 2 tipos possíveis de retorno.

Ao forçar o retorno de algo (um objeto JSON com uma string vazia), o Firefox consegue entender o retorno, deixando de exibir o erro exibido na figura.

Melhorando a solução…

Para melhorar a solução acima, você pode encapsular esse tratamento em um método e colocá-lo em um controller base:

public class ControllerPadrao : Controller
{
    // método que encapsula tratamento da lista contendo o resultado da pesquisa
    public ActionResult JsonQuery<T>(IEnumerable<T> resultado, PartialViewResult partialView)
    {
        if (resultado.Any()) return partialView;
        return Json(string.Empty, JsonRequestBehavior.AllowGet);
    }
}

Vejam que o método recebe um IEnumerable de qualquer coisa – usando Generics – e a partial view que será renderizada caso o resultado não seja vazio.

Refatorando a action Pesquisar, temos como resultado:

// controller agora herda do ControllerPadrao
public class TesteController : ControllerPadrao
{
    // action refatorada para chamar o método JsonQuery do controller padrão
    public ActionResult Pesquisar()
    {
        // simulando consulta
        var resultado = new List<string>() { "texto1", "texto2" };
        // troque por este para simular retorno de dados
        // var resultado = new List<string>();

        // utilizando o novo método do controller padrão
        return JsonQuery(resultado, PartialView("ResultadosDaPesquisa", resultado));
    }
}

Bem mais elegante, com o “if feio” mantido em um só lugar!

Era isso, pessoal!

Até a próxima!