Create Editable Table

Asked

Viewed 4,875 times

4

I would like to create a table where your cells can be edited but meet certain requirements. What I have is this:

HTML

<table class="table table-striped table-bordered" id="vendaTabela" width="100%">
    <thead>
      <tr>
        <th data-class="expand">Cód.</th>
        <th data-hide="phone">Designação</th>
        <th data-hide="phone">Qnt.</th>
        <th data-hide="phone,tablet">Uni.</th>
        <th>Preço</th>
        <th>Desconto</th>
        <th>IVA</th>
        <th>Sub-Total</th>
      </tr>
    </thead>
  <tbody>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
 </tbody>

JQUERY

$(function () {
        $("td").dblclick(function () {
            var conteudoOriginal = $(this).text();
            $(this).addClass("celulaEmEdicao");
            $(this).html("<input type='text' value='" + conteudoOriginal + "' />");
            $(this).children().first().focus();
            console.log($(this).attr('id'));
            $(this).children().first().keypress(function (e) {
                if (e.which == 13) {
                    var novoConteudo = $(this).val();
                    $(this).parent().text(novoConteudo);
                    $(this).parent().removeClass("celulaEmEdicao");
                }
            });
            $(this).children().first().blur(function () {
                $(this).parent().text(conteudoOriginal);
                $(this).parent().removeClass("celulaEmEdicao");
            });


        });
    });

I also have a button to add new lines:

//ADICIONAR LINHA
    $("#btnAdd").click(function () {
        $('#vendaTabela').append('<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>');
    });

As for the requirements it will be better to go in stages:

1º- I would like to find a way for the cells to be identified. I know I can put id’s in HTML tds but when I add a new line, how do they get identified?

2º- How can I place function by columns? That is, I want the column 'Sub-Total' to be the multiplication of the column 'Qnt.' with the column 'Price'. I can do the function for the first line already created in HTML, but how to do for when I add another line ?

3º- How can I put an autocomplete in the column you want, for example in the column of 'Designation' ?

  • can you add a plugin to the project? in this case I advise using jsView to help.

  • Can I, but I don’t know this plugin, I have to search about its use.

  • then put an example on it, it will help at the time to add a new line already with some data.

  • The lines I add will always start empty. Thank you :)

  • posted an alternative way to make this table using jsViews, you can take a look if you have interrese.

2 answers

7


As I said above, you can do this using jsViews, as in the example below:

For this you will need an Entity that will serve as a model, in the following case:

{
    Codigo: "",
    Designacao: "",
    Quantidade: "",
    Unidade: "",
    Preco: "",
    Desconto: "",
    IVA: "",
    SubTotal: ""
}

You will have the templates for each Row state (Details, Insert and Create):

<script id="tmplDetails" type="text/x-jsrender">
    <tr data-type="details">
        <td><input name="btEditar" type="button" value="Editar" /></td>
        <td>{{:Codigo}}</td>
        <td>{{:Designacao}}</td>
        <td>{{:Quantidade}}</td>
        <td>{{:Unidade}}</td>
        <td>{{:Preco}}</td>
        <td>{{:Desconto}}</td>
        <td>{{:IVA}}</td>
        <td>{{:SubTotal}}</td>
    </tr>
</script>

<script id="tmplEdit" type="text/x-jsrender">
    <tr data-type="edit">
        <td><input name="btSalvar" type="button" value="Salvar" /></td>
        <td><input name="txtCodigo" type="text" value="{{:Codigo}}" /></td>
        <td><input name="txtDesignacao" type="text" value="{{:Designacao}}" /></td>
        <td><input name="txtQuantidade" type="text" value="{{:Quantidade}}" /></td>
        <td><input name="txtUnidade" type="text" value="{{:Unidade}}" /></td>
        <td><input name="txtPreco" type="text" value="{{:Preco}}" /></td>
        <td><input name="txtDesconto" type="text" value="{{:Desconto}}" /></td>
        <td><input name="txtIVA" type="text" value="{{:IVA}}" /></td>
        <td><input name="txtSubTotal" type="text" value="{{:SubTotal}}" /></td>
    </tr>
</script>

<script id="tmplCreate" type="text/x-jsrender">
    <tr data-type="create">
        <td><input name="btSalvar" type="button" value="Salvar" /></td>
        <td><input name="txtCodigo" type="text" value="{{:Codigo}}" /></td>
        <td><input name="txtDesignacao" type="text" value="{{:Designacao}}" /></td>
        <td><input name="txtQuantidade" type="text" value="{{:Quantidade}}" /></td>
        <td><input name="txtUnidade" type="text" value="{{:Unidade}}" /></td>
        <td><input name="txtPreco" type="text" value="{{:Preco}}" /></td>
        <td><input name="txtDesconto" type="text" value="{{:Desconto}}" /></td>
        <td><input name="txtIVA" type="text" value="{{:IVA}}" /></td>
        <td><input name="txtSubTotal" type="text" value="{{:SubTotal}}" /></td>
    </tr>
</script>

Remembering that you can use arithmetic operations in the template, then {{:Quantidade * Preco}} is validated and can be used in Subtotal.

Note that I used the Template properties in templates, so we know how to fill the template.

finally we will have the HTML of the table itself:

<table id="vendaTabela">
    <thead>
        <tr>
            <th></th>
            <th data-class="expand">Cód.</th>
            <th data-hide="phone">Designação</th>
            <th data-hide="phone">Qnt.</th>
            <th data-hide="phone,tablet">Uni.</th>
            <th>Preço</th>
            <th>Desconto</th>
            <th>IVA</th>
            <th>Sub-Total</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
    <tfoot>
        <tr>
            <td><input name="btCreate" type="button" value="Criar" /></td>
            <td colspan="8"></td>
        </tr>
    <tfoot>
<table>

The Script below is mounting the table using a Source, which in this case may be an AJAX request, but I am using a list with 10 Entities.

var documento = $(document);
var vendaTabela = $("#vendaTabela");
var tabelaBody = $("tbody", vendaTabela);

var tmplDetails = $.templates("#tmplDetails");
var tmplEdit = $.templates("#tmplEdit");
var tmplCreate = $.templates("#tmplCreate");

var entidades = [];
for (var i = 1; i <= 10; i++) {
    entidades.push({
        Codigo: "Codigo" + i,
        Designacao: "Designacao" + i,
        Quantidade: "Quantidade" + i,
        Unidade: "Unidade" + i,
        Preco: "Preco" + i,
        Desconto: "Desconto" + i,
        IVA: "IVA" + i,
        SubTotal: "SubTotal" + i
    });
}

tabelaBody.empty();
$.each(entidades, function (indice, entidade) {
    var novaLinha = $(tmplDetails.render(entidade));
    novaLinha.data("Entidade", entidade);

    tabelaBody.append(novaLinha);
});

documento.on("click", "#vendaTabela input[name='btCreate']", function () {
    var novaEntidade = {};
    var novaLinha = $(tmplCreate.render(novaEntidade));
    novaLinha.data("Entidade", novaEntidade);

    tabelaBody.append(novaLinha);
});

documento.on("click", "#vendaTabela input[name='btEditar']", function () {
    var linha = $(this).closest("[data-type]");
    var entidade = linha.data("Entidade");
    var novaLinha = $(tmplCreate.render(entidade));
    novaLinha.data("Entidade", entidade);

    linha.replaceWith(novaLinha);    
});

documento.on("click", "#vendaTabela input[name='btSalvar']", function () {
    var linha = $(this).closest("[data-type]");
    var txtCodigo = $("[name='txtCodigo']", linha);
    var txtDesignacao = $("[name='txtDesignacao']", linha);
    var txtQuantidade = $("[name='txtQuantidade']", linha);
    var txtUnidade = $("[name='txtUnidade']", linha);
    var txtPreco = $("[name='txtPreco']", linha);
    var txtDesconto = $("[name='txtDesconto']", linha);
    var txtIVA = $("[name='txtIVA']", linha);
    var txtSubTotal = $("[name='txtSubTotal']", linha);

    var entidade = linha.data("Entidade");
    entidade.Codigo = txtCodigo.val();
    entidade.Designacao = txtDesignacao.val();
    entidade.Quantidade = txtQuantidade.val();
    entidade.Unidade = txtUnidade.val();
    entidade.Preco = txtPreco.val();
    entidade.Desconto = txtDesconto.val();
    entidade.IVA = txtIVA.val();
    entidade.SubTotal = txtSubTotal.val();    

    var novaLinha = $(tmplDetails.render(entidade));    
    novaLinha.data("Entidade", entidade);

    linha.replaceWith(novaLinha);

});

note that I made the bind of the events using the on right in the document, I have done this so that these events are available for elements created through the template.

pro fim the code in full:

var documento = $(document);
var vendaTabela = $("#vendaTabela");
var tabelaBody = $("tbody", vendaTabela);

var tmplDetails = $.templates("#tmplDetails");
var tmplEdit = $.templates("#tmplEdit");
var tmplCreate = $.templates("#tmplCreate");

var entidades = [];
for (var i = 1; i <= 10; i++) {
    entidades.push({
        Codigo: "Codigo" + i,
        Designacao: "Designacao" + i,
        Quantidade: "Quantidade" + i,
        Unidade: "Unidade" + i,
        Preco: "Preco" + i,
        Desconto: "Desconto" + i,
        IVA: "IVA" + i,
        SubTotal: "SubTotal" + i
    });
}

tabelaBody.empty();
$.each(entidades, function (indice, entidade) {
    var novaLinha = $(tmplDetails.render(entidade));
    novaLinha.data("Entidade", entidade);
    
    tabelaBody.append(novaLinha);
});

documento.on("click", "#vendaTabela input[name='btCreate']", function () {
    var novaEntidade = {};
    var novaLinha = $(tmplCreate.render(novaEntidade));
    novaLinha.data("Entidade", novaEntidade);
    
    tabelaBody.append(novaLinha);
});

documento.on("click", "#vendaTabela input[name='btEditar']", function () {
    var linha = $(this).closest("[data-type]");
    var entidade = linha.data("Entidade");
    var novaLinha = $(tmplEdit.render(entidade));
    novaLinha.data("Entidade", entidade);
    
    linha.replaceWith(novaLinha);    
});

documento.on("click", "#vendaTabela input[name='btSalvar']", function () {
    var linha = $(this).closest("[data-type]");
    var txtCodigo = $("[name='txtCodigo']", linha);
    var txtDesignacao = $("[name='txtDesignacao']", linha);
    var txtQuantidade = $("[name='txtQuantidade']", linha);
    var txtUnidade = $("[name='txtUnidade']", linha);
    var txtPreco = $("[name='txtPreco']", linha);
    var txtDesconto = $("[name='txtDesconto']", linha);
    var txtIVA = $("[name='txtIVA']", linha);
    var txtSubTotal = $("[name='txtSubTotal']", linha);
    
    var entidade = linha.data("Entidade");
    entidade.Codigo = txtCodigo.val();
    entidade.Designacao = txtDesignacao.val();
    entidade.Quantidade = txtQuantidade.val();
    entidade.Unidade = txtUnidade.val();
    entidade.Preco = txtPreco.val();
    entidade.Desconto = txtDesconto.val();
    entidade.IVA = txtIVA.val();
    entidade.SubTotal = txtSubTotal.val();    
    
    var novaLinha = $(tmplDetails.render(entidade));    
    novaLinha.data("Entidade", entidade);
    
    linha.replaceWith(novaLinha);
    
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://www.jsviews.com/download/jsviews.js"></script>
<script src="http://cdn.foundation5.zurb.com/foundation.js"></script>
<link href="http://cdn.foundation5.zurb.com/foundation.css" rel="stylesheet"/>
<table id="vendaTabela">
    <thead>
        <tr>
            <th></th>
            <th data-class="expand">Cód.</th>
            <th data-hide="phone">Designação</th>
            <th data-hide="phone">Qnt.</th>
            <th data-hide="phone,tablet">Uni.</th>
            <th>Preço</th>
            <th>Desconto</th>
            <th>IVA</th>
            <th>Sub-Total</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
    <tfoot>
        <tr>
            <td><input name="btCreate" type="button" value="Criar" /></td>
            <td colspan="8"></td>
        </tr>
    <tfoot>
<table>
    

<script id="tmplDetails" type="text/x-jsrender">
    <tr data-type="details">
        <td><input name="btEditar" type="button" value="Editar" /></td>
        <td>{{:Codigo}}</td>
        <td>{{:Designacao}}</td>
        <td>{{:Quantidade}}</td>
        <td>{{:Unidade}}</td>
        <td>{{:Preco}}</td>
        <td>{{:Desconto}}</td>
        <td>{{:IVA}}</td>
        <td>{{:SubTotal}}</td>
    </tr>
</script>

<script id="tmplEdit" type="text/x-jsrender">
    <tr data-type="edit">
        <td><input name="btSalvar" type="button" value="Salvar" /></td>
        <td><input name="txtCodigo" type="text" value="{{:Codigo}}" /></td>
        <td><input name="txtDesignacao" type="text" value="{{:Designacao}}" /></td>
        <td><input name="txtQuantidade" type="text" value="{{:Quantidade}}" /></td>
        <td><input name="txtUnidade" type="text" value="{{:Unidade}}" /></td>
        <td><input name="txtPreco" type="text" value="{{:Preco}}" /></td>
        <td><input name="txtDesconto" type="text" value="{{:Desconto}}" /></td>
        <td><input name="txtIVA" type="text" value="{{:IVA}}" /></td>
        <td><input name="txtSubTotal" type="text" value="{{:SubTotal}}" /></td>
    </tr>
</script>

<script id="tmplCreate" type="text/x-jsrender">
    <tr data-type="create">
        <td><input name="btSalvar" type="button" value="Salvar" /></td>
        <td><input name="txtCodigo" type="text" value="{{:Codigo}}" /></td>
        <td><input name="txtDesignacao" type="text" value="{{:Designacao}}" /></td>
        <td><input name="txtQuantidade" type="text" value="{{:Quantidade}}" /></td>
        <td><input name="txtUnidade" type="text" value="{{:Unidade}}" /></td>
        <td><input name="txtPreco" type="text" value="{{:Preco}}" /></td>
        <td><input name="txtDesconto" type="text" value="{{:Desconto}}" /></td>
        <td><input name="txtIVA" type="text" value="{{:IVA}}" /></td>
        <td><input name="txtSubTotal" type="text" value="{{:SubTotal}}" /></td>
    </tr>
</script>

  • I thank you in advance for your cooperation and help. I tested and it is quite complete, but for what I am doing, and for the required level is a bit complex :D Anyway Thank you and deserve my vote

  • I believe that once you understand jsRender, the script itself is easy to understand, until pq the only thing it does is replace one template with another.

3

1. You can resolve using classes in columns and id’s in rows to identify them. For example:

<tr id="linha1">
    <td class="numero">123</td>
    <td class="nome">Teste</td>
</tr>
<tr id="linha2">
    <td class="numero">123</td>
    <td class="nome">Teste</td>

var $numero = $("#linha1 .numero"); // coluna número na linha 1

2. Following the previous example, you could do something like this:

var subTotal = 0;
var $linhas = $("#minhaTabela tbody > tr");
// aconselho a usar o tbody na seleção para evitar selecionar o header e o footer

// percorre todas as linhas
$linhas.each(function() {
    // o this refere-se a linha
    var qtd = $(".quantidade", this).html();
    var vlr = $(".valor", this).html();

    // tenta converter para float e retorna 0 caso esteja em branco
    qtd = parseFloat(qtd) || 0;
    vlr = parseFloat(vlr) || 0;

    subTotal += qtd * vlr;
});

$("#subTotal").html(subTotal);

To update the subtotal when adding a line is simple: put the above code in a function and call again whenever necessary.


3. I don’t understand your difficulty here, don’t you know how to add an autocomplete? Because you already use jQuery, you can use jQueryUI. See sample page.

  • I appreciate your help. Looking at point 1 of your answer, my question is this: I only have one 'tr' in my html where I define the id I want. If you pay attention to my add line function, what do I put on this tr to trouble id when adding the new line?

  • If possible use a counter. Otherwise, a very dynamic solution is to use the number of current lines, for example: var id = 'linha' + $("#minhaTabela tbody > tr").length;.

  • Thanks for your help. I don’t understand this part: var $numero = $("#line1 .numero"); // column number on line 1 ?

  • It will return a jQuery object. Try, for example, to run console.log($numero.html()). You are using this jQuery object in your code, even without realizing it.

  • returns me Undefined :s I have this: <thead><tr id="tr0"> <th>Cód.</th></thead> <tbody> <td class="codigo"></td></tbody> ... var $codigo = $("#tr0 . code");

  • You’re confusing the css selectors a little bit. The selector #tr0 .codigo will search for the element with class .codigo within of an element with id #tr0. Test again with an html like this: <table><tr id='tr0'><td class='codigo'>123</td></tr></table>.

  • That way it works :D But I can’t have Header in my table? That’s <th></th> ?

  • Yes, but look again at the html code you tried before: <thead><tr id="tr0"> <th>Cód.</th></thead> <tbody> <td class="codigo"></td></tbody>. The column .codigo is not inside the line #tr0.

  • I put it the way I wanted but I have a problem now. I with the code want to get the designation. To do so, I’m using var id = $(".code",this). html(); inside each of the lines. If I do the console log, it prints everything. In the case of the subtotal, it is working right because it takes the right value, but to get the designation in which I have to pass the id, I have the getDesignacaobyId(id) method inside each of the lines and as it goes through all the lines it always picks up the first designation. You know how I can give ?

  • Follow the same example of how to get the value. Add a class to the desired column and to get just run $(".designacao", this).html() inside the loop.

  • I followed exactly the same way, but the problem lies here: I have two each’s: $lines.each(Function(){...and then to go get the designation by ajax I have ... if (date.length > 0) { $.each(date, Function (key, value) {... just inside this last each, this ($(". designation", this). html()) does not work.

  • I believe it’s best you create a new question for this problem.

  • OK so I’ll do it then

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.