简体   繁体   中英

ASP.Net MVC Sending Table data from view to controller

I have a table in my view for what is essentially my attempt at making a timesheet table. It also contains a button for adding more rows to the table.

<table class="table table-bordered table-responsive table-hover" id="mytab" cellspacing="0" cellpadding="0">  
        <thead>
            <tr>  
                <th>Project</th>   
                <th>Discipline</th>  
                <th>Mo</th>  
                <th>Tu</th>  
                <th>We</th>  
                <th>Thu</th>  
                <th>Fri</th>  
                <th>Sat</th>  
                <th>Sun</th>  
                <th></th>
            </tr>  
        </thead>
        <tr>
            <td><select name="selectedProjectId" asp-items="@ViewData["projectSubProject"] as SelectList" class="form-control-plaintext align-content-around">
            </select></td>  
            <td><select name="selectedPositionId" asp-items="@ViewData["Positions"] as SelectList" class="form-control-plaintext align-content-around"></select></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td>  
            <td><input class="form-control-plaintext align-content-around txtCal" type="number" min="1" max="24"/></td> 
        </tr>
    </table> 
    <br />
    <form action="">
        <input type="button" value="Add a Row" onclick="addRow()">
    </form>

It looks like this in the web page

The script for adding rows to the table and the script for what should , from what i gather, send the table data in json format to controller on table data change look like this:

$(document).ready(function(){
        $("#myTable").on('input', '.txtCal', function () {
               var calculated_total_sum = 0;
 
               $("#myTable .txtCal").each(function () {
                   var get_textbox_value = $(this).val();
                   if ($.isNumeric(get_textbox_value)) {
                      calculated_total_sum += parseFloat(get_textbox_value);
                      }                  
                    });
                      $("#total_sum_value").html(calculated_total_sum);
               });

        });

        function addRow() {
            var root = document.getElementById('mytab').getElementsByTagName('tbody')[0];
            var rows = root.getElementsByTagName('tr');
            var clone = cloneEl(rows[rows.length - 1]);
            cleanUpInputs(clone);
            root.appendChild(clone);
        }
        
        function cloneEl(el) {
            var clo = el.cloneNode(true);
            return clo;
        }

        function cleanUpInputs(obj) {
          for (var i = 0; n = obj.childNodes[i]; ++i) {
            if (n.childNodes && n.tagName != 'INPUT') {
              cleanUpInputs(n);
            } else if (n.tagName == 'INPUT' && n.type == 'number') {
              n.value = '';
            }
          }  
        }

        $('input').change(function () {
            var table = document.getElementById("mytab");
            var rows = table.getElementsByTagName("tr");
            var data = [];
            for (var i = 0; i < rows.length; i++) {
                var cells = rows[i].getElementsByTagName("td");
                var row = [];
                for (var j = 0; j < cells.length; j++) {
                    var cell = cells[j];
                    row.push(cell.innerText);
                }
                data.push(row);
            }
            $.ajax({
                type: "POST",
                url: '@Url.Action("TableList", "Home")',
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    alert("success");
                },
                failure: function (data) {
                    alert("can not update the timesheet");
                }
            });
        });

And finally, my controller methods look like this:

public async Task<IActionResult> TableList()
    {
        var projectSubProject = await _context.SubProject.Include(x => x.Project).ToListAsync();
        ViewData["projectSubProject"] = new SelectList(projectSubProject, "Id", "DisplayId");
        ViewData["Positions"] = new SelectList(await _context.Position.ToListAsync(), "Id", "Title");

        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> TableList(string JSON)
    {
        if (ModelState.IsValid)
        {
            var list = JsonConvert.DeserializeObject(JSON);
        }

        return View();
    }

The problem that i think i'm encountering is that the JSON data doesn't actually reach the controller, since putting a break point anywhere on the Post method doesn't ever trigger it.

Am i doing something wrong? Am i missing some crucial step? Is there perhaps an easier way of doing what i want to do?

I would probably use a Model for that something like a Row class list.

Like this:

public class Row
{
    public string Project   {get;set;}
    public string Discipline {get;set;} 
    public string Mo  {get;set;}
    public string Tu  {get;set;}
    public string We  {get;set;}
    public string Thu  {get;set;}
    public string Fri  {get;set;}
    public string Sat  {get;set;}
    public string Sun  {get;set;}
}

public class TableModel
{
    public List<Row> Rows {get; set;}
}

And then I would set all the actions to interact with the model.

This would make your work easier.

I also suggest to take a look at the microsoft documentation since you are missing the use of models.

There're several points you need to care. Firstly, you are now trying to use ajax to send post request to your controller, it's different from the default form submit in asp.net core MVC. Hence, [ValidateAntiForgeryToken] and if (ModelState.IsValid) are not suitable for your scenario.

Then, when you use data: JSON.stringify(data) to set it as the request data, it will generate payload like this, you can't use string to receive the data, you need to use List<object> data :

在此处输入图像描述 在此处输入图像描述 在此处输入图像描述

You may change your code like this:

@section Scripts{
    <script>
        $("#btn1").click(function(){
            var data = [];
            var row1 = [1, 2, 3, 4, 5];
            var row2 = [6,7,8,9,10];
            data.push(row1);
            data.push(row2);
            $.ajax({
                url: "https://localhost:7175/Home/TableList",
                type: "post",
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (data) {
                    alert(data);
                }
            });
        });
    </script>
}

[HttpPost]
//[ValidateAntiForgeryToken]
public string TableList([FromBody]List<object> data)
{
    //if (ModelState.IsValid) { 
    //    var list = JsonConvert.DeserializeObject(json);
    //}
    return "hello";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM