9

I have a directive that adds new options to a select.

For that i'm using:

let opt: any = angular.element(
            '<option value="' + opcion.valor + '">' + opcion.texto + '</option>'
          );
          this.element.append(this.$compile(opt)(scope));

I don't want to use templates because I don't want a new scope.

The options get added to the list on the view. But when I select some of them, the ng-model of the select doesn't get updated. It gets value null.

How can I make angular to refresh with the new option values?

Here is a codepen example: Choosing Option X doesn't get reflected on model.

The strange thing is that if i link to angular 1.5.9, it works, but starting with angular 1.6.0 it doesn't.

https://codepen.io/anon/pen/XemqGb?editors=0010

0

4 Answers 4

8

How can i make angular to refresh with the new option values ?

You do not need to do this. Updating model and data binding is done by digest cicle.

Data binding means that when you change something in the view, the scope model automatically updates.

You just need to update your scope and digest cicle is dealing with the rest of work.

I recommend you to not mix jquery with angularJS.

You should definitely try to do things the angular way when possible though.

You should not use jQuery on the top of the AngularJS, because AngularJS digest cycle won't run if we do any angular DOM manipulation or scope variable manipulation using JQuery.

However, you can do this manually using $scope.$apply() method by passing a callback function.

HTML

<select ng-model="selectedValue">
  ....
</select>

JS

$('select').change(function(){
    var value = $(this).val();
    var selectScope = angular.element($("select")).scope();
    selectScope.$apply(function(){
        selectScope.selectedValue=value;
    });
});
Sign up to request clarification or add additional context in comments.

5 Comments

I understand the warning about jquery. That's why i'm using it only in a Directive. I want to add new options to the select but without using a new template for the directive.
@MartinIrigaray, yes, you could do this by applying manually $scope.$apply method.
@MartinIrigaray, I updated my answer with a possible solution in order to update the scope of the select.
I put an example on codepen, is not working on angular 1.6.5.
it is important to note though that the scope() function on an element is only meant to be used for debugging/testing purposes and it is not meant to be used in actual code
5

I want to add new options to the select but without using a new template for the directive

Use compile attribute in directive:

myApp.directive('myList', function() {
   return {
        restrict: 'EA', //E = element, A = attribute, C = class, M = comment
         link: function ($scope, element, attrs) {
             // ....
        }, //DOM manipulation
         compile: function(tElement, tAttrs) {
           tElement.append('<option value="10">Option Ten</option>');
        }
      }
  });

Updated Demo Codepen


[EDIT 1]

Is possible to do this after a change on external model field ? Watch a field and then add the option ?

Not at all. compile is called once right after we created the instance. This is a phase when Angularjs compiles the directive

However if you want to create value after some delay based on external flow, why do not to use ng-options - You just need to add new value to list of objects and ng-options will do the job for you:

Simple Example Fiddle

$scope.items = [
    { value: "C", name: "Process C" },
    { value: "Q", name: "Process Q" }
];
 $timeout(function(){
    $scope.items.push({ value: "New", name: "Process New" });
 },3000);

and HTML:

<select class="form-control" name="theModel" ng-model="theModel" 
        ng-options="c.value as c.name for c in items">
    <option value=""> -- </option>
  </select>

2 Comments

Is possible to do this after a change on external model field ? Watch a field and then add the option ?
@MartinIrigaray Not at all. compile is called once right after we created the instance. I think this is a right answer for your question you posted. However if you want to create value after delay, why you don't want to use ng-options? You just need to add new value to list of objects and and ng-options will do the job for you: jsfiddle.net/21on92dk
4
+50

In latest angularJS Select value (read from DOM) is validated

Better to use select's in standard way,

BTW - If you really need this, remove validation by decorating selectDirective as follows

Codepen: https://codepen.io/anon/pen/NapVwN?editors=1010#anon-login

myApp.decorator('selectDirective', function($delegate) {
    let originalCtrl = $delegate[0].controller.pop();
    $delegate[0].controller.push(function() {
      originalCtrl.apply(this, arguments);
      this.hasOption = function() { 
        return true; 
      }
    })
    return $delegate;
});

Comments

2

Actually, what you have failed to understand is data binding. It means that when you have something in the $scope, you have to work with it. So your variable $scope.opcion must be an array as it is a select. The code needs to be something like:

/*
AngularJS Basic Directives

For More Examples AngularJS  

http://mehmetcanker.com

*/

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

myApp.controller('MyCtrl',['$scope', function($scope) {
$scope.opcion = [1];
}])

 //This directive doesn't individual scope so
 //Controller and Directive share same scope
 myApp.directive('myList', function() {
   return {
        restrict: 'EA', //E = element, A = attribute, C = class, M = comment
        link: function ($scope, element, attrs) {
          // add options
          $scope.opcion.join(2);
        } //DOM manipulation
    }
  });

The important part is $scope.opcion = [1] and $scope.opcion.join(value)

Comments

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.