user1453870 user1453870 - 6 months ago 31
AngularJS Question

Directive take other directive's data after deletion

Edit: Thanks to Simon Sch├╝pbach, I was able to resolve the issue by changing the template. See the end for the solution.

Let's preface this by saying that we are beginner to soft-intermediate in Angular.

On one of our project, we are using angularjs 1.4.x and also ng-cart (https://github.com/snapjay/ngCart). It worked great but then we were confronted with a demand from our client that created new weird issues.

We added fsCounter, as a directive, to the cart page so user can add or remove items. This all work great but the users also have the option to delete an item from the cart view. Deletion works as expected BUT it seems to affect the scope to the item that takes it place.

Let me make it clearer :
Let's say we have 2 products in our cart page, it displays something like that

Product_1 {price} {counter} {total} delete_btn
Product_2 {price} {counter} {total} delete_btn


Each fsCounter is its own scope

return {
restrict: "A",
scope: {
value: "=value",
index: "=index"
},
link: //other logic


However when we delete the first item, visually and in the directives, the data seems to shift. So our second row will now inherit the first row's counter.
Directive's data looks like this:

Product_1:
itemId:3,
quantity:2,
{other data}

Product_2:

itemId:8,
quantity:5,
{other data}


But once we delete the first directive (We get the scope, remove the DOM element, destroy the scope) the second directive will now have this data:

Product_2:
itemId:3,
quantity:2,
{other data}


Here is the template code :

<div class="unItem" ng-repeat="item in ngCart.getCart().items track by $index">
<div class="photo"><img src="{[{ item.getImage() }]}" alt=""></div>
<div class="details">
<h3>{[{ item.getName() }]} <span>{[{ item.getPrice() | currency:$}]}</span></h3>
<md-select ng-model="attributes" placeholder="Attribut" class="select-attribut" ng-show="item.hasAttributes()" ng-change="item.updateSelected(attributes)">
<md-option ng-repeat="attr in item.getAttributes()" ng-selected="attr == item.getSelected()" ng-value="attr">{[{ attr }]}</md-option>
</md-select>
</div>

<div class="quantity">
<div fs-counter-dynamic value="itemQuantity"
data-min="1"
data-max="999"
data-step="1"
data-addclass="add-quantity"
data-width="130px"
data-itemid="{[{ item.getId() }]}"
data-editable
ng-model="itemQuantity"
name="quantity" id="quantity-{[{ item.getId() }]}",
index="{[{ item.getId() }]}"

></div>
</div>
<div class="total">Total : {[{ item.getTotal() | currency }]}</div>
<div class="delete"><a ng-click="ngCart.removeItemById(item.getId());"></a></div>
</div>


Is this normal behavior? Is there any way to force the directive to keeps its own data? From what I've understood, each directive has its own scope, so what I think happens is that, when we remove the first one, it keeps the data stored in some kind of array that says "directive 1 data is : " and when we delete the first directive, the second one becomes the first.

So basically, are we doing anything wrong or is there anyway to remap the data?

Hope it was clear enough,
Thanks!

Edit: added html code

Edit2: Answer :
New FsCounter template looks like this:

<div fs-counter-dynamic value="item._quantity"
data-min="1"
data-max="999"
data-step="1"
data-addclass="add-quantity"
data-width="130px"
data-itemid="{[{ item.getId() }]}"
data-editable
ng-model="item._quantity"
name="quantity" id="quantity{[{ item.getId() }]}"
></div>

Answer

Do you know ng-repeat, then you don't have such problems

<div ng-repeat="product in products">
   <fs-counter index="product.index" value="product.value"></fs-counter>
</div>

and in your controller

$scope.products = [
   {index:1, value:"Cola"},
   {index:2,,value:"Fanta"}
]

to remove an element you just have to do

$scope.products.splice(0,1);

Edit:

I suggest to save all necessary data inside the item you use inside ng-repeat. Your problem is, that you mix data from array with other data from your $scope. It is possible to $watch changes in your directive, but if you set them with ng-repeat everything is done automatically.

$scope.products = [
   {index:1, name:"Cola", price:1.50, image:"your/path.png", attributes:{...}},
   {index:2, name:"Fanta", price:1.40,  image:"your/path.png"}
]

And then in your html

<div class="unItem" ng-repeat="item in ngCart.products track by $index">
    <div class="photo"><img ng-src="item.image" alt=""></div>
    <div class="details">
        <h3>{{item.name}} <span>{{item.price | currency}}</span></h3>
    </div>

    <div class="quantity">
        <div fs-counter-dynamic value="item.quantity"
                            data-min="1"
                            data-max="999"
                            data-step="1"
                            data-addclass="add-quantity"
                            data-width="130px"
                            data-itemid="item.index"
                            data-editable
                            ng-model="item.quantity"
                            name="quantity" id="{{'quantity-' + $index}}",
                            index="item.index"

                            ></div>
    </div>
    <div class="total">Total : {{ item.price * item.quantity | currency }}</div>
    <div class="delete"><a ng-click="ngCart.removeItemById(item.index);"></a></div>
</div>
Comments