1

I have a razor view which renders on Get call to Controller,

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            <div>
                @Html.LabelFor(model => model.StartTime, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-2">
                    @Html.EditorFor(model => model.StartTime, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.StartTime, "", new { @class = "text-danger" })
                </div>
            </div>
            <div>
                @Html.LabelFor(model => model.EndTime, htmlAttributes: new { @class = "control-label col-md-1" })
                <div class="col-md-2">
                    @Html.EditorFor(model => model.EndTime, new { htmlAttributes = new { @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.EndTime, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.SampleTimes, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-2">
                @Html.DropDownListFor(model => model.SelectedSampleTime, Model.SampleTimes, htmlAttributes: new { @class = "selectpicker form-control", @data_actions_box = "true" })
                @Html.ValidationMessageFor(model => model.SelectedSampleTime, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Measurands, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-2">
                @Html.DropDownListFor(model => model.SelectedMesurands, Model.Measurands, htmlAttributes: new { @class = "selectpicker form-control", @multiple = "", @data_actions_box = "true" })
                @Html.ValidationMessageFor(model => model.SelectedMesurands, "", new { @class = "text-danger" })

            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.Customers, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-2">
                @Html.DropDownListFor(model => model.SelectedCustomers, Model.Customers, htmlAttributes: new { @class = "selectpicker form-control", @multiple = "", @data_actions_box = "true" })
            </div>
        </div>
           <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                @*<input value="Run Report" class="btn btn-default" id="btnRunReport" type="submit" data-toggle="modal" data-target="#reportModal" />*@
                <input value="Run Report" class="btn btn-default" id="btnRunReport" />
            </div>
        </div>
    @Html.Partial("_reportsModal")
}

In the same controller , I have a Index Post,

[HttpPost]
        public JsonResult Index(ReportViewModel vm)
        {

            List<MultiStoredProcedureReturnData> listSpData = new List<MultiStoredProcedureReturnData>();

            List<Chart> chartList = new List<Chart>();

            if (ModelState.IsValid)
            {
                Chart chartData = new Chart();

                string sleectedMeasurandName = "";
                foreach (var item in vm.SelectedMesurands)
                {

                    listSpData.Add(new MultiStoredProcedureReturnData());
                   //Some more updates

                    chartData = UpdateChart();
                    chartList.Add(chartData);
                }

            }


            return Json(chartList);
        }

Now , I want to call this method on button click , but It can not be, as it will return json data to browser.

Instead, I want to use jQuery click event , get all JsonData using Post , and then update a chart on the Index page from return data and display on modal.

I tried doing following, but as expected, I lost all model binding. Is there a way to use jQuery and not loose the data. I can go ahead and get the value from each element and then create a post request. But it would be lot nicer to use the existing model binding and get the data back!!

 $('#btnRunReport').click(function (e) {
                e.preventDefault();
                $.ajax({
                    type: "POST",
                    url:"Reports/Index",
                    success: function (result) { console.log(result); }
                });
            });
Simsons
  • 12,295
  • 42
  • 153
  • 269
  • 3
    Just add `data: $('form').serialize()` to post back the form values. But you really should be handling the forms `.submit()` event (not a button event) and checking if if the form is valid before you make your ajax call (and cancel the call if its not) –  Feb 01 '18 at 09:51
  • so , trigger form submit from click of button? – Simsons Feb 01 '18 at 09:56

1 Answers1

4

To serialize the form controls you can use $('form').serialize();

However, you should be handling the forms submit event rather than the buttons click event so that client side validation is triggered and you can test if the data is valid

$('form').submit(function(e) { // consider giving your form an id attribute and using that as the selector
    if (!$(this).valid()) {
        return; // cancel and display validation errors   
    }
    var formData = $(this).serialize();
    $.ajax({
        url: '@Url.Action("Index", "Reports")', // always use `Url.Action()
        type: "POST",
        data: formData,
        success: function (result) {
            ....
        }
    });
    return false; // this is just an alternative to using e.preventDefault
}
  • Thanks much , I was worried how to submit so many values with out model biding , as getting value from each element is trouble sum and hard to maintain. Many Thanks again!! – Simsons Feb 01 '18 at 10:13
  • 1
    You also have another problem with your view. Your `foreach (var item in vm.SelectedMesurands)` in the view means `SelectedMesurands` is `IEnumerable` which mean you must use `ListBoxFor()`, not `DropDownListFor()` - refer [Why does the DropDownListFor lose the multiple selection after Submit but the ListBoxFor doesn't?](https://stackoverflow.com/questions/40725358/why-does-the-dropdownlistfor-lose-the-multiple-selection-after-submit-but-the-li/40732481#40732481) –  Feb 01 '18 at 10:17
  • Ditto for the `SelectedCustomers` property –  Feb 01 '18 at 10:18
  • Will change that as this is a better approach. I did refer to the link , but I am getting collection of selected items back in my controller with Fordropdown !! – Simsons Feb 01 '18 at 10:33
  • Yes, but you cannot set it initially (i.e. the binding from the controller to the view does not work - if `SelectedMesurands` is set to an array containing say `[1, 4]`, in the GET method, then the options with values 1 and 4 will not be selected in the view –  Feb 01 '18 at 10:38