ng-options not binding when it has preselected values
Asked Answered
R

5

7

I am using select2 to create a div with tags like functionality when creating a new post.

Stack is Angular 1.6.x

It works well when I am creating a new post BUT when I add pre-selected values when editing the said post, the preselected values never change from the default.

In a nutshell, the values are not binding.

See below:

HTML snippet:

<div class="form-group">
  <label for="tags" class="control-label">Tags</label>
    <select name="tags" class="tagsSearch" class="form-control" id="tags"
            ng-options="tag as tag for tag in post.tags track by tag"
            ng-model="post.tags" style="width: 100%" multiple>
    </select>
</div>

Note: it looks messy but I got this to work to show my original tags

Controller snippet:

$http.get('/api/post', {params: { title: $scope.title }})
.then(function(res){
   $scope.post = res.data.post;
});

$scope.updatePost = function() {
  console.log($scope.post.tags);
};

The problem is that the tags do not bind, so if the values are: tag1, tag2, tag3 at rendering and I add: tag4 - updatePost consoles tag1, tag2 and tag3

PS: My tags are an array of strings and have no keys to it like an ID (saw some other post which was referencing to them).

Very lost. Any input would be highly appreciated.

Thanks

EDIT - 28th April 2018:

I have updated my tags to be objects of an array like this:

[
  {tag: "tag1", _id: "5ae410756b7a61080cd17c81"},
  {tag: "tag2", _id: "5ae410756b7a61080cd17c80"},
  {tag: "tag3", _id: "5ae410756b7a61080cd17c7f"}
]

It still doesn't work when I do it like this:

<select name="tags" class="tagsSearch" class="form-control" id="tags"
        ng-options="tag as tag.tag for tag in post.tags track by tag._id" 
        ng-model="post.tags" style="width: 100%" multiple>
</select>

The console.log still only captures the pre-existing tags. New ones are ignored.

Rotate answered 2/4, 2018 at 4:26 Comment(6)
create a fiddle!Click
use track by $index.it may workIaea
could you try using a different ng-model variable instead of post.tags?Lumpkin
I can copy post.tags and then bind that. What are you thinking?Rotate
The event handlers added by jQuery select2 are fighting the event handlers added by ng-options. When asking a question about a problem caused by your code, you will get much better answers if you provide code people can use to reproduce the problem. That code should be… Complete – Provide all parts needed to reproduce the problem. See How to create a Minimal, Complete, and Verifiable example.Platelayer
Consider using ui-select2, an AngularJS wrapper for select2, different from jquery-select2Platelayer
G
4

Below implementation might be what you asked for:

HTML:

 <form name="myForm">
    <label for="mySelect">Make a choice:</label>
    <select name="mySelect" id="mySelect"
      ng-options="option.tag for option in post.tag track by option._id"
      ng-model="post.selected" multiple></select>
      <br>
      <button ng-click="updatePost()"> Add Tag</button>
 </form>

JS:

(function(angular) {
  'use strict';
  angular.module('defaultValueSelect', [])
    .controller('ExampleController', ['$scope', '$http', function($scope, $http) {
      var url = "https://jsonblob.com/api/jsonBlob/aa6b4eb4-5284-11e8-a5ee-fd00735e3b38";
      var index = 4;
      var extraObj = {
        tag: "tag",
        _id: "5ae410756b7a61080cd17c7"
      };
      $http
        .get(url)
        .then(function(response) {
          $scope.post = {
            tag: response.data,
            selected: response.data[0]
          };
        });
      $scope.updatePost = function() {
        var tmp = {};
        tmp = angular.copy(extraObj);
        console.log(angular.copy($scope.post));
        tmp.tag += index;
        tmp._id += index;
        $scope.post.tag.push(tmp);
        console.log($scope.post);
        index++;
      }
    }]);
})(window.angular);

For working code refer to this plunkr: plnkr.co/edit/cwDRa2Qjg2IlUi5JOAPj

Grenadine answered 9/5, 2018 at 9:57 Comment(3)
This looks very interesting and I wanted to see the plunkr but I see it is empty. Can you please provide the link where you did save it? Thanks in advance manRotate
Does the answer resolve your problem? If not let me know.Grenadine
Hey man. That did it! Sorry I was away for so long as something quite urgent went down. I have marked this as the answer. Thanks a lotRotate
G
4

ng-model is holding the same array post.tags. Please use a different ng-model for holding the selected tags.

HTML:

<div ng-controller="MyCtrl">
    <!-- this list is for assure, that two way binding works -->
    List of Tags:
  <ul>
        <li data-ng-repeat="tag in post.tags">{{tag.tag}}</li>
    </ul>
  <br>
  Select Tags: <!-- selected items are not binded to the model -->
    <select multiple ui-select2 class="form-control" data-ng-model="selectedTags" >
        <option data-ng-repeat="tag in post.tags" value="{{tag._id}}" text="">{{tag.tag}}</option>
    </select>
</div>

Controller:

var myApp = angular.module('myApp', ['ui.select2']);

function MyCtrl($scope) {
    $scope.selectedTags = [4]; // Averell is preselected (id:4)
    $scope.post = {
       tags: [
    {tag: "Angular JS", _id: "5ae410756b7a61080cd17c81"},
    {tag: "Java", _id: "5ae410756b7a61080cd17c80"},
    {tag: "JQuery", _id: "5ae410756b7a61080cd17c7f"}
  ]};
};

Please check this DEMO and check whether you get what you are looking for.

Gullet answered 8/5, 2018 at 6:9 Comment(2)
Can you elaborate please? I need the textbox to be binded so I can capture the data when updatePost is triggeredRotate
This is a great workaround, thanks. But - this is not what I want as I want them all in one field. Much like the tags in StackOverflow. You get the list of tags and then you deselect them or add new onesRotate
M
4

I used angular select documentation as a reference and created a plunker from their example found here.

I used this blob to simulate your data set.

This is what my select directive looks like. I would suggest that you not overwrite the binding for the array with the bind for the selected item, that is what is causing you problems.

(function(angular) {
  'use strict';
angular.module('defaultValueSelect', [])
  .controller('ExampleController', ['$scope','$http', function($scope,$http) {
    var url = "https://jsonblob.com/api/jsonBlob/aa6b4eb4-5284-11e8-a5ee-fd00735e3b38";
    $http
        .get(url)
        .then(function(response){
            $scope.post = {
                tag: response.data,
                selected: response.data[0]
            };
        })
 }]);
})(window.angular);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="defaultValueSelect">
  <div ng-controller="ExampleController">
  <form name="myForm">
    <label for="mySelect">Make a choice:</label>
    <select name="mySelect" id="mySelect"
      ng-options="option.tag for option in post.tag track by option._id"
      ng-model="post.selected" multiple></select>
  </form>
  <hr>
  <tt>option = {{post.selected}}</tt><br/>
</div>
</body>

Happy Coding

Musicale answered 8/5, 2018 at 7:1 Comment(0)
P
4

I think you can try to remove the element from the DOM and add it again with the new values. You can use ng-if with a flag..

<div class="form-group" ng-if="someflag">
  <label for="tags" class="control-label">Tags</label>
    <select name="tags" class="tagsSearch" class="form-control" id="tags"
            ng-options="tag as tag for tag in post.tags track by tag"
            ng-model="post.tags" style="width: 100%" multiple>
    </select>
</div>

Now the place where you want to update the data, put the following code: (Note: You need to inject $timeout in the controller)

//Default Value
$scope.someflag = true;

//Update Data
$scope.myNewData = function(){
  //Remove from DOM
  $scope.someflag = false;

  //Add to the DOM with some delay
  $timeout(function(){
    $scope.someflag = true;
  })
}
Planetarium answered 8/5, 2018 at 10:5 Comment(2)
I am sorry but I am not getting the point here. Sorry for the blackness in my head right now but can you elaborate a little?Rotate
In your case, the element is already loaded in the DOM when you provide the data (pre-selected values, which is not reflected). So, whenever you update the data through your controller, just remove the element from the DOM and add it again. ng-if="false" will remove it. ng-if="true" will add it with new values. Hope you got my point.Planetarium
G
4

Below implementation might be what you asked for:

HTML:

 <form name="myForm">
    <label for="mySelect">Make a choice:</label>
    <select name="mySelect" id="mySelect"
      ng-options="option.tag for option in post.tag track by option._id"
      ng-model="post.selected" multiple></select>
      <br>
      <button ng-click="updatePost()"> Add Tag</button>
 </form>

JS:

(function(angular) {
  'use strict';
  angular.module('defaultValueSelect', [])
    .controller('ExampleController', ['$scope', '$http', function($scope, $http) {
      var url = "https://jsonblob.com/api/jsonBlob/aa6b4eb4-5284-11e8-a5ee-fd00735e3b38";
      var index = 4;
      var extraObj = {
        tag: "tag",
        _id: "5ae410756b7a61080cd17c7"
      };
      $http
        .get(url)
        .then(function(response) {
          $scope.post = {
            tag: response.data,
            selected: response.data[0]
          };
        });
      $scope.updatePost = function() {
        var tmp = {};
        tmp = angular.copy(extraObj);
        console.log(angular.copy($scope.post));
        tmp.tag += index;
        tmp._id += index;
        $scope.post.tag.push(tmp);
        console.log($scope.post);
        index++;
      }
    }]);
})(window.angular);

For working code refer to this plunkr: plnkr.co/edit/cwDRa2Qjg2IlUi5JOAPj

Grenadine answered 9/5, 2018 at 9:57 Comment(3)
This looks very interesting and I wanted to see the plunkr but I see it is empty. Can you please provide the link where you did save it? Thanks in advance manRotate
Does the answer resolve your problem? If not let me know.Grenadine
Hey man. That did it! Sorry I was away for so long as something quite urgent went down. I have marked this as the answer. Thanks a lotRotate
S
3

Try and see if this works:

ng-options="tag as tag for tag in post.tags track by tag.id"

Only change being track by tag.id. If there is a different key in the tag object, that can also be used instead of id.

The HTML snippet with that change:

<div class="form-group">
  <label for="tags" class="control-label">Tags</label>
  <select name="tags" class="tagsSearch" class="form-control" id="tags"
          ng-options="tag as tag for tag in post.tags track by tag.id"
          ng-model="post.tags" style="width: 100%" multiple>
  </select>
</div>
Sextans answered 2/4, 2018 at 9:15 Comment(1)
Sorry for the late reply. I gave this a shot - I changed the tags array to include an ID and it still doesn't work. The new values I am putting in is not being captured.Rotate

© 2022 - 2024 — McMap. All rights reserved.