Yes you can do that, but please bear in mind that it is not so straightforward. I will give you some basic guidelines with code. But you should look to make this as a plugin rather than change the core source code.
1. In the _ProductBox.cshtml in your theme add some markup for the textbox:
@if (!Model.ProductPrice.DisableBuyButton)
{
<table width="133" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="35">
@*@Html.TextBoxFor(model => model.EnteredQuantity, new { @class = "inputNumber" })*@
@Html.TextBox("EnteredQuantity", null, new { @class = "inputNumber" })
</td>
<td>
@*<input type="button" value="@T("ShoppingCart.AddToCart")" class="addBasket" onclick="setLocation('@(@Url.RouteUrl("AddProductToCart", new { productIdAndEnteredQuantity = string.Format("{0}-{1}", Model.Id, Model.EnteredQuantity) }))')" />*@
<input type="button" value="@T("ShoppingCart.AddToCart")" class="addBasket" data-productId="@Model.Id"/>
</td>
</tr>
</table>
}
Note the data-productId attribute in the button control. This attribute will be used in the next step.
2. Add some javascript to your Category template so that the quantity entered into the textbox can be passed to the controller action, which adds the product to the basket. The code could look something like this:
script type="text/javascript">
$(document).ready(function () {
$("input.addBasket").click(function () {
var productId = $(this).attr("data-productId");
var quantity = $(this).parent().siblings().find("#EnteredQuantity").val();
var productIdAndEnteredQuantity = productId + "-" + quantity;
var addProductToCartUrl = "@Url.RouteUrl("AddProductToCart")";
addProductToCartUrl = addProductToCartUrl + "/" + productIdAndEnteredQuantity;
setLocation(addProductToCartUrl);
});
});
</script>
What this code is doing is constructing a productid-quantity string and appending it to the url for the add to basket action.
3. In the Nop.Web.Infrastructure.RouteProvider edit the following route.
routes.MapLocalizedRoute("AddProductToCart",
"cart/addproduct/{productIdAndEnteredQuantity}",
new { controller = "ShoppingCart", action = "AddProductToCart", productIdAndEnteredQuantity = string.Empty },
new[] { "Nop.Web.Controllers" });
Please note that ideally you should register this route in a plugin and not change the core RouteProvider.
4. Add the following method to the Nop.Web.Controllers.ShoppingCartController class:
public ActionResult AddProductToCart(string productIdAndEnteredQuantity)
//public ActionResult AddProductToCart(int productId, int enteredQuantity)
{
int productId = -1;
int enteredQuantity = -1;
var elements = productIdAndEnteredQuantity.Split('-');
if (elements.Count() < 2)
return RedirectToAction("Index", "Home");
if (!int.TryParse(elements[0], out productId))
return RedirectToAction("Index", "Home");
if (!int.TryParse(elements[1], out enteredQuantity))
return RedirectToAction("Index", "Home");
var product = _productService.GetProductById(productId);
if (product == null || enteredQuantity <= 0)
return RedirectToAction("Index", "Home");
int productVariantId = 0;
if (_shoppingCartService.DirectAddToCartAllowed(productId, out productVariantId))
{
var productVariant = _productService.GetProductVariantById(productVariantId);
var addToCartWarnings = _shoppingCartService.AddToCart(_workContext.CurrentCustomer,
productVariant, ShoppingCartType.ShoppingCart,
string.Empty, decimal.Zero, enteredQuantity, true);
if (addToCartWarnings.Count == 0)
return RedirectToRoute("ShoppingCart");
else
return RedirectToRoute("Product", new { productId = product.Id, SeName = product.GetSeName() });
}
else
return RedirectToRoute("Product", new { productId = product.Id, SeName = product.GetSeName() });
}
Again this change should be done from a plugin not directly to the ShoppingCartController class.
This is it!
This is an implementation which if extracted to a plugin could be quite a good solution.
Hope you manage to implement it.