Search code examples
javascriptc#asp.net-mvcasp.net-corepost

POST List of Objects in ASP.Net Core MVC


I can't post list of objects (Count is unknown) from view to Controller. I worked something out and here what I do with JS. I have a button to add 2 inputs and a remove button beside that row of 2 inputs. each of the inputs has the name of the Model like Product.Features[0].TitleName and Product.Features[0].Value

everything works fine but the problem is that if we have 3 inputs and user click on the remove button of index 1, then after posting the form, just index 0 will post and ignore index 2!

How can I do something to have inputs as many as user wants and has the ability to remove in any order.

My Model is a product model that has many things and has List of ProductFeatures Model:

public class ProductFeature
{
    public int Id { get; set; }
    public required string TitleName { get; set; }
    public required string Value { get; set; }
}

my HTML :

<div class="accordion-body w-50">
    <div id="features" class="form-group">
    </div>
    <input id="cmdAdd1" class="btn btn-primary" type="button" value="افزودن ویژگی" />
</div>

and here is the JS:

var itemCount = 0;
const removedItems = [];

$('#cmdAdd1').click(function () { addNewFeature(); });

function addNewFeature() {
// Add new line with text field and button
    if (removedItems.length == 0) {
        var newItem = ' <div id="item' + itemCount + '" class="input-group mb-2">';
        newItem += '<input id="title' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].TitleName" placeholder="عنوان" class="form-control" type="text"/>';
        newItem += '<input id="value' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].Value" placeholder="مقدار" class="form-control" type="text"/>';
        newItem += '<input id="cmdAdd' + itemCount + '" type="button" class="btn btn-danger" value="حذف ویژگی"></input>';
        newItem += "</div>";

        $('#features').append(newItem);
        var thisItem = itemCount;
        $('#cmdAdd' + itemCount).click(function () { removeItem(thisItem); });
        itemCount++;
    }
    else {
        var id = removedItems[0];
        var newItem = ' <div id="item' + id + '" class="input-group mb-2">';
        newItem += '<input id="title' + id + '" name="Product.ProductFeatures[' + id + '].TitleName" placeholder="عنوان" class="form-control" type="text"/>';
        newItem += '<input id="value' + id + '" name="Product.ProductFeatures[' + id + '].Value" placeholder="مقدار" class="form-control" type="text"/>';
        newItem += '<input id="cmdAdd' + id + '" type="button" class="btn btn-danger" value="حذف ویژگی"></input>';
        newItem += "</div>";

        $('#features').append(newItem);
        thisItem = id;
        $('#cmdAdd' + id).click(function () { removeItem(thisItem); });
        removedItems.splice(0, 1);
    }
}

function removeItem(i) {
    $('#item' + i).remove();
    removedItems.push(i);
}

Solution

  • The issue you're facing seems related to how the items are indexed when adding and removing them dynamically in your JavaScript code. When an item is removed, the array "removedItems" keeps track of removed indexes, but it doesn't rearrange the indexes of the existing items, causing a mismatch between the indexes in the form data and the actual items on the page.

    One way to solve this issue is to re-index the input fields' names when an item is removed.

    var itemCount = 0;
    
    $('#cmdAdd1').click(function () { addNewFeature(); });
    
    function addNewFeature() {
        var newItem = '<div id="item' + itemCount + '" class="input-group mb-2">';
        newItem += '<input id="title' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].TitleName" placeholder="عنوان" class="form-control" type="text"/>';
        newItem += '<input id="value' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].Value" placeholder="مقدار" class="form-control" type="text"/>';
        newItem += '<input id="cmdAdd' + itemCount + '" type="button" class="btn btn-danger" value="حذف ویژگی"></input>';
        newItem += '</div>';
    
        $('#features').append(newItem);
        var thisItem = itemCount;
        $('#cmdAdd' + itemCount).click(function () { removeItem(thisItem); });
        itemCount++;
    }
    
    function removeItem(i) {
        $('#item' + i).remove();
        // Re-index the remaining items
        reIndexItems();
    }
    
    function reIndexItems() {
        var items = $('#features').children();
        items.each(function (index) {
            var id = 'item' + index;
            $(this).attr('id', id);
            $(this).find('input[type=text]').each(function () {
                var inputName = 'Product.ProductFeatures[' + index + '].' + $(this).attr('name').split('.')[2];
                $(this).attr('name', inputName);
            });
            $(this).find('input[type=button]').attr('onclick', 'removeItem(' + index + ')');
        });
    }
    This code should dynamically adjust the indexes of the remaining items whenever one is removed, ensuring that all the indexes are aligned properly when the form is submitted.