Páginas

domingo, 27 de fevereiro de 2011

jQuery Templates e combos preenchidas

Estou usando o plugin de template do jQuery em uma tela de um sistema que estou construindo, e encontrei o seuginte problema, que mostro no exemplo abaixo.

Vamos supor que temos uma página que contém uma tabela usada para edição de informações. Lista de cidades e estados, por exemplo.

image

Nesta listagem, conforme vamos precisando de novas linhas, vamos incluindo informando o nome da cidade e selecionando o estado na combo. Abaixo está o código que faz essa inclusão:

<!DOCTYPE html>
<html>
<head>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>
</head>
<body>
    <script id="templateLinha" type="text/x-jquery-tmpl">
    <tr>
        <td>
            <input type="text" value="${Cidade}" />
        </td>
        <td>
            <select>
                <option value="GO">GO</option>
                <option value="SP">SP</option>
                <option value="PR">PR</option>
                <option value="RJ">RJ</option>
            </select>
        </td>
    </tr>
    </script>
    <script language="javascript">
        $(document).ready(function () {
            $("#btnAdd").click(function () {
                var cidades = [{ Cidade: $("#txtCidade").val(), Estado: $("#ddlEstado").val()}];
                $("#templateLinha").tmpl(cidades).appendTo("#listaCidades").find("select").val(function (index, value) {
                    return cidades[index].Estado;
                });
            });
        });
    </script>
    <input id="txtCidade" type="text" />
    <select id="ddlEstado">
        <option value="GO">GO</option>
        <option value="SP">SP</option>
        <option value="PR">PR</option>
        <option value="RJ">RJ</option>
    </select>
    <button id="btnAdd">
        Adicionar cidade</button>
    <br /><br />
    <table border="1">
        <thead>
            <tr>
                <td>
                    Cidade
                </td>
                <td>
                    Estado
                </td>
            </tr>
        </thead>
        <tbody id="listaCidades">
            <tr>
                <td>
                    <input type="text" value="Santo André" />
                </td>
                <td>
                    <select>
                        <option value="GO">GO</option>
                        <option value="SP" selected>SP</option>
                        <option value="PR">PR</option>
                        <option value="RJ">RJ</option>
                    </select>
                </td>
            </tr>
        </tbody>
    </table>
</body>
</html>



Perceba que no código estou utilizando a funcionalidade de template para a inclusão da nova linha. Dentro da tag <script> chamada “templateLinha”, tenho todo o modelo que será utilizado para esta inclusão. Note que trata-se apenas de uma nova linha na tabela, contendo uma caixa de texto e uma combo. Veja que no lugar do valor da caixa de texto, eu coloquei ${Cidade}. É a partir da substituição desse campo que o modelo da linha será preenchido automaticamente (e veja também que, pela característica de um objeto do tipo <select>, não conseguimos fazer essa substituição, e este será nosso problema.



No código que é executado no clique do botão, eu obtenho os valores que serão passados ao template, transformados em um array de objetos, e chamo a função abaixo, que faz com que os dados sejam aplicados no template “templateLinha”, e anexados no objeto “listaCidades”.



$("#templateLinha").tmpl(cidades).appendTo("#listaCidades");

No entanto, ao executar, vemos que a combo não é preenchida com o valor que queremos (ela fica com o valor padrão, que é o primeiro da lista, “GO”). Isto ocorre pois não temos como substituir um valor dentro da tag <select> para que seja ajustado o valor da combo (diferentemente de um objeto do tipo <input>, que é apenas substituir o conteúdo da propriedade “value”).



image



Neste caso específico, a resolução não pode ser feita apenas com o template do jQuery (minto, até consegue usando a funcionalidade de “if” do plugin de Template do jQuery, mas se usar desta maneira terá que construir o código da combo na mão, e não poderá, por exemplo, utilizar um helper de geração de HTML como o método Html.DropDownList() do ASP.NET MVC).



Bom, para resolver este problema de uma forma elegante, temos que contar com a função .val(xxx) do jQuery, só que não passando um valor mas sim uma função que retorne este valor. Com isso, podemos fazer uma iteração nos valores do array, obtendo o dado correto. Veja o trecho do código alterado abaixo (destacado em azul).



<script language="javascript"> 
    $(document).ready(function () {
        $("#btnAdd").click(function () {
            var cidades = [{ Cidade: $("#txtCidade").val(), Estado: $("#ddlEstado").val()}];
           $("#templateLinha").tmpl(cidades).appendTo("#listaCidades").find("select").val(function (index, value) {
                return cidades[index].Estado;
            });
        });
    });
</script>

image


Desta maneira, logo após a inclusão da linha na tabela, já fazemos a correção dos valores da combo.


[]’s e até a próxima!