Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input selectors being lost after HTML table data is updated after ajax call

Question background:

I have an MVC4 project with a shopping cart as shown:

enter image description here

This uses Touchspin.js to provide a way for users to update their cart Quanity of each item in the cart. The input contain selector to increment or decrement the amount:

enter image description here

The issue:

If a user deletes an item from the cart I send the specified item ID through an ajax POST request to a method on the Cart Controller which in-turn deletes it from the cart items list. Once this is completed the item list is then returned to the Success function of the ajax call which builds up the html rows of the list items and then appends them to the cart Table.

The issue is I seem to be losing the Touchspin input selector HTML when the cart item table is rebuilt from the success call. It is using the same method when the page originally loads. Here an image displaying the incorrectly formatted HTML input with the red arrows denoting the missing selectors:

enter image description here

The code:

  @{
    Layout = "~/Views/Shared/MasterLayout.cshtml";
}


<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="~/Scripts/jquery.js"></script>
<script src="~/Scripts/bootstrap.js"></script>
<script src="~/Scripts/jquery.blImageCenter.js"></script>
<script src="~/Scripts/bootstrap.touchspin.js"></script>
<script src="~/Scripts/mimity.js"></script>


    <h2>Cart</h2>
    <br />
    <table id="Table1" class="table table TableSection">
        <thead>
            <tr>
                <td style="display:none;">id</td>
                <td></td>
                <td class="TableCell"><b>Item</b></td>
                <td class="TableCell"><b>Brand</b></td>
                <td class="TableCell"><b>Unit Price</b></td>
                <td class="TableCell"><b>Quantity</b></td>
                <td></td>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
    <input class="btn btn-success btn-block updateCart" type="button" value="Update Cart" />

    @Html.Partial("_ViewCartContents")

    <div class="PaymentButtons">
        <div class="row">

            <div class="col-sm-4">

                <input class="btn btn-success btn-block updateCart" type="button" value="PayPal" onclick="location.href='@Url.Action("Index", "PayPalExpress")'" />

            </div>
            <div class="col-sm-4 pull-left">
                <input class="btn btn-success btn-block updateCart" type="button" value="Card Payment" onclick="location.href='@Url.Action("ShippingDetails", "PayPalDirectPayment")'" />
            </div>
        </div>
    </div>
</script>

AddRows is used to build up the rows of each item in the cart items list. This is append to the cart Table body.

<script type="text/javascript">

    var AddRows = function (productId, productImage, productName, productBrand, productPrice, productQty) {

        var button = '<input class="btn btn-primary btn-block deleteItem" type="button" value="Remove"/>';
        var image = '<img src="/Images/' + productImage + '" class="productCartImage"/>';
        var selectors = '<input id="demo1" type="text" value="' + productQty + '" name="demo1">';


        var $html = $('<tr class="item">' +
            '<td class="prodId" style="display:none;">' + productId + '</td>' +
            '<td class="prodImage hidden-xs">' + image + '</td>' +
            '<td class="prodName">' + productName + '</td>' +
            '<td class="prodBrand">' + productBrand + '</td>' +
            '<td class="prodPrice"> £' + productPrice + '</td>' +
            '<td class="prodQty TableCell">' + selectors + '</td>' +
            '<td>' + button + '</td>' +
            '</tr>');

        $('#Table1 > tbody:last').append($html);

    };
</script>


@foreach (var cartItem in (List<LoginTest.Models.CartItem>)ViewBag.Data)
{
    <script>
        var cartItemId = '@cartItem.CartItemId';
        var cartImage = '@cartItem.CartItemImage';
        var cartItemName = '@cartItem.CartItemName';
        var cartBrand = '@cartItem.CartItemBrand';
        var cartItemPrice = '@cartItem.CartItemPrice';
        var cartItemCartItemQty = '@cartItem.CartItemQty';

        AddRows(cartItemId, cartImage, cartItemName, cartBrand, cartItemPrice, cartItemCartItemQty);

    </script>
}

The Delete function is used to delete the specified cart item, then in the Success method rebuild the cart Items using the AddRows method.

    $(".deleteItem").click(function () {
        var $row = $(this).closest("tr");
        var $text = $row.find(".prodId").text();

        $.ajax({
            url: '@Url.Action("RemoveCartItem")',
            type: 'POST',
            data: {
                "id": $text
            },
            success: function (cartItems) {

                $('#Table1 > tbody:last').empty();

                $.each(cartItems.cartList, function (i, item) {

                    AddRows(item.CartItemId, item.CartItemImage, item.CartItemName, item.CartItemBrand, item.CartItemPrice, item.CartItemQty);

                });
            }
        });
    });
</script>

TouchSpin Input selector setup values.

<script>
    $("input[name='demo1']").TouchSpin({
        min: 1,
        max: 100,
        step: 1,
    });
</script>
like image 381
user1352057 Avatar asked Apr 15 '15 21:04

user1352057


2 Answers

You have to add Touchspin API to the input element with name demo1 every time you dynamically add it to the DOM.

There are various ways to bind API to dynamically loaded content

Method 1

You can call Touchspin on demo1 in AddRows function just before appending $html to $('#Table1 > tbody:last')

like your end of AddRows function should look like

    /*....Addrows funcion....*/
        $html.find("input[name='demo1']").TouchSpin({
        min: 1,
        max: 100,
        step: 1,
    });
    $('#Table1 > tbody:last').append($html);
};

Method 2

You can call Touchspin on demo1 in success function just after $.each function. So your success function becomes

success: function (cartItems) {
    $('#Table1 > tbody:last').empty();
    $.each(cartItems.cartList, function (i, item) {
        AddRows(item.CartItemId, item.CartItemImage, item.CartItemName, item.CartItemBrand, item.CartItemPrice, item.CartItemQty);
    });
    $("input[name='demo1']").TouchSpin({
        min: 1,
        max: 100,
        step: 1,
    });
}

However,your code needs refactoring as Ste-fu mentioned in comment, so you can return 1 or 0(or some text to differentiate between some error or OK response) and if response is something signifying that the item is removed then you remove $row from your DOM , in that case your success function would become like this

success: function (status) {
    if(status==1)//means that item is removed from database then
        $row.remove(); //remove the closest row to the clicked element                            
}
like image 59
bugwheels94 Avatar answered Nov 14 '22 15:11

bugwheels94


you should call the JS code that define TouchSpin again everytime you add new HTML content.

$(NewContentSelector). find("input[name='demo1']").TouchSpin({ min: 1, max: 100, step: 1, });

like image 33
Qusai87 Avatar answered Nov 14 '22 16:11

Qusai87