Reputation: 1891
I'm creating a shopping cart with angular 1.5.x and am really trying to focus on doing things the proper 'Angular Way.' I have a product list (ng-repeat
), in which the user can adjust quantity of any item (ng-model
), then add that item (and associated quantity) to their cart (ng-click
).
The issue I am having is what variable to assign to ng-model in the quantity input. I don't wish to update the ctrl.productList
array, so I figured I would create a seperate ctrl.itemQuantity
primitive. However, with ng-repeat
each input box then changes when one is changed.
My solution currently is to initialize a new primitive property with a dynamic name using $index
in ng-model
within the html (but not initialize it in the controller).
This works fine, but seems a bit hacky, and the inputs all start as blank rather than 0 because the ng-model
begins undefined. If this is truly the way to go, I suppose I could initialize all of the ng-model
variables by running a forEach
on ctrl.productsList
and assigning each to 0.
Does anyone have a better way to go about this? It seems like a fairly common situation.
Markup:
<div class="section-container product-container">
<div class="section-header product" ng-repeat="product in products.productList">
<div class="product-info">
<div>{{ product.name }} - <span>{{ product.price | currency }}</span></div>
<div><a href="">{{ product.brand }}</a></div>
</div>
<div class="product-selection">
<label for="product-quantity-{{$index}}">Quantity: </label>
//Initialize new dynamically named ng-model for each quantity input
<input id="product-quantity-{{$index}}" type="number" ng-model="products['quantity-' + $index]">
<a href="" class="product-cart-btn" ng-click="products.addCart(product, $index)">+</a>
</div>
</div>
</div>
Controller:
function ProductsController() {
var ctrl = this;
//Cart
ctrl.cartList = [];
ctrl.addCart = function(product, index){
if(ctrl.cartList.indexOf(product) === -1){
ctrl.errorMessage = '';
console.log(ctrl);
//Add input value here
product.quantity = ctrl['quantity-'+index];
ctrl.cartList.push(product);
//Reset input value
ctrl['quantity-'+index]=0;
}else{
ctrl.errorMessage = "Your cart already contains " + product.name + " by " + product.brand +
". Please visit your cart to adjust item quantities.";
}
};
//Products
ctrl.productList = [
{
name: 'Tissue (50 Ct)',
brand: 'Kleenex',
price: '5.00'
}, {
name: 'Whole Wheat Bread',
brand: 'Roman Meal',
price: '3.27'
}, {
name: 'Chili Spiced Mango',
brand: "Trader Joe's",
price: '4.56'
}
];
}
Please let me know if I need to explain further. Cheers!
Upvotes: 0
Views: 300
Reputation: 405
Create a product selector directive to wrap the product
If you implemented it using transclude it might look like this:
<div class="section-container product-container">
<div class="section-header product" ng-repeat="product in products.productList">
<div class="product-info">
<div>{{ product.name }} - <span>{{ product.price | currency }}</span></div>
<div><a href="">{{ product.brand }}</a></div>
</div>
<product-selector product="product" on-product-selected="addCart">
<div class="product-selection">
<label for="product-quantity-{{$index}}">Quantity: </label>
//Initialize new dynamically named ng-model for each quantity input
<input id="product-quantity-{{$index}}" type="number" ng-model="quantity">
<a href="" class="product-cart-btn" ng-click="FireProductSelected(product, quantity)">+</a>
</div>
</product-selector>
</div>
</div>
Otherwise it might look like this:
<div class="section-container product-container">
<div class="section-header product" ng-repeat="product in products.productList">
<product-selector product="product" on-product-selected="addCart"></product-selector>
</div>
</div>
Upvotes: 1
Reputation: 664
I don't know that this is a great practice, but since ng-repeats generate their own private scope, you can actually generate a scope variable within the input tag. If you want it to show as "0" by default you can use ng-init to set it to 0 (again, probably not the cleanest).
<input id="product-quantity-{{$index}}" type="number" ng-model="quantity" ng-init="quantity = 0;" />
<a href="" class="product-cart-btn" ng-click="products.addCart(product, quantity)">+</a>
That should do the trick, I'll let you decide whether it's less hacky ;)
Upvotes: 0