Reputation: 3182
Question background:
I have an MVC4 project with a shopping cart as shown:
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:
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:
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>
Upvotes: 7
Views: 1979
Reputation: 31950
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
}
Upvotes: 1
Reputation: 13
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, });
Upvotes: 1