Search code examples
javascripthtmlangularjsdomangular-directive

Manipulating DOM of parent directive due to event raised by child directive


I'm not sure how to accomplish the following in the right way:

Consider, for the sake of example, that I want to create my own custom radio-buttons list directive, something like that:

<my-radio-button-list>
    <my-radio-button>
        ...Some HTML content...
    </my-radio-button>
    <my-radio-button>
        ...Some HTML content...
    </my-radio-button>
    <my-radio-button>
        ...Some HTML content...
    </my-radio-button>      
</my-radio-button-list>

Please note - the <my-radio-button> directive doesn't necessarily use any <input> elements.

I would like that <my-radio-button> will have its own internal event listener to track when it was clicked, and I would also like that when a <my-radio-button> directive was clicked, it will notify the parent <my-radio-button-list> directive that such event occurred, so the parent directive will change the DOM accordingly - it will deselect the current selected item, and will select the item that was clicked.

What is the correct way to achieve something like this?

The only way I could think of was to create a method on the parent directive's controller which will manipulate the DOM as necessarily (which will get as a parameter the newly selected item), and then to share the parent directive's controller with its children directives (so they can call this method from their click event handlers). However, I know that this approach is wrong, because the controller should never manipulate the DOM.

Thanks!


Solution

  • Using events (not just click events) would be an easy way to do it.

    child (my-radio-button) html:

    <button ng-click="childController.handleClick()">{{childController.childData.id}}</button>
    <span ng-if="parentController.currentSelection.id === childController.childData.id">THERE CAN ONLY BE ONE!!!</span>
    

    child (my-radio-button) controller:

    controller.childData = {id: 'child1'};
    
    controller.handleClick = function(){
      $scope.$emit('childClicked', childData);
    };
    

    parent (my-radio-button-list) html:

    <div>
      <ng-transclude></ng-transclude>
    <div>
    

    parent (my-radio-button-list) controller:

    $scope.$on('childClicked', function(childData){
      controller.currentSelection = childData;
    });