1

I am pretty new to angularJS. I am trying to create an interface for the user where he will be able to select exactly two items from two drop down list. They are actually the same options. When the user selects some option from the left drop down list he will not be able to select the same thing from the right drop down list and vice versa. The user will also have a button to add more options. The code works fine for everything but when the user clicks the button to add more options the newly added options doesn't work at all. Here is my full code:

   <html>

<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
</head>
<body>
<div ng-app="app">
    <div ng-controller="MyCtrl">
        <h2>Select one Item from left and one Item from right</h2>
        <select ng-model="leftmodel"
                ng-change="ChangeOptions()"
                ng-options="option as option.value disable
  when option.disabled for option in left">
        </select>

        <select ng-model="rightmodel"
                ng-change="ChangeOptions()"
                ng-options="option as option.value disable when option.disabled for option in right">

        </select>
        <button ng-click="addOptions()">Click Me</button>
    </div>
</div>
<script>
    var module = angular.module("app", []);
    module.controller("MyCtrl",
            function($scope) {
                $scope.left = [{
                    "name": "apple",
                    "value": "Nice Apple",
                    "disabled": false
                }, {
                    "name": "orange",
                    "value": "Yellow Orange",
                    "disabled": true
                }, {
                    "name": "berry",
                    "value": "Blue Berry",
                    "disabled": false
                }];

                $scope.right = [{
                    "name": "apple",
                    "value": "Nice Apple",
                    "disabled": true
                }, {
                    "name": "orange",
                    "value": "Yellow Orange",
                    "disabled": false
                }, {
                    "name": "berry",
                    "value": "Blue Berry",
                    "disabled": false
                }];

                $scope.leftmodel = $scope.left[0];
                $scope.rightmodel = $scope.right[1];
                $scope.addOptions=function()
                {
                    var banana={
                        "name": "banana",
                        "value": "Tasty Banana",
                        "disabled": false
                    };
                    var orange={
                        "name":"orange",
                        "value":"Soour Orange",
                        "disabled":false
                    };
                    $scope.left.push(banana);
                    $scope.left.push(orange);
                    $scope.right.push(banana);
                    $scope.right.push(orange);
                };
                $scope.ChangeOptions = function() {
                    var lsize = $scope.left.length;
                    var rsize = $scope.left.length;
                    for (var i = 0; i < lsize; i++) {

                        console.log($scope.left[i]);
                        if ($scope.left[i].name === $scope.rightmodel.name) {
                            $scope.left[i].disabled = true;
                        } else {
                            $scope.left[i].disabled = false;
                        }
                    }

                    for (var i = 0; i < rsize; i++) {
                        if ($scope.right[i].name === $scope.leftmodel.name) {
                            $scope.right[i].disabled = true;
                        } else {
                            $scope.right[i].disabled = false;
                        }
                    }
                };

            }
    );
</script>
</body>
</html>

I also have a Codepen. The errors i get once clicking a newly created option on clicking the button are:

TypeError: Cannot read property 'name' of null at ChildScope.$scope.ChangeOptions (first.html:89) at fn (eval at compile (angular.js:15156), :4:159) at ChildScope.$eval (angular.js:17972) at angular.js:25711 at Object. (angular.js:28536) at forEach (angular.js:357) at Object.$$writeModelToScope (angular.js:28534) at writeToModelIfNeeded (angular.js:28527) at angular.js:28521 at validationDone (angular.js:28446)

Can anyone help me, how can i solve this problem? Thanks in advance.

I am noticing one more strange thing. It can console the names at line 88. But it fails at the same line saying it cant find name of null at line 88. The image Strange Bug shows the scenario.

8
  • My code works until I click the add more options button. After adding more options the functionality doesn't work for newly created options Commented Jan 10, 2017 at 16:27
  • any idea why it doesn't work? Commented Jan 10, 2017 at 22:15
  • Is this some sort of test or class or something that you are working on with other people? The code from this question stackoverflow.com/q/41560693/2495283 seems very simillar... In fact, this appears to be the code from the accepted answer. Commented Jan 10, 2017 at 22:48
  • Yes this code is the extended version of that one which I am struggling to make work Commented Jan 11, 2017 at 0:38
  • actually looking at this code and the answers provided here, and the answer provided yesterday, this clearly doesn't make sense; var rsize = $scope.left.length; why would the size of the right be the length of the left? This probably worked as long as the arrays were the same size, but the moment something is added to one side and not the other, this is going to break. Commented Jan 11, 2017 at 1:31

3 Answers 3

1

You have two flaws in your code.

The first is that you are pushing the same object into both the left and right arrays in your addOptions(). This means when you disable the object on the right side, it's automatically disabled on the left (since they are the same object, not just two objects that look the same). When it gets disabled, then leftmodel is no longer a valid option, so it gets undefined.

You can correct this by using angular.copy() to clone the object, creating two distinct objects on the left and the right side.

Your second issue is that you already have an item with the name 'orange' in your lists, so if you were to pick one of those on the left, it would disable both on the right, and cause the leftmodel to become undefined (because the first 'orange' is the default option for right).

here is an updated addOptions():

$scope.addOptions = function() {
  var banana = {
    "name": "banana",
    "value": "Tasty Banana",
    "disabled": false
  };
  var orange = {
    "name": "sorange",
    "value": "Soour Orange",
    "disabled": false
  };
  $scope.left.push(angular.copy(banana));
  $scope.left.push(angular.copy(orange));
  $scope.right.push(angular.copy(banana));
  $scope.right.push(angular.copy(orange));
};

and a fork of your codepen: https://codepen.io/anon/pen/xgZYmW

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

1 Comment

Thanks a lot for your nice help
0

You have two for-loops below each other, which both use the variable i as index. Javascripts actually moves these variables to the top of the scope, so the interpreter will create something like this:

$scope.ChangeOptions = function() {
    var lsize = $scope.left.length;
    var rsize = $scope.left.length;

    var i = 0;
    var i = 0;

    for(i; i < lsize; i++) {
        //
    }

    // After the previous loop, i will be 3
    for(i; i < rsize; i++) {

This will cause the second loop to start at i = 3, so it won't find the $scope.right[3].name. To fix this just change the second loop to another variable like j.

3 Comments

But my code works till i click the add more options button to add few more options dynamically
is there a reason why you did this? var lsize = $scope.left.length; var rsize = $scope.left.length;
I did this to find the length of the left and right arrays. They are same though
0

Instead of initializing new variables inside your addOptions method. Grab the two models you already have defined in the HTML and add them to the array using a function:

   $scope.addOptions=function()
            {
                var leftOption = $scope.leftmodel;
                var rightOption = $scope.rightmodel; 

                function newFruit(option){

                    var fruit = {
                    "name": option,
                    "value": "",
                    "disabled": false

                  };

                  return fruit;
                }

                $scope.left.push(newFruit(leftOption));
                $scope.right.push(newFruit(rightOption));
            };

1 Comment

My code works until I click the add more options button. After adding more options the functionality doesn't work for newly created options

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.