Send a ListT with several items to the controller

1

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

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

I'm building this on a 'table' and performing a 'for' to popular the same. The response time to build the View is excellent, but to send the list to my controller and start validating the selected rows and later write to the database is absurdly slow / slow. My controller is getting the List as 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 any smarter way to do this "pass"?

I thought of doing via ajax-jQuery, passing line-by-line and recording one-by-one. It works. However, the user has to have the power to only submit when he is sure of the selected rows ...

    
asked by anonymous 03.05.2016 / 19:59

3 answers

1

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!

    
02.06.2016 / 21:11
4

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

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

            // realiza ações

    }
}

This will scroll through the list only of those that have been selected.

    
03.05.2016 / 22:54
2

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

Let's imagine that you need the user to select only the products that he wants to buy and send to the server. However, you just need to know what Id of each product selected to actually purchase.

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;}
    }
}

The 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");
        }
    }
}

Your View would look 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 have helped \ o /

    
04.05.2016 / 18:48