javascriptarraysangularjsangular-ui-select

Angular-UI-Select ng-model not working with a simple variable on $scope


How do you clear an array with selected values so that values can return to the select?

I have a people array. The people array values are available in select. When I choose names, they are transferred to the multipleDemo array. And you can not reselect them from select because they disappear and are moved to the multipleDemo array. With the Delete button I have to delete all elements from the multipleDemo array (except the first element) into the people array. So that you can again choose a name from the select. Error in function $clearTag.

Expecting behavior: Example:

  1. Select: Wladimir
  2. Appear tag Wladimir
  3. Select Wladimir (You can't choose Wladimir because he is already chosen)
  4. Click Delete. Cut elements(tags) with multipleDemo array and put them in array people
  5. You can again select Wladimir

Here is my code: http://plnkr.co/edit/TPZjXkkSRrIc5ApzP07F?p=preview

index.html

<!DOCTYPE html>
<html lang="en" ng-app="demo">
<head>
  <meta charset="utf-8">
  <title>AngularJS ui-select</title>

  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular-sanitize.js"></script>
  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.css">

  <!-- ui-select files -->
  <script src="select.js"></script>
  <link rel="stylesheet" href="select.css">

  <script src="demo.js"></script>

  <!-- Select2 theme -->
  <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">

  <style>
    body {
      padding: 15px;
    }

    .select2 > .select2-choice.ui-select-match {
      /* Because of the inclusion of Bootstrap */
      height: 29px;
    }

    .selectize-control > .selectize-dropdown {
      top: 36px;
    }
  </style>
</head>
<body ng-controller="DemoCtrl">
    
  <h3>Array of strings</h3>
  <button ng-click='clearTag()'>Delete</button>
  <ui-select tagging tagging-label="new tag" multiple ng-model="multipleDemo" 
  on-select="OnClickSelect($item)" on-remove="OnRemoveSelect($item)"
  theme="select2" ng-disabled="disabled" style="width: 300px;">
    <ui-select-match placeholder="Select name...">{{$item.name}}</ui-select-match>
    <ui-select-choices  repeat="item in people | filter:$select.search">
      {{item.name}}
    </ui-select-choices>
  </ui-select>
  <p>Selected: {{multipleDemo}}</p>
  <hr>  

</body>
</html>

demo.js

app.controller('DemoCtrl', function($scope, $http, $timeout) {
  $scope.multipleDemo =[];
    $scope.people = [
    { name: 'Adam',      email: 'adam@email.com',      age: 12, country: 'United States' },
    { name: 'Amalie',    email: 'amalie@email.com',    age: 12, country: 'Argentina' },
    { name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina' },
    { name: 'Adrian',    email: 'adrian@email.com',    age: 21, country: 'Ecuador' },
    { name: 'Wladimir',  email: 'wladimir@email.com',  age: 30, country: 'Ecuador' },
    { name: 'Samantha',  email: 'samantha@email.com',  age: 30, country: 'United States' },
    { name: 'Nicole',    email: 'nicole@email.com',    age: 43, country: 'Colombia' },
    { name: 'Natasha',   email: 'natasha@email.com',   age: 54, country: 'Ecuador' },
    { name: 'Michael',   email: 'michael@email.com',   age: 15, country: 'Colombia' },
    { name: 'Nicolás',   email: 'nicolas@email.com',    age: 43, country: 'Colombia' }
  ];

  $scope.OnClickSelect=function(item)
  {
   $scope.multipleDemo.push(item.name);
  }
  
  $scope.OnRemoveSelect = function(item) { 
   var index = $scope.people.indexOf(item.name);
   $scope.people.splice(index, 1); 
  }
  
  $scope.clearTag = function() {
    for(var i =0; i < $scope.multipleDemo.length; i++) {
      $scope.multipleDemo.splice($scope.multipleDemo[i], 1000);
      $scope.people.push($scope.multipleDemo[i]);
    }
  }

Solution

  • Angular-UI-Select Common Issues

    ng-model not working with a simple variable on $scope

    You cannot write:

    WRONG

    <ui-select ng-model="multipleDemo"> <!-- Wrong -->
      [...]
    </ui-select>
    

    You need to write:

    <ui-select ng-model="vm.multipleDemo"> <!-- Correct -->
      [...]
    </ui-select>
    

    For more information, see


    Update

    vm.multipleDemo doesn't work; I try $parent.multipleDemo - it works. I don't understand $parent. Why it works?

    For vm.multipleDemo to work, the controller must initialize the vm object:

    app.controller('DemoCtrl', function($scope, $http, $timeout) {
        $scope.vm = { multipleDemo: [] };
    

    New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes, so the [data hiding] problem often shows up when these directives are involved. (See this example for a quick illustration of the problem.)

    This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models – watch 3 minutes worth. Misko demonstrates the primitive binding issue with ng-switch.

    What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

    Avoid using $parent to fix a data hiding problem. It is a brittle solution as there can be more than one level of scope heirarchy between the controller and the ui-select directive. I consider the use of $parent to be a code smell, a symptom of a deeper problem.


    Update #2

    When I can use $ctrl in view and this in controller?

    If the controller is instantiated with "controller as" syntax:

    <body ng-controller="DemoCtrl as $ctrl">
    
        <ui-select ng-model="$ctrl.multipleDemo">
           <!-- -->
        </ui-select>
    

    Then there is no need to use $scope:

    app.controller('DemoCtrl', function($http) {
        this.multipleDemo =  [];
    

    And it avoids the data hiding problem.

    For more information, see