Send a list with multiple items to the controller

Well, I'm facing the following problem in a project I'm working on: how to pass a list with approx. 500~1000 lines from View to Controller?

Actually, this my list has a field called " Selected (bool)" from which the user selects only the rows he wants to generate an action, which gives around 50, 100, or even sometimes all of them.

I'm building this into a 'table' and performing a ' for ' to popular the equal. The response time to build the View is excellent, but to send the list to my controller and start validating the selected rows and subsequently write to the database is absurdly slow/stuck. My controller is receiving the List as a parameter and performing the actions upon receipt.

My Controller:

public ActionResult Create(List<MyClass> list) {
    foreach (var item in list) {
        if (item.Checked) {
            // realiza ações
        }
    }
}

My View:

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

    @* Aqui fica todo o cabeçalho (th) e componentes HTML *@

    @for (int r = 0; r < Model.Count(); r++)
    {
        <tr class="tr-clickable">
            @Html.HiddenFor(i => i[r].ID_Usuario)
            <td>@Html.CheckBoxFor(i => i[r].Checked)</td>
            <td>@Html.DisplayFor(i => i[r].Matricula)</td>
            <td>@Html.DisplayFor(i => i[r].Nome)</td>
            <td>@Html.DisplayFor(i => i[r].Value)</td>
        </tr>
    }

    @* Aqui ficam os componentes HTML restantes *@

    <div class="control-group margin-top-20 pull-right">
        <div class="controls">
            <input type="submit" class="btn btn-default" value="Gerar" />
        </div>
    </div>
}

Is there a smarter way to do this "passage"?

I thought I'd do via ajax-jQuery, passing line-by-line and recording one-by-one. Work. However, the user must have the power to submit only when he is sure of the selected lines...

Author: Antônio Filho, 2016-05-03

3 answers

If you want to pass the list to View to change only in submit, I think the best option would be to do the foreach() only with the selected items, like this:

public ActionResult Create(List<MyClass> list) {
    foreach (var item in list.Where(l => l.Selected)) {

            // realiza ações

    }
}

This way will scroll through the list only those that are selected.

 4
Author: Randrade, 2016-05-03 20:54:19

The most interesting thing would be to know how your Controller and View are doing. But I will try to show you through a practical example:

Let's imagine that you need the user to select only the products they want to buy and send to the server. However, you only need to know what is the Id of each selected product to make the purchase in fact.

The Class Product would look like this:

namespace AntonioFilho.Models
{
    public class Product
    {
        public int Id {get; set;}
        public string Name {get; set;}
        public decimal Price {get; set;}
    }
}

Or Controller would look something like this:

namespace AntorioFilho.Controllers
{
    public class ProductController : Controller
    {
        // Camada fictícia apenas para ilustração ;)
        private IProductRepository _repository = new ProductRepository();

        public ActionResult Index()
        {
             return View();
        }
        public ActionResult Buy()
        {
            IList<Product> products = _repository.GetAllProducts();
            return View(products);
        }

        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Buy(List<Product> products)
        {
            bool ok = _repository.SelectProducts(products);
            return RedirectToAction("Index");
        }
    }
}

Already your View would be like this:

@model IList<Product>

@using (Html.BeginForm("Buy", "Product", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    <table>
        <tr>
            <th><input type="checkbox" id="checkall" /></th>
            <th>Product name</th>
        </tr>
    @for(int i = 0;i < Model.Length;i++)
    {
        <tr>
            <td>
                @Html.HiddenFor(m => Model[i].Price, new { @disabled = "disabled", @id = String.Format("product{0}", i) })
                @Html.CheckboxFor(m => Model[i].Id, new { @class = "check", @idFake = String.Format("product{0}", i) })
            </td>
            <td>@Model[i].Name</td>
        </tr>
    }
        <tr>
            <td colspan="2">
                <input type="submit" value="comprar" />
            </td>
        </tr>
    </table>
}

<script>
    $(document).ready(function() {
        $('.check').click(function(){
            var id = $(this).attr('idFake');
            if(this.checked)
                $('#' + id).removeAttr('disabled');
            else
                $('#' + id).attr('disabled', 'disabled');
        });
    });
</script>

I hope I helped \o /

 2
Author: Uilque Messias, 2016-05-04 17:52:02

I solved this problem using jQuery-Ajax:

   $('input[type="button"][data-submit]').click(function () {

        if (confirm('Você confirma?')) {

            var array = [];

            $('#table > tbody > tr').each(function () {
                var $tr = $(this);
                // aqui é só colocar algo que filtre apenas as tr's com um checkbox igual a true (':checked')
                var usid = $tr.find('[data-usid]').val();
                var irvlr = $tr.find('[data-irvlr]').val();
                array.push({
                    User: usid,
                    Value: irvlr
                });
            });

            if (array.length > 0) {
                $.ajax({
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    type: 'POST',
                    url: '@Url.Action("MyAction", "MyController")',
                    data: JSON.stringify({ 'list': array }),
                    success: function (result) {
                        window.location.href = result.url;
                    },
                    error: function (ex) {
                    }
                });
            }
            else {
                alert('No items selected.');
            }

        }

    });

Thank you all!

 1
Author: Antônio Filho, 2016-06-02 19:11:45