0

I have a jQuery script that captures a form into an object and is supposed to send that object to a controller method. Here's the script:

var modalConfirm = function (callback) {
$("#modal-btn-si").on("click", function () {
    callback(true);
    $("#modal-confirm").modal('hide');
});
$("#modal-btn-no").on("click", function () {
    callback(false);
    $("#modal-confirm").modal('hide');
});};

function confirmar(form, text) {
$("#modal-confirm").modal('show');
modalConfirm(function (confirm) {
    if (confirm) {
        enviar(form);
    }
}); };

function enviar(form) {
debugger;
var datos = $('#' + form).serializeArray(),
    dataObj = {};
$(datos).each(function (i, field) {
    dataObj[field.name] = field.value;
});
if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; }
$.post("NuevaOpcion", {
    contentType: "application/JSON",
    data: JSON.stringify(dataObj),
}); }

Note: the script was originally much simpler, but trying to fix the issue I'm describing forced me to divide the code in the functions you see.

I created a model to receive the form's data:

public class NuevaOpcionFormModel {

    public NuevaOpcionFormModel() { }

    public int Id { get; set; }
    public string nombre { get; set; }
    public int cantidad { get; set; }
    public int precio { get; set; }
    public int idrespuesta { get; set; }
    public int OptionSelectedItem { get; set; }
}

And the controller's method signature:

[HttpPost]
    public ActionResult NuevaOpcion (Dayvo.Presupuestador.Web.Models.Form.NuevaOpcionFormModel nuevaOpcion) { ... }

What I've tried

On the script:

  • .serialize() instead of .serializeArray().
  • Not serialize at all.
  • Passing entire 'form' into object and then to controller.
  • JSON.stringify (actual state) and not using it.
  • Stablishing each field in data manually.
  • Stablishing each field in data manually and apllying JSON.stringify.

On the controller:

  • [FromForm] & [FromBody]
  • [Bind]
  • A single variable for each field, matching names and types.

Everything I've tried ends up with the controller's method receiving nothing. I tracked the script (that's why you're seeing a debugger; breakpoint in it), it gets the object into the array correctly, each field with it's proper value:

Script debug screenshot

But still hits the controller with empty object:

Controller's method debug screenshot

Any clue about what I'm doing wrong is more than welcome. Thanks in advance.

EDIT

As requested, here's the view part I'm capturing into the form:

<div class="panel-footer">
            @using (Html.BeginForm("NuevaOpcion", "Home", FormMethod.Post, new { @id = "frm_nueva_opcion" })) {
                @Html.HiddenFor(m => m.Id)
                <div class="row">
                    <div class="col-md-6">
                        <div class="form-group" style="margin-bottom: .7em;margin-top: .7em;">
                            <button class="btn btn-success btn-xs" type="button" onclick=" $('#row-nueva-opcion').toggle()" id="add-opcion">
                                <span class="glyphicon glyphicon-plus-sign"></span> A&ntilde;adir nueva opci&oacute;n
                            </button>
                        </div>
                    </div>
                </div>
                <div class="row" id="row-nueva-opcion" style="display:none">
                    <div class="col-md-10">

                        <label>
                            <input type="checkbox" id="opcion-extra" onclick=" $('#nuevo-precio').attr('disabled', !this.checked);" />
                            Es opci&oacute;n extra
                        </label>
                        <div class="input-group" style="margin-bottom:1.7em;">
                            <input type="text" placeholder="Opción" class="form-control" name="nombre" style="max-width:70%;">
                            <input type="number" placeholder="Cantidad" min="1" value="1" class="form-control" name="cantidad" style="max-width:15%;">
                            <input type="number" placeholder="Precio" class="form-control" id="nuevo-precio" name="precio" style="max-width:15%;" disabled>
                            <input type="hidden" name="idrespuesta"  id="idrespuesta" value="@listItems.Select(x=>x.Value).FirstOrDefault()" />
                            <div class="input-group-addon">&euro;</div>
                            <span class="input-group-btn">
                                <a class="btn btn-primary" data-title="Confirmación de acción" data-toggle="modal" data-target="#modal_confirm" onclick="confirmar('frm_nueva_opcion')">
                                    <span class="glyphicon glyphicon-floppy-disk"></span> Guardar
                                </a>
                            </span>
                        </div>

                    </div>
                    <div class="col-md-8">
                        <div class="form-group">
                            <label>
                                ¿Para que pregunta es la opción?
                                @Html.DropDownList("OptionSelectedItem", listItems, new { @class = "form-control" })
                            </label>
                        </div>
                    </div>
                </div>
            }
        </div>
4
  • 2
    Use .serialize(), not .serializeArray(), and you need to remove contentType: "application/JSON", and use $.post("NuevaOpcion", datos) (where datos is $('#' + form).serialize();). And that assumes the name attributes of your form match the names of the properties (you need to show your view) Commented Sep 5, 2018 at 10:14
  • @StephenMuecke Hi again and thank you very much for your answer. That actually solved it! I can't believe it, I've been suffering with this **** since yesterday. If you don't mind, can you tell me what I'm missing here? And by the way, do you want to post an answer or should I do it? Thanks again. Commented Sep 5, 2018 at 10:30
  • 1
    I'll add a answer with a bit more explanation in 30 min or so. Commented Sep 5, 2018 at 10:36
  • @StephenMuecke Thank you for your time & help, much appreciated. Commented Sep 5, 2018 at 10:38

1 Answer 1

1

The jquery $.post() method sends data using the default contentType='application/x-www-form-urlencoded; charset=UTF-8' where the data needs to be PlainObject.

For the DefaultModelBinder to bind to your model, the name/value pairs of the object need to match the model properties, so the format needs to be

var data = { Id: someValue, nombre: anotherValue, .... };

To generate that object, either generate it manually, or better, use the .serialize() method (not .serializeArray()) to correctly serialize all form controls. Change the script to

function enviar(form) {
    var data = $('#' + form).serialize();
    $.post("NuevaOpcion", data, function(response) {
        ... // code to execute when the response is returned
    });

Note it is not clear what you where expecting with the if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; } code, but it is unnecessary and can be omitted - your precio property is int and it will have a value of 0 if it is not included in the request.

I also strongly recommend you use the HtmlHelper methods to strongly bind to your model, and to ensure the correct name, value and data-val-* attributes are added for 2-way model binding and client side validation.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.