1

Can somebody please have a look at below plunker?

http://plnkr.co/edit/oTHJcVVzJE5CwMnFMEpS?p=preview

Problem: Change in the scope variable "specifications.selectedColor" is overwriting the specifications of other products i.e changing the selectedColor of all the products.

Steps to reproduce: 1) Click on Buy Now. checkoutProductList[0].selectedColor is set to Red. 2) Select Blue color from the drop-down. 3) Click on Buy Now. checkoutProductList[0].selectedColor is set to Blue.

On clicking Buy Now second time(step 3 above), it adds another product in checkoutProductList Array i.e checkoutProductList[1], it should not change checkoutProductList[0].selectedColor from Red to Blue.

What can be done to keep specifications of each product separately?

Code: Contoller

var app = angular.module('plunker', ['ui.select', 'ngSanitize']);

app.controller('MainCtrl', function($rootScope, $scope,checkoutService) {

  $scope.productAvailableColors=['Red','Blue'];
  $scope.specifications={'selectedColor':'Red'};



  $scope.buyNow = function (){    

    checkoutService.setCheckoutProductList($scope.specifications);
  };

});


app.service ('checkoutService', function (){
  var checkoutProductList=[];
  this.setCheckoutProductList = function ( specs){
    checkoutProductList.push(specs);
    window.alert(checkoutProductList.length);
    window.alert(checkoutProductList[0].selectedColor);
  }

})

HEAD

HTML:
<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>

  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css" />
  <script data-require="[email protected]" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.3/css/bootstrap.min.css" integrity="sha384-MIwDKRSSImVFAZCVLtU0LMDdON6KVCrZHyVQQj6e8wIEJkW4tvwqXrbMIya1vriY" crossorigin="anonymous">
  <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js" integrity="sha384-THPy051/pYDQGanwU6poAc/hOdQxjnOEXzbT+OuUAFqNqFjL+4IGLBgCJC3ZOShY" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.2.0/js/tether.min.js" integrity="sha384-Plbmg8JY28KFelvJVai01l8WyZzrYWG825m+cZ0eDDS1f7d/js6ikvy1+X+guPIB" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.3/js/bootstrap.min.js" integrity="sha384-ux8v3A6CPtOTqOzMKiuo3d/DomGaaClxFYdCu2HPMBEkf6x2xiDyJ7gkXU0MWwaD" crossorigin="anonymous"></script>


  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.12/angular-sanitize.js"></script>
  <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css">
  <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.default.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.19.4/select.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.19.4/select.min.css">



  <script src="app.js"></script>
</head>

BODY

<body ng-controller="MainCtrl">

 <div class="productModal-circle" 
     style="cursor: pointer; font-size: 14px; "     

      aria-hidden="true" 
      ng-click="buyNow()"
      title="Buy Now!" id="buyNow">Buy Now                                 

  </div>

  <div id="choices" class="panel-collapse collapse in">


      <div class="panel-body">                                           
            <ui-select ng-model="$parent.specifications.selectedColor" 
              theme="bootstrap" 
              ng-disabled="false" 
              close-on-select="true"                                               
              style="color: black;" 
              title="Choose Color and Design" 
              >
              <ui-select-match placeholder="Choose Color/Design">{{$parent.specifications.selectedColor}}</ui-select-match>
              <ui-select-choices repeat="listItem in productAvailableColors | filter:$select.search">
                 <div ng-bind-html="listItem | highlight: $select.search"></div>
              </ui-select-choices>
           </ui-select> 
       </div>

  </div>
  {{specifications | json}}
</body>


</html>
5
  • its working for me Commented Oct 15, 2016 at 12:55
  • Your plunkr is not same as the code that you are have shown. You do not have any Buy Now button in the plunkr. If you are changing the plunkr then please update the question as well. Commented Oct 15, 2016 at 14:54
  • @Ujjwalkaushik: It is not working, In step 3, it should show color as Red, however it is showing color as Blue which is a problem. Commented Oct 16, 2016 at 0:33
  • @PratikBhattacharya: This is the first plunker I have created, may be I have not created it properly. I have created a new one, please check if you are able to see the problem in this plunk. plnkr.co/edit/Kxdk3YD7ToC31CNSiKdG Commented Oct 16, 2016 at 0:34
  • @user1513857, thanks for the new plunkr. I can reproduce the problem that you have mentioned. I have figured the solution and have posted the answer. Commented Oct 16, 2016 at 17:14

1 Answer 1

1

Problem

The problem lies in deep copy and shallow copy in JavaScript. When you are pushing an object to the array, it's not really creating a copy of the object and pushing it instead it just stores a reference to the original object (which is $scope.specifications in your case). Since you are changing the $scope.specifications object in your controller your array is also getting changed.

Solution

You can leverage the angular.copy method which is used to create deep copy of an object. So what you can do is before pushing the object to the array, you can make a deep copy of the object and then push it to the array.

In your service where you are pushing the object to the array make this change

checkoutProductList.push(angular.copy(specs));

Full Service

app.service ('checkoutService', function (){
    var checkoutProductList=[];
    this.setCheckoutProductList = function ( specs){
    checkoutProductList.push(angular.copy(specs));
    window.alert(checkoutProductList.length);
    window.alert(JSON.stringify(checkoutProductList));
 }

I have also created a plunkr to demonstrate the working solution. You can see it here.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Pratik for the explanation and solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.