How to send dynamically created fields via JSON?

0

How to send via%% of% dynamically created% fields%, eg:

The user types in a text field the quantity 4 and the function creates 8 input fields, or type 5 and the function creates 10 input fields, this function already works and is OK!

This is the snippet of the function that creates the fields dynamically:

for (var i = 0; i < _qtde; i++) {
var new_date = new Date();
new_date.setMonth(new_date.getMonth() + i);
$("#divParcela").append("<div class='col-xs-6'> <label>Vencimento - parcela 
  " + parseInt(i + 1) + "</label> <input type='text' id='' value='" + 
  $.datepicker.formatDate('dd/mm/yy', new_date) + "' class='form-control' />
  </div> <div class='col-xs-6'><label>Valor - parcela " + parseInt(i + 1) + 
  "</label><input type='text' id='' value='" + _valorParcela.toFixed(3)  + 
  "' class='form-control' /></div>");
 };

Next, when you click the Register button, the system takes the values and sends via JSON to the database, it looks something like this:

$("#btnCadastrar").on("click", function () {

        var _movimentacao = {
            "MovimentoFinanceiroID": $("#MovimentoFinanceiroID").val(),
            "NumDocumento": $("#NumDocumento").val(),
            "ItemMovimentoFinanceiro":[]
            };

        _movimentacao.ItemMovimentoFinanceiro.pusch({
                "NumParcela": "Campo_Parcela_criado_dinamicamente",
                "ValorDocumento": "Campo_Valor_criado_dinamicamente"
         });

        $.ajax({
        url: "/MovimentoFinanceiro/IncluirJSON",
        type: "post",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        processData: false,
        data: JSON.stringify(_movimentacao),
        success: function (data) {
            window.location.href = "/MovimentoFinanceiro/Index";
        },
        error: function (result) {
            alert(result.responseText);
        }
    });
});
  

This is the JsonResult method:

public JsonResult IncluirJSON(MovimentoFinanceiroViewModel pMovimentoFinanceiro)
        {
            try
            {
                //Aqui vou implementar rotina para gravar no banco de dados
                return Json("OK", JsonRequestBehavior.AllowGet);
            }
            catch (Exception)
            {
                return Json("ERRO", JsonRequestBehavior.AllowGet);
            }
        }
  

These two classes are the intermediate model (DTO):

public class MovimentoFinanceiroViewModel
{
    public List<ListDetalheMovimento> ListItens { get; set; }
}

public class ListDetalheMovimento
{
    public decimal ValorParcela { get; set; }
    [Column(TypeName = "DateTime2")]
    public DateTime? DataVencimentoParcela { get; set; }
}
  

Entity that reflects the database table:

 public class MovimentoFinanceiro
    {
        [Key]
        public int MovimentoFinanceiroID { get; set; }
        public int ItemPlanoContabilID { get; set; }
        public decimal ValorParcela { get; set; }
        public DateTime DataVencimentoParcela { get; set; }
}
    
asked by anonymous 09.02.2016 / 11:55

3 answers

2

In order to send the dynamically created field values you need to create input elements with the same name and in your model you need to have a property with the same name used in the% and that is of a collection type such as array or name . Just do that ASP.NET MVC will do the automatic binding of this data sent into the property.

In addition, I noticed that you are sending the data to the action method in JSON format (% with%), ideally you would change to List<T> which is the default format, and will allow easier serialization of form data using only contentType: "application/json; charset=utf-8" .

Well, I'll give you an example to make it easier to understand.

Model :

public class IndexModel
{
    public List<string> Coisas { get; set; }
}

Action method :

 public JsonResult IndexJson(IndexModel model)
 {
      return Json("Ok", JsonRequestBehavior.AllowGet);
 }

View :

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "form" }))
{
    <div class="form-group">
        @Html.LabelFor(x => x.Coisas)
        @Html.TextBoxFor(x => x.Coisas, new { @class = "form-control" })
        @Html.TextBoxFor(x => x.Coisas, new { @class = "form-control" })
        @Html.TextBoxFor(x => x.Coisas, new { @class = "form-control" })
        @Html.TextBoxFor(x => x.Coisas, new { @class = "form-control" })
        @Html.TextBoxFor(x => x.Coisas, new { @class = "form-control" })
    </div>

    <button id="enviar" class="btn btn-primary">Enviar</button>
}

<script src="~/Scripts/jquery-1.10.2.min.js"></script>

<script>
    $('#form').submit(function () {
        $.ajax({
            url: '/Home/IndexJson',
            type: 'POST',
            dataType: 'json',
            data: $('#form').serialize(),
            success: function (data) {
                console.log(data);
            },
            error: function (result) {
                console.log(result);
            }
        });
    });
</script>

In the example I generated the fields by Razor, but in your case just continue doing it by JavaScript and remembering to put contentType: "application/x-www-form-urlencoded; charset=UTF-8" in all elements .serialize() :

<form action="/Home/Index" method="post">
    <div class="form-group">
        <label for="coisa">Coisas</label>
        <input class="form-control" type="text" name="coisa">
        <input class="form-control" type="text" name="coisa">
        <input class="form-control" type="text" name="coisa">
        <input class="form-control" type="text" name="coisa">
        <input class="form-control" type="text" name="coisa">
    </div>
    <button class="btn btn-primary">Enviar</button>
</form>

One thing that went unnoticed by me and would be interesting to add is that in your case it might be better to create an intermediate model to be used in place of name as a parameter in input , this is a pattern known as Data Transfer Object (DTO) , a DTO can be used as a container of data between communications within a system, in your case this DTO, which is nothing more than a class you mounted yourself, should contain this collection property, in addition to the other properties of MovimentoFinanceiro .

This way you do not have to change the IncluirJSON , which apparently maps a table in the database, so it is not feasible to change its structure.

    
09.02.2016 / 14:26
1

In your case, I believe that using Action Filters is a good way, since you want to receive the contents of your JSON already as a properly populated instance in your Action.

To make this happen the idea is:

1) You must have a default when naming your fields. By default, the browser understands that when there are multiple fields of the same name with square brackets (for example "ValueParcela []"), all values of these fields will be divided by a comma in the request.

2) Create a class that extends ActionFilterAttribute and make the OnActionExecuting () method read the parameters passed according to the defined pattern. Through the context of this filter, you can handle all those fields and return your filled ViewModel.

3) Mark your Action with the class created above.

You can even implement this by passing just one string with your JSON and doing the proper filter handling. However, taking advantage of @Zignd's good idea of passing the serialized form information, I gave a small example based on how it was already doing.

View, where I took some advantage of @Zignd's response code:

<form id="form">
    <input type="text" name="ValorParcela[]">
    <input type="text" name="DataVencimentoParcela[]">

    <input type="text" name="ValorParcela[]">
    <input type="text" name="DataVencimentoParcela[]">

    <input type="text" name="ValorParcela[]">
    <input type="text" name="DataVencimentoParcela[]">

    <input type="text" name="ValorParcela[]">
    <input type="text" name="DataVencimentoParcela[]">

    <input type="text" name="ValorParcela[]">
    <input type="text" name="DataVencimentoParcela[]">
</form>
<button id="submit">Enviar</button>

<script src="~/Scripts/jquery-1.10.2.min.js"></script>

<script>
    $('#submit').on('click', function () {
        $.ajax({
            url: '/Home/IncluirJSON',
            type: 'POST',
            dataType: 'json',
            data: $('#form').serialize(),
            success: function (data) {
                console.log(data);
            },
            error: function (result) {
                console.log(result);
            }
        });
    });
</script>

The classes related to the View Model:

public class MovimentoFinanceiroViewModel
{
    public MovimentoFinanceiroViewModel()
    {
        this.DetalhesMovimento = new List<DetalheMovimento>();
    }

    public List<DetalheMovimento> DetalhesMovimento { get; set; }
}

public class DetalheMovimento
{
    public decimal ValorParcela { get; set; }        
    public DateTime? DataVencimentoParcela { get; set; }
}

The filter class:

public class MovimentoFinanceiroFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        /*
        Exemplo de como são recebidos os campos:

        filterContext.HttpContext.Request.Form["ValorParcela[]"] = "1,2,3,4,5"
        filterContext.HttpContext.Request.Form["DataVencimentoParcela[]"] = "1,2,3,4,5"
         */

        string sValorParcela = filterContext.HttpContext.Request["ValorParcela[]"];
        string sDataVencimentoParcela = filterContext.HttpContext.Request["DataVencimentoParcela[]"];

        var valoresParcela = sValorParcela.Split(new char[] { ',' });
        var datasVencimentoParcela = sDataVencimentoParcela.Split(new char[] { ',' });

        var viewModel = new MovimentoFinanceiroViewModel();

        for (int i = 0; i < valoresParcela.Length; i++)
        {
            decimal valorParcela = 0;
            Decimal.TryParse(valoresParcela[i], out valorParcela);

            DateTime dataVencimentoParcela = DateTime.MinValue;
            DateTime.TryParse(datasVencimentoParcela[i], out dataVencimentoParcela);

            viewModel.DetalhesMovimento.Add(new DetalheMovimento { ValorParcela = valorParcela, DataVencimentoParcela = dataVencimentoParcela });
        }

        filterContext.ActionParameters["pMovimentoFinanceiro"] = viewModel;
    }
}

And finally, Action:

[MovimentoFinanceiroFilterAttribute]
public JsonResult IncluirJSON(MovimentoFinanceiroViewModel pMovimentoFinanceiro)
{
    try
    {
        //Aqui vou implementar rotina para gravar no banco de dados
        return Json("OK", JsonRequestBehavior.AllowGet);
    }
    catch (Exception)
    {
        return Json("ERRO", JsonRequestBehavior.AllowGet);
    }
}
    
10.02.2016 / 04:06
0

It may not be the best solution, but it has met my needs:

   $("#btnCadastrar").on("click", function () {
            var _movimentacao = {
                "MovimentoFinanceiroID": $("#MovimentoFinanceiroID").val(),
                "NumDocumento": $("#NumDocumento").val(),
                "ItemMovimentoFinanceiro": []
            };

            var _contaLinha = 0;

            $("input[name='ValorParcela[]']").each(function () {                
            var _valor = new Array();
            var _dtVencimento = new Array();
            _valor.push($(this).val());               
            _dtVencimento[0] = new Object();
            _dtVencimento[0].DataVencimentoParcela = $("input[name='DataVencimentoParcela[]']")[_contaLinha].value;
            _movimentacao.ItemMovimentoFinanceiro.push({
                "ItemMovimentoFinanceiro": 0,
                "MovimentoFinanceiroID": $("#MovimentoFinanceiroID").val(),
                "qtdeParcela": $("#qtdeParcela").val(),
                "ValorParcela": JSON.parse(_valor),
                "DataVencimentoParcela": _dtVencimento
            });
            _contaLinha = _contaLinha + 1;
        });

        $.ajax({
            url: "/MovimentoFinanceiro/IncluirJSON",
            type: "post",
            dataType: "json",
            contentType: "application/json charset=utf-8",
            processData: false,
            data: JSON.stringify(_movimentacao),
            success: function (data) {
                console.log(data);
            },
            error: function (result) {
                alert(result.responseText);
            }
        });
    });
    
10.02.2016 / 12:36