Search code examples
c#jqueryasp.net-coremodel-bindingjquery.repeater

ASP.NET Core Model Binding using jquery repeater


There are many similar question yet I don't find any suitable answers.

I use Jquery repeater repeater and repeater is working fine but I can not bind my model as input name doesn't match my model name.

So I followed this answer answer and changed the input name group-a[0][text-input] to group-a[0].text-input which works perfectly fine for the first input but as soon as I add next row input name becomes group-a[0].0

Now again I can't bind my model.

I want to ask how to solve this issue or please suggest me any better approach to bind the model. I've been searching for some days but still didn't get the answer and I'm also a beginner. Thank you

enter code here public class CreatePurchaseOrderModel
{
    [Required(ErrorMessage ="Vendor name is required")]
    public string VendorId { get; set; }

    public List<ProductDetails> ProductDetails { get; set; }

    [Required]
    public decimal TotalPrice { get; set; }
    public decimal VatAmount { get; set; }
    [Required]
    public decimal NetAmount { get; set; }
    public bool IsVatType { get; set; }
    public List<VendorModel>? Vendor { get; set; }
}

public class ProductDetails
{
    [Required(ErrorMessage = "Product name is required")]
    public string ProductId { get; set; }

    [Required(ErrorMessage = "Quantity  is required")]
    public int Quantity { get; set; }

    [Required(ErrorMessage = "Rate  is required")]
    public decimal Rate { get; set; }
}


enter code here public async Task<IActionResult> CreatePurchaseOrder(CreatePurchaseOrderModel model)
    {

        if (ModelState.IsValid)
        {
            var response = await _iPurchaseOrderService.CreatePurchaseOrder(model);
            if (response.IsSuccessStatusCode)
            {
                var responseMessage = await response.Content.ReadAsAsync<ResponseMessageModel>();
                if (responseMessage.ResponseMessage == ResponseMessage.PurchaseOrderCreatedSucessfully)
                {
                    TempData["Success"] = ResponseMessage.PurchaseOrderCreatedSucessfully;
                    return RedirectToAction("Index", "PurchaseOrder");
                }
            }
            TempData["Error"] = $"Something went wrong";
            return RedirectToAction("Index", "PurchaseOrder");
        }
        await InitializedViewBagAsync();
        var vendorListResponse = await _iPurchaseOrderService.GetAllVendorList();
        if (vendorListResponse.IsSuccessStatusCode)
        {
            var vendorList = await vendorListResponse.Content.ReadAsAsync<List<VendorModel>>();
            var vendorListmodel = new CreatePurchaseOrderModel()
            {
                Vendor = vendorList
            };
            return View(vendorListmodel);
        }
        return View(model);
    }

Solution

  • Your error was caused by this code:

    var matches = $input.attr('name').match(/\[[^\]]+\]/g);
    
     var name = matches ?
      // strip "[" and "]" characters
     last(matches).replace(/\[|\]/g, '') :
     $input.attr('name');
                            
    
     var newName = groupName + '[' + index + '].' + name +($input.is(':checkbox') || $input.attr('multiple') ? '[]' : '');
    
     $input.attr('name', newName);
    

    The code reads name from last value inside[],and I logged the values of newName, you could see how it works:

    Test1:

    enter image description here

    Test2:

    enter image description here

    To bind your model,I think it's more convenient if you would add js codes to change the input name when you submit the form rather than modify the logic in jQuery.

    I tried as below:

    <script>
        var items = document.getElementsByClassName("product");
        $('#save').click(function () {
            for (var i = 0; i < items.length; i++)
            {
                items[i].setAttribute("name", "ProductDetails["+i+"].ProductId")
            }        
        });
    </script>
    

    ......

    <div data-repeater-list="">
            <div data-repeater-item="">
                <div class="col-lg-12 col-md-12 col-sm-12">
                    <input  class="product"name="ProductId" />               
                </div>
            </div>
        </div>
    <input data-repeater-create type="button" value="Add" />
        <input id="save"type="submit" value="Save" />
    

    The result:

    enter image description here