No ASP.NET MVC / Razor, como adicionar o JavaScript inicializador a um “controle”?

5

Na verdade, eu já tenho pelo menos 3 soluções diferentes para o problema, não gosto de nenhuma delas por vários motivos.

No ASP.NET MVC / Razor, não há mais controles, no sentido em que estavam no ASP.NET. Um controle ASCX costumava ser view + controller interligado, então eu entendi. Em vez disso, temos ajudantes html que emitem strings, fragmentos html. Digamos que eu queira criar um método auxiliar em uma biblioteca que crie um selecionador de data da jQuery UI.

Primeira solução. Acabei de escrever um método que primeiro cria uma caixa de texto (na verdade, posso apenas chamar TextBoxFor porque faz a mesma coisa para mim), então cria um pequeno fragmento de código JavaScript que chama $('#textboxid').datepicker() . Então eu posso chamar isso em minhas visualizações do Razor e funciona. Eu não gosto do fato de que coisas relacionadas à visão sejam feitas no código, e não no Razor, mas todos os modelos de editor padrão são assim, infelizmente. Eu não gosto do fato de que haverá muitos pequenos fragmentos de script após cada caixa de texto no html de saída. E meu fragmento de código pode ficar complexo, se o inicializador JS tivesse muitos parâmetros, ficaria feio, haveria problemas de escape de string, etc.

A Microsoft está impulsionando a arquitetura JavaScript não-intrusiva. Eu poderia apenas colocar uma classe de marcador CSS na minha caixa de texto, adicionar alguns atributos de dados, se necessário, e emitir apenas um JavaScript que transforma todas as minhas caixas de texto em selecionadores de data, com base na classe de marcador CSS. Esta última parte é o principal problema, eu preciso de um código JS imperativo para fazer isso. O AJAX e a validação discretos funcionam bem porque não precisam disso, apenas respondem a eventos de interação do usuário. Este não é o caso, eu preciso transformar minhas caixas de texto em selecionadores de data sempre que eles aparecerem. E eles podem aparecer dinamicamente em uma grade editável, ou depois de uma chamada AJAX, sempre.

Terceira solução, a visualização deve ser feita no Razor, então vamos fazê-lo no Razor, como um modelo de editor. O problema é que estamos falando de uma biblioteca de classes aqui. No passado, eu vi hacks feios para incorporar arquivos .cshtml como recursos incorporados ou compilá-los para o código C # real durante a compilação. Última vez que chequei, eles pareciam ser feios e não eram suportados.

Existe outra solução? Se não, qual das opções acima é a mais agradável, a que mais se ajusta às convenções de codificação do estado da arte, ou a idéia da Microsoft, etc?

    
por fejesjoco 14.01.2014 / 16:31
fonte

2 respostas

5

Não sei se identifiquei o problema certo, mas, se tiver, isso pode ajudar:

Criamos uma classe chamada ScriptManager que nos permite adicionar arquivos javascript e / ou funções arbitrárias ao final de todas as nossas páginas quando elas são renderizadas. Experimente:

public class ScriptManager
{
    public List<string> scripts = new List<string>();
    public List<string> scriptFiles = new List<string>();
}
public static class HtmlExtensions
{

    [ThreadStatic]
    private static ControllerBase pageDataController;
    [ThreadStatic]
    private static ScriptManager pageData;

    public static ScriptManager ScriptManager(this HtmlHelper html)
    {
        ControllerBase controller = html.ViewContext.Controller;

        // This makes sure we get the top-most controller
        while (controller.ControllerContext.IsChildAction)
        {
            controller = controller.ControllerContext.ParentActionViewContext.Controller;
        }
        if (pageDataController == controller)
        {
            // We've been here before
            return pageData;
        }
        else
        {
            // Initial setup
            pageDataController = controller;
            pageData = new ScriptManager();
            return pageData;
        }
    }
}

Em seguida, na parte inferior da sua página _Layout.cshtml :

@foreach (var script in Html.ScriptManager().scriptFiles.Distinct())
{
    @Html.Script(script);
}
@foreach (var script in Html.ScriptManager().scripts)
{
    @Html.Raw("<script type='text/javascript'>")
    @Html.Raw(script)
    @Html.Raw("</script>")
}

Finalmente, você o usa em uma visão parcial como:

@{
  Html.ScriptManager().scriptFiles.Add(Url.Content("~/Scripts/jquery.blockUI.js"));
 }

Você perde a capacidade de informar ao cliente sobre os scripts no cabeçalho da página, mas eles serão incluídos em todas as páginas em que você usa uma exibição parcial que usa o blockUI (por exemplo).

    
por 14.01.2014 / 22:47
fonte
0

Outra é ter um cshtml e o controlador correspondente abaixo. Tal coisa nós chamamos um controle e o incorporamos em outra visão usando @Html.RenderPartial('<action_url>', <model>) . No controlador, a ação deve ser anotada com o atributo [ChildActionOnly] , portanto, não pode ser chamado em uma chamada direta.

Não que eu seja um grande fã dessa abordagem, apenas descreva-a aqui para termos uma visão completa.

Você também pode usar @helper do Razor além de @Html. helpers.

    
por 14.01.2014 / 21:02
fonte