Ir para o conteúdo
jQuery Grid Checkbox Column Alternatives

jQuery Grid Checkbox Column Alternatives

A coluna checkbox (introduzida com a última versão, veja este post sobre Usando Colunas de Checkbox com o Infragistics jQuery Grid) foi criada para fornecer um 'atalho' para transformar colunas com valores booleanos em checkboxes e principalmente se tornou realidade devido ao grande interesse em tal funcionalidade por parte dos clientes (e afinal faz todo o sentido).

11min read

A coluna checkbox (introduzida com a última versão, veja este post sobre Usando Colunas de Checkbox com o Infragistics jQuery Grid) foi criada para fornecer um 'atalho' para transformar colunas com valores booleanos em checkboxes e principalmente se tornou realidade devido ao grande interesse em tal funcionalidade por parte dos clientes (e afinal faz todo o sentido).

jQuery Grid Checkbox column

Claro, este não é um mundo perfeito e criar padrões que possam atender às necessidades de todos é provavelmente uma causa perdida. Se você der uma olhada no blog introdutório acima, está realmente economizando muito tempo – basta definir uma única propriedade. Isso é bom e tudo, mas como pode ser visto nos comentários lá e em nossos fóruns, há uma limitação - a coluna da caixa de seleção funciona muito bem, mas fica tímida quando alguns modelos estão envolvidos.

O problema

Na referência da API de Grade em 'renderCheckboxes', diz "Essa opção não está disponível quando jQueryTemplating é usado". Isso é um pouco enganoso e certamente será atualizado, já que isso, de fato, inclui nosso próprio mecanismo de modelos. Portanto, em essência, o texto acima deve ser lido como 'Essa opção não está disponível quando o Templating é usado'. Isso ocorre porque, por design, o recurso de coluna Caixa de seleção é suprimido nesses casos, pois um modelo de linha pode ter sua própria renderização para a coluna.

Isso pode ou não ser uma explicação intuitiva de por que ele não estará disponível com o modelo de coluna também, mas quando você pensa sobre isso - a grade renderiza linhas, ela tem um modelo padrão para fazer isso - um modelo de linha. Você define uma coluna simplesmente acaba sendo incluída em algum lugar ao longo do caminho nesse modelo de linha, em vez do padrão. É por isso que os modelos em geral desativarão esse recurso.

Mas não se preocupe, há opções como sempre. Eu me deparei com isso e, como o feedback do cliente apontou isso para nós (Continue assim, gostamos de feedback construtivo!) neste blog, compartilharei minha experiência com a criação de maneiras alternativas de ter essa funcionalidade.

A solução

Template Checkbox

Curiosamente, o problema também é parte principal das soluções, pois é a maneira mais fácil de alterar a representação da interface do usuário de seus dados e também é muito flexível para ser ajustado ao seu gosto. Usando isso para adicionar caixas de seleção em nem todos os novos (Fóruns » NetAdvantage para jQuery » igGrid »Infragistics IGGrid com caixa de seleção) e, como mencionado, o próprio recurso deve ser um atalho para isso.

Um aviso justo: Estou compartilhando minha experiência e, por isso, passarei por duas abordagens diferentes que adotei. Antes de mergulhar no uso de um, certifique-se de ter visto e considerado os dois.

Portanto, a primeira abordagem é usar uma entrada HTML simples do tipo marca de caixa de seleção e atribuir a ela nosso valor. Esta é a abordagem que você pode ver em ambas as postagens do fórum vinculadas acima também. Você pode aplicar o modelo ao seu modelo de linha (se já estiver usando um) ou simplesmente atribuí-lo a uma única coluna. Para fins de demonstração, usarei a tabela Employees da AdventureWorks (AdventureWorks Sample Databases (MSDN)) para a coluna Bandeira assalariada e aqui está como uma configuração de grade seria:

$("#grid").igGrid({
    primaryKey: "BusinessEntityID",
    height: 550,
    dataSource: "@Url.Action("Employees")",
    autoGenerateColumns: false,
    columns: [
        { key: "BusinessEntityID", width: "50px", headerText: "ID", dataType: "number" , template: "<a style=\'font-size:20px;\' href=\'http://msdn.microsoft.com/en-us/library/ms124432(v=sql.100).aspx\'>${BusinessEntityID}</a>'},
        { key: "LoginID", width: "250px", headerText: "Login ID", dataType: "string" },
        { key: "JobTitle", width: "220px" , headerText: "Job Title", dataType: "string" },
        { key: "SalariedFlag", width: "120px", headerText: "SalariedFlag", dataType: "bool", template: "<input type=\"checkbox\" {{if ${SalariedFlag} === \"true\"}} checked=\"checked\" {{/if}} disabled=\"disabled\" style=\'display: block; margin-left: auto; margin-right: auto;\'>'}
    ],
    features: [
        { name: "Filtering", mode: "advanced", type: "local" },
        { name: "Sorting", type: "local" }]
});

Observe que a primeira coluna também tem um modelo – um link para a descrição da mesma tabela no MSDN – e, como é visível, isso não impede que as caixas de seleção apareçam, além de funcionar bem com recursos como classificação e filtragem:

Uma alternativa básica para a coluna da caixa de seleção usando o modelo e a caixa de seleção do tipo de entrada HTML simples.

Aprimoramentos

O modelo acima é apenas um mero ajuste de renderização e não vem com um pacote de interação. Um outro ponto justo feito pelos clientes é que a interação padrão pode ser melhorada, pois a coluna Caixa de seleção requer 3 cliques para atualizar - que é como a edição de linha com seleção se comporta - 1 clique para selecionar, outro para entrar em editar e terceiro para alterar o valor. Embora este não fosse o problema original, já que agora você está no controle das caixas de seleção, por que não melhorar um pouco as coisas?

O primeiro passo é remover a parte desativada, é claro. Em seguida, você precisaria lidar com a interação do usuário com a caixa de seleção - portanto, adicione algo como:

data-rowid=\"${BusinessEntityID}\" onchange=\"checkboxChanged(event);\"

ao modelo. Para entradas de caixa de seleção habilitadas, os eventos onchange e click são basicamente intercambiáveis, então escolha um, mas o nome do parâmetro passado para o identificador * deve * ser 'evento'. O atributo 'data-' é a maneira mais fácil de armazenar informações para o local da caixa de seleção – a grade faz a mesma coisa com os elementos de linha se você olhar mais de perto e é muito mais fácil armazená-la na criação, pois você tem acesso à entrada de dados de linha separada e dificilmente adicionará qualquer sobrecarga. Agora, como é fácil com a API de atualização colocar esse modelo em uso:

function checkboxChanged(evt) {
    // get rowID where change occured:
    var rowId = $(evt.currentTarget).data().rowid;
    $("#grid").igGridUpdating("updateRow", rowId, { "SalariedFlag": evt.currentTarget.checked });
}

O uso do método jQuery data() nos dá esse ID de linha em um piscar de olhos e o evento passado pode nos dizer o estado da caixa de seleção a ser atribuída a esse valor de coluna. Observe que isso requer que a atualização seja carregada como um recurso e adicionada aos recursos da grade(NetAdvantage® jQuery Online Help : igGrid Updating). E isso leva a alguns problemas que podem surgir

Quando a atualização entra em cena..

É bastante razoável supor, uma vez que a edição das caixas de seleção e a atualização já estão envolvidas, que a grade deve fornecer a experiência de edição completa. No entanto, uma vez ativado o modo de edição, a interface do usuário de célula/linha editada é separada, o que significa que, se você não implementar um provedor por conta própria, obterá o editor de estilo de combinação padrão:

O que acontece com o modelo no modo de edição.

Agora, isso pode ou não ser um problema para você (funcionará bem e as caixas de seleção serão atualizadas assim que você sair do modo de edição), mas por uma questão de experiência consistente, seria bom se o editor também pudesse ser uma caixa de seleção .. de preferência o mesmo. Neste ponto, você tem algumas opções, na verdade, vou apenas fornecer alguns exemplos de como acho que isso pode ser melhorado e utilizável.

Um pequeno truque para tentar é definir a mesma coluna como somente leitura. Você já tem um controle que define o valor da célula independentemente do estado de edição e, portanto, você pode ir em frente e definir essa mesma coluna como somente leitura! O que isso faria é impedir que a célula tenha sua interface do usuário substituída pelo editor e, no modo de linha, ela permanecerá inalterada. Isso significa que não há combinação como acima e a mesma caixa de seleção com o mesmo manipulador de eventos ainda pronto para ação. No entanto, é necessário um ajuste - como o método Update Row não deve ser chamado de dentro da sessão de edição, ele atualizará a interface do usuário. Tudo bem? Não. O problema é que, no caso em que você tem a grade com a configuração acima e tenta atualizar uma linha quando a edição é ativada, o comportamento estranho é garantido. A interface do usuário é atualizada, mas a edição ainda está ativa, mesmo que a grade pareça ter saído daquela e como não há botões ou outros elementos que lidam com a edição da sessão de edição. bem, está preso. Vejo algumas opções aqui, coisas como encerrar a edição (o método está disponível, é claro) antes de chamar a linha de atualização, mas isso sai imediatamente com a mudança da caixa de seleção e provavelmente não é isso que o usuário esperaria que acontecesse. Então, novamente, você pode desativar as caixas de seleção durante a edição, mas esse não é o caminho a seguir quando a edição está ativa.

O que você pode fazer é salvar a alteração diretamente nos logs de transações da fonte de dados, afinal a caixa de seleção cuidará de sua interface do usuário, mas pode exigir trabalho adicional (evento de dados sujos, religação) para funcionar corretamente com outros recursos. Você também pode simplesmente reiniciar a edição na mesma linha para o usuário:

function checkboxChanged(evt) {
    // get rowID where change occured:
    var rowId = $(evt.currentTarget).data().rowid;
    // if editing is active - update just the cell, otherwise use row update
    if($("#grid").igGridUpdating("isEditing")){
        $("#grid").igGridUpdating("endEdit");
        $("#grid").igGridUpdating("setCellValue", rowId, "SalariedFlag", evt.currentTarget.checked);
         
        //optionally can start the editing on the same row again
        //need row index:
        var rows = $("#grid").igGrid("rows");
        var rowIndex;
        //var context = this;
        $.each(rows, function (index, row) {
            if ($(row).data().id == rowId) {
                rowIndex = index;
            }
        });
        //make sure you let the calling code exit before attempting start edit,
        // a few milliseconds should be enough
        setTimeout(function () { $("#grid").igGridUpdating("startEdit", rowIndex, 1); }, 2);
    }
    else {
        $("#grid").igGridUpdating("updateRow", rowId, { "SalariedFlag": evt.currentTarget.checked });
    }
}

O snippet acima mostra como obter o índice da linha do ID e iniciar a edição nessa linha com um pequeno atraso (o manipulador de eventos é chamado dentro da função anônima em outro lugar). Terminar e iniciar a edição causa a mudança da interface do usuário, que por sua vez causa uma leve cintilação, mas com algum desejo e ajustes de CSS que podem ser alterados.

Observe que você pode explorar a possibilidade de criar um provedor de editor personalizado para uma experiência ainda melhor e mostrarei um pouco sobre isso na próxima parte.

No Boolean? No problem!

Se você notou até agora, há uma conexão muito fraca entre o valor real e a representação - nossa lógica dita tanto a representação quanto o resultado da interação. Portanto, nada está realmente impedindo você de usar mais do que apenas booleano - strings, números, valores nulos - todos bastante plausíveis. Talvez explore mais de dois estados da caixa de seleção também. Vamos ter a tabela SpecialOffers da AdventureWorks em que uma propriedade MaxQty para cada oferta declara um máximo OR 'NULL'. Eu quero não apenas exibir esses dados, quero exibir um resultado de avaliação disso. Pode não ser o melhor exemplo, mas terei uma coluna que mostrará se a oferta tem um máximo:

$.ig.loader(function () {
    $("#grid").igGrid({
        primaryKey: "SpecialOfferID",
        height: 550,
        dataSource: "@Url.Action("SpecialOffersData")",
        autoGenerateColumns: false,
        columns: [
            { key: "SpecialOfferID", width: "100px", headerText: "ID", dataType: "number" , template: "<a style=\'font-size:20px;\' href=\'http://msdn.microsoft.com/en-us/library/ms124455(v=sql.100)\'>${SpecialOfferID}</a>'},
            { key: "Description", width: "250px", headerText: "Description", dataType: "string" },
            { key: "Type", width: "220px" , headerText: "Type", dataType: "string" },
            { key: "MaxQty", width: "150px", headerText: "Has MaxQty", dataType: "string", template: "<input type=\"checkbox\" {{if parseInt(${MaxQty}) }} checked=\"checked\" {{/if}} data-rowid=\"${SpecialOfferID}\"  data-test=\"${MaxQty}\" onchange=\"checkboxChanged(event);\" style=\'display: block; margin-left: auto; margin-right: auto;\'>'}
        ],
        features: [
            { name: "Filtering", mode: "advanced", type: "local" },
            { name: "Sorting", type: "local" },
            { name: "Updating"}]
    });
});

Observe que a caixa de seleção está sendo marcada somente se o valor não for um dos equivalentes 'falsos' (a análise retorna NaN, por exemplo, quando falha). Além disso, você pode definir os valores da mesma maneira - adicione null para false e valor padrão / calculado para true:

function checkboxChanged(evt) {
    // get rowID where change occured:
    var rowId = $(evt.currentTarget).data().rowid;
    var newValue = evt.currentTarget.checked ? 10 : null;
    $("#grid").igGridUpdating("updateRow", rowId, { "MaxQty": newValue });
}

Os resultados (do SQL Management Studio e do aplicativo em execução com a Grade jQuery):

É possível com o modelo de caixa de seleção exibir facilmente valores não booleanos.

E, novamente, os truques de atualização mencionados podem ser implementados para isso de maneira idêntica.

Seguindo em frente

Aqui está uma comparação rápida entre o modelo DIY e a coluna padrão da caixa de seleção:

PROS

  • Funcionará com outros modelos.
  • Fácil de implementar – 1 linha para cenários simples.
  • Não se limita apenas a valores booleanos.
  • Como uma solução personalizada, não se limita a uma caixa de seleção de dois estados, uma caixa de seleção de três estados pode ser potencialmente implementada(JSFiddle mostrando uma implementação simples de caixa de seleção de 3 estados.)

CONTRAS

  • Requer algum código para obter resultados semelhantes.
  • Pode ser um pouco complicado de implementar SE também for necessário funcionar no modo de edição de atualização. No geral, em relacionamentos complicados com o recurso de atualização.
  • As implementações do navegador não parecem nada de especial e (corrija-me se eu estiver errado) também não têm garantia de ter a mesma aparência.


Espero que essa experiência tenha sido útil para todos aqueles que têm maiores funcionalidades em mente, pois os padrões podem fornecer. Como eu disse acima, isso é apenas eu compartilhando experiências, há uma curva de aprendizado aqui e esta não é a única ou última solução. Fique ligado para outra abordagem no próximo blog!

O projeto de demonstração está disponível para download. Como sempre, você pode nos seguir no Twitter@DamyanPeteve@ Infragisticse manter contato noFacebook,Google+eLinkedIn!

Solicite uma demonstração