0

I need two sibling directives to communicate with each other. The first select is populated through REST service and when you select a value (from the first dropdown), the second dropdown should be enabled and a subset of the object below should be displayed as its options.

For ex: if the first value of the dropdown = dog or dropdown = bird, then the 2nd dropdown should only display a subset of SEries like spaghetti. But if dropdown = turtle then 2nd dropdown should display all of SEries.

If theres anyway to do this without using parent/children directive communication that would be great.

Here are the Types object:

  $scope.Types = [{
    "id": "dog",
    "name": "dog"
  }, {

    "id": "cat",
    "name": "cat"
  }, {

    "id": "bird",
    "name": "bird"
  }, {

    "id": "turtle",
    "name": "turtle"
  }];

Here are the SEries object:

$scope.Series = [{
    "id": "spaghetti",
    "name": "spaghetti"
  }, {
    "id": "eggs",
    "name": "eggs"
  }];

})s" }];

Here are my 2 directives:

.directive('selectBox', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: false,
        template: function (element, attrs) {
            return '<div class="selectBox selector">' + '<select " class="form-control" name="' + attrs.name + '" ng-model="' + attrs.ngModel + '" ng-options="' + attrs.optexp + '"' + '  ng-disabled="' + attrs.selectdisabled + '"></select>' + '</div>';
        }        
    };
})

.directive('selectSeries', function() {
    return {
      restrict: 'E',
      replace: true,
      scope: false,
      template: function(element, attrs) {
        return '<div><select class="form-control" name="' + attrs.name + '" ng-model="' + attrs.ngModel + '" ng-options="series.id as series.name for series in series" ' + '  disabled="disabled" ></select></div>';

      },

        link: function (scope, el, attrs) {
            scope.$watch('model.PlanType', function(value,b){

                if (value !== null){
                    //angular.element(el).children('select').removeAttr('disabled');
                    attrs.$set('ngOptions', 'series.id as series.name for series in series');

                }

            },this);
        }

    };

});

Here is my fiddle

gerl
  • 1,161
  • 2
  • 17
  • 53
  • You could try creating a custom pub/sub. [Check out this answer](http://stackoverflow.com/questions/25274563/angularjs-communication-between-directives#answer-25274665) – PSL Nov 24 '14 at 21:58
  • @PSL I have heard that it's not a good idea to pollute the $rootscope. This application will be fairly large and I dont want to start polluting $rootscope if its going to cause issues on the long run. – gerl Nov 25 '14 at 16:34
  • you are no polluting the rootscope with the implementation of an event bus (It is not specific to any application business logic), you are basically extending it so that when a new scope is created internally, i,e `$scope.$new()` these methods are also available in the child scopes and share the same impl. Well pollution is subjective based on how much junk you are placing especially if you are placing the variables, objects that are specific to the business logic of the application. Also if you really don't want to use it don't put it on the root scope use the factory which manages pubsub. – PSL Nov 25 '14 at 17:00

2 Answers2

1

Do not try to force direct communication between directives on sibling elements. The sibling elements have no real connection to each other. They can be easily added/removed and when using ng-if for example, the directive on the element that is compiled second might not even meet the first element in DOM during its compilation phase.

If you want "siblings" to talk to each other and not leak their communication outside, putting them in a container that creates a scope is your best bet. For more direct/complex interaction, you can create a directive that facilitates their communication to be put on their container.


Creating a directive that just creates a local scope is as easy as:

.directive('scope', function () {
    return {
        scope: true,
        link: function () {}
    };
});

and then you can use it

<div scope>
    <select communicating-directive>...</select>
    <select communicating-directive>...</select>
</div>

and your local assignments to scope will not leak outside the container.

hon2a
  • 7,006
  • 5
  • 41
  • 55
0

I don't think this is a good case of directive usage. In your case, plain selects and a ng-change would be enough. Like this:

<select ng-options="type.id as type.name for type in Types" ng-model="selectedType" ng-change="setEnabledSeries(selectedType)"></select>

<select ng-options="series.id as series.name for series in EnabledSeries" ng-model="selectedSeries"></select>

And in your controller:

$scope.setEnabledSeries = function(type) {
    $scope.EnabledSeries = blah blah blah, according to type...
}

Update

There was a typo. It should be selectedType instead of type in ng-change's function call. Please see the updated fiddle which is working: http://jsfiddle.net/cp6kp6xb/1/

Tong Shen
  • 1,364
  • 9
  • 17
  • I've tried doing it like that but the view doesnt get updated when $scope.EnabledSeries is updated. Heres the code http://jsfiddle.net/9so4kw7f/ – gerl Nov 25 '14 at 17:47