1

I am presenting the question with the wording shown so that it indicates what I am really trying to do. While I could present the question as, "How can I use jQuery to read a table's contents an convert to type IEnumerable<ModelName>?" I would be hiding important context that could suggest a far better way of achieving this outcome, which is what I'm really hoping for.

When auto-scaffolding a controller and views from a model (using Entity Framework), the resulting view allows one to edit one record at a time by clicking the row, editing the record, and returning to the Index. For many cases that is the desired functionality.

But what about when one wants to mass-update values in a table, as if one were working on a spreadsheet. For example, toggle some checkboxes and click "Update", like in this scenario.

enter image description here

One working idea I have is to use jQuery to:

  1. Read the table data and convert into a variable of type IEnumerable<SampleModel>.
  2. Pass the table contents to a public void method in the controller.
  3. Notify the user that the action was successful and refresh the page.

It's really #1 where I am stuck because I need to be able to pass an object of type IEnumerable<SampleModel> to the controller's method, and I do not know how to do this.

Controller:

public void UpdateTable(IEnumerable<SampleModel> query)
{
    // I'm verifying existence before writing code here.
    // This is where I'll be updating the database.
    Debug.WriteLine("Test for query existence " + query.Count());
}

View:

@model SampleSystem.Areas.FakeName

<button id="UpdateTableTop">Update</button>

<table class="table">
    <tr>
        <th></th>
        <th>
            @Html.DisplayNameFor(model => model.Reconciled)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.StudentID)
        </th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.HiddenFor(modelItem=>item.ID)
            </td>
            <td>                    
                @Html.CheckBoxFor(modelItem => item.Reconciled)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.StudentID)
            </td>               
        </tr>
    }
</table>

@section scripts {
    <script>
        $(function () {
            $("UpdateTableTop").click(function (e) {                
                $.ajax({
                    url: '@Url.Action("UpdateTable")',
                    data: 
                    /* ...  Need to convert table 
                     *      to IEnumerable<SampleModel>  ...
                    */,
                    success: function (){
                        console.log("Success!");
                    }
                });
            });
        });
    </script>
}
  • For the data, you could just pass properly formatted JSON to your controller. – Jack Marchetti Aug 11 '16 at 17:39
  • I don't understand, why don't you just wrap the entire table into a form and just submit all the values? What do you need jQuery for? – tocqueville Aug 11 '16 at 17:46
  • @FrancescoLorenzetti84 -- The short answer is because it's more complicated than you know. I was trying to keep things simple enough to head off complaints that I shouldn't be posting too much code. :) –  Aug 11 '16 at 17:48
  • Generate your view correctly using a `for` loop or custom `EditorTemplate` (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943)) and then all you need is `data: $('form').serialize()` in you ajax options to correctly serialize the form and post it back to the controller. –  Aug 12 '16 at 01:33
  • The you need to modify the method to `public JsonResult UpdateTable(IEnumerable query)` and return something back to the client (e.g. `Json(true);` assuming success). But why in the world would you want to refresh the page? –  Aug 12 '16 at 01:36

2 Answers2

1

This is not a complete answer, but should lead you in the correct direction.

        $("UpdateTableTop").click(function (e) {                
           var selectedModels = [];

           // Get all of the rows that were selected

           // Loop through each row, create an object and add to array
           for(var i = 0; i < numItemsSelected; i++)
           {
              // Make sure the properties of the model match your definition of SampleModel
               var currentModel = {
                                      Reconciled = ??? , //Reconciled from the current row
                                      StudentID = ???
                                   };
               selectedModels.push(currentModel);
           }

            $.ajax({
                url: '@Url.Action("UpdateTable")',
                data: /* pass in the list of models (selectedModels) */,
                success: function (){
                    console.log("Success!");
                }
            });
        });

On the server-side, model-binding will take care of creating the SampleModel based on the posted values.

Andy T
  • 10,223
  • 5
  • 53
  • 95
  • In this case, I need to capture the entire table to capture both checked and unchecked values. Still, it gives me an approach. –  Aug 11 '16 at 17:47
1

One more possible approach in addition to previous answer. Add data attribute to the checkbox

@Html.CheckBoxFor(modelItem => item.Reconciled, new { data_myid = item.ID }) /* the _ gets converted to - */

Later, use jQuery to retrieve all checked checkboxes.

var selectedIds = new Array();
$( "input:checked" ).each(function(eachCheckbox){
    selectedIds.push($(eachCheckbox).data('myid'));// could serialize to JSON but if the update action is the same for all id's then there is no need for additional data transfer
});

Then pass selectedIds as your data in ajax call and notify on success.

On the server side:

public void UpdateTable(IEnumerable<int> query) /* change type to int */
{
    Debug.WriteLine("Test for query existence " + query.Count());
}
bvoleti
  • 2,472
  • 1
  • 18
  • 20
  • I'm liking your approach more now, but when I do a console test of `console.log($(eachCheckbox).data('myid'));` I'm getting "undefined" per each checkbox, rather than the row ID. –  Aug 11 '16 at 19:37
  • 1
    Remove the parameter eachCheckbox from the function signature and replace it in the push statement with $(this).data('myid') – JB06 Aug 11 '16 at 19:58
  • Rubix_Revenge: Good to hear that it worked for you. @JB06 thanks for the fix. – bvoleti Aug 12 '16 at 16:06