locked
Cannot pass list of objects from view to controller via Ajax RRS feed

  • Question

  • User-1668256174 posted

    Hello everybody,I cannot pass a list of objects to a controller via Ajax.

    However my code is simple :

    Here is the object class : 

    public class OptionDTO
        {
    
            public string ID_OPTION { get; set; }       
            public string LI_VALUE { get; set; }
    
        }

    Here is my view : 
    </div> <div>

    <div class="col-lg-12 col-md-12 col-xs-12" id="divOption">
    
        <table id="TableOption">
           @foreach (var item in Model)
           {
            <tr class="item">
                <td>@item.LI_OPTION</td>
                <td>
                        <input type="text" class="option-value" data-id="@item.ID_OPTION" />
                </td>
            </tr>
           }
        </table>
    </div>
    <input id="ButtonValidate" type="button" value="Validation" onclick="fctValidate()" />
    
        <script>
        
        function fctValidate() {
            var lstOption = [];
            try
            {
                $(".option-value").each(function(){
                    var oOption = new Object();
                    oOption.ID_OPTION = $(this).attr('data-id');
                    oOption.LI_VALUE = $(this).val();
                    lstOption.push(oOption);
                });
            } catch (error) {
                alert(error);
            }
    
            $.ajax({
                type: "POST",
                traditional: true,
                url: '@Url.Action("CreateOption", "CreateOption")',
                data: { "lstOption": lstOption },
                dataType: "json",
                error: function (xhr, status, error) {
                    var err = eval("(" + xhr.responseText + ")");
                    alert(err.Message);
                }
            });
        }
    </script>

    and here is the controller:

        [HttpPost]
        public void CreateOption(List<OptionDTO> lstOption)
        {
           string dd = "";
        }


    I fill the input "txt" with values (several rows in the table).

    I have checked in the javascript that the list contains several rows.
    And when I click on the Validation button the code goes to the controller but the parameter lstOption remains empty.
    Could you help me, please ?

    Thanks a lot in advance.

    Eric.

    Tuesday, November 24, 2020 1:57 PM

Answers

  • User475983607 posted

    I built a test based on your code which works as expected.  Compare your code to the the following.

            [HttpGet]
            public IActionResult Index()
            {
                return View();
            }
    
           [HttpPost]
            public ActionResult CreateOption(List<OptionDTO> lstOption)
            {
                return Json(lstOption);
            }
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <div>
        @for (int i = 0; i < 5; i++)
        {
            <input type="text" class="option-value" data-id="@i" value="value @i" />
        }
    
    </div>
    <div>
        <input id="ButtonValidate" type="button" value="Validation" onclick="fctValidate()" />
    </div>
    
    @section scripts {
        <script>
           function fctValidate() {
               var lstOption = [];
    
               $(".option-value").each(function () {
                lstOption.push({
                    ID_OPTION: $(this).data('id'),
                    LI_VALUE: $(this).val()
                });
            });
    
               console.log(lstOption);
               $.ajax({
                   type: "POST",
                   url: '@Url.Action("CreateOption")',
                   data: { 'lstOption': lstOption },
                dataType: "json",
                success: function (response) {
                    console.log(response);
                },
                error: function (xhr, status, error) {
                    console.log(err.Message);
                }
            });
        }
        </script>
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, November 24, 2020 3:10 PM

All replies

  • User475983607 posted

    I built a test based on your code which works as expected.  Compare your code to the the following.

            [HttpGet]
            public IActionResult Index()
            {
                return View();
            }
    
           [HttpPost]
            public ActionResult CreateOption(List<OptionDTO> lstOption)
            {
                return Json(lstOption);
            }
    @{
        ViewData["Title"] = "Index";
    }
    
    <h1>Index</h1>
    
    <div>
        @for (int i = 0; i < 5; i++)
        {
            <input type="text" class="option-value" data-id="@i" value="value @i" />
        }
    
    </div>
    <div>
        <input id="ButtonValidate" type="button" value="Validation" onclick="fctValidate()" />
    </div>
    
    @section scripts {
        <script>
           function fctValidate() {
               var lstOption = [];
    
               $(".option-value").each(function () {
                lstOption.push({
                    ID_OPTION: $(this).data('id'),
                    LI_VALUE: $(this).val()
                });
            });
    
               console.log(lstOption);
               $.ajax({
                   type: "POST",
                   url: '@Url.Action("CreateOption")',
                   data: { 'lstOption': lstOption },
                dataType: "json",
                success: function (response) {
                    console.log(response);
                },
                error: function (xhr, status, error) {
                    console.log(err.Message);
                }
            });
        }
        </script>
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, November 24, 2020 3:10 PM
  • User-474980206 posted

    Your Ajax call is incorrect. You are doing a form post, which is name / value pairs. The to string of lstOptions is not what you want. Using the browsers network debugger would have shown this. Try sending as json

            $.ajax({
                type: "POST",
                traditional: true,
                url: '@Url.Action("CreateOption", "CreateOption")',
                data: JSON.stringify(lstOption),
                contentType: “application/json”,
                dataType: "json",
                error: function (xhr, status, error) {
                    var err = eval("(" + xhr.responseText + ")");
                    alert(err.Message);
                }
            });

    Also you should not use eval().

    Tuesday, November 24, 2020 3:34 PM
  • User-1668256174 posted

    mgebhard, bruce :
    Thank you for your answers.
    I will check them and will let you know.
    Eric.

    Tuesday, November 24, 2020 8:46 PM
  • User1686398519 posted

    Hi eric.bryan, 

    I have another solution, you can refer to it.

    Controller

        public class TestAjaxController : Controller
        {
            // GET: TestAjax
            public ActionResult Index()
            {
    //Here is the test data var data = new List<OptionDTO> { new OptionDTO{ ID_OPTION="ID_OPTION1",LI_VALUE="LI_VALU1"}, new OptionDTO{ ID_OPTION="ID_OPTION2",LI_VALUE="LI_VALU2"}, new OptionDTO{ ID_OPTION="ID_OPTION3",LI_VALUE="LI_VALU3"}, new OptionDTO{ ID_OPTION="ID_OPTION4",LI_VALUE="LI_VALU4"} }; return View(data); } [HttpPost] public void CreateOption(List<OptionDTO> lstOption) { string dd = ""; } }

    View

    @model IEnumerable<DailyMVCDemo.Models.OptionDTO>
    <div class="col-lg-12 col-md-12 col-xs-12" id="divOption">
        <form id="testform">
            <table id="TableOption">
                @for (var i = 0; i <Model.ToList().Count(); i++)
                {
                    <tr class="item">
                        <td>
                            @Html.DisplayTextFor(m => Model.ToList()[i].ID_OPTION)
                            @Html.HiddenFor(m => Model.ToList()[i].ID_OPTION)
                        </td>
                        <td>
                            @Html.TextBoxFor(m => Model.ToList()[i].LI_VALUE)
                        </td>
                    </tr>
                }
            </table>
        </form>
    </div>
    <input id="ButtonValidate" type="button" value="Validation" onclick="fctValidate()" />
    @section scripts{
        <script>
            function fctValidate() {
                $.ajax({
                type: "POST",
                traditional: true,
                url: '@Url.Action("CreateOption", "TestAjax")',
                data: $("#testform").serialize(),
                dataType: "json",
                error: function (xhr, status, error) {
                    var err = eval("(" + xhr.responseText + ")");
                    alert(err.Message);
                }
            });
        }
        </script>
    }

    Here is the result. 

    Best Regards,

    YihuiSun

    Wednesday, November 25, 2020 5:26 AM
  • User-1668256174 posted

    Bruce, YihuiSun :
    Thank you very much for your answers.
    I have checked mgebhard answer and it works, it suits my needs.

    Wednesday, November 25, 2020 9:53 AM