Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better approach for triggering directive from controller

I have a directive which needs to do some DOM manipulation based on the result of a service call in the controller. Following is the approach I am currently following:

1) Create a trigger object in each controller scope corresponding to each directive in view - to do dom manipulation when needed

2) Create the directive and do the dom manipulation based on the value set from controller;

app.directive("myDirective", function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            attrs.$observe('myDirective', function (value) {
                if (value === "true") {
                    $(element).text("Scrolled to####" + $(element).data("scroll"));
                }

            });
        }
    };
});

3)From the respective controller method set the value to true to trigger directive functionality

app.controller("controller1", ["$scope", function ($scope) {
    $scope.trigger1 = false;

    $scope.triggerDirective1 = function () {

        $scope.trigger1 = true;
    };
    $scope.trigger2 = false;

    $scope.triggerDirective2 = function () {

        $scope.trigger2 = true;
    };
}]);

<div id="c1" ng-controller="controller1">Controller 1
    <br>List 1
    <div my-directive="{{trigger1}}" data-scroll="20"></div>List 2
    <div my-directive="{{trigger2}}" data-scroll="30"></div>
    <button ng-click="triggerDirective1()">Trigger Directive 1</button>
    <button ng-click="triggerDirective2()">Trigger Directive 2</button>
</div>

Complete code is here - http://jsfiddle.net/qec35dq4/

I find this approach not so good because of the following reason:

1) There will be multiple elements in view with the directive attached

2) Each Directive trigger is independent.At any single time only one directive would be in action.Depending on the number of directives in view, I have to keep track of all the trigger in the respective controller.

Is there a better way to solve this problem, so that the dependency of keeping track of this trigger scope object in controller can be avoided?.I thought of using $broadcast/$emit,$on. But don't think that will be a good solution either .Please let me know your thoughts.

Thanks in advance for any help

EDIT:

New fiddle - http://jsfiddle.net/86pk8LtL/

Changed the example a bit to reflect more on what I am trying to achieve - There will be multiple lists on page to which this directive will be applied.Based on the some logic from back-end some items need to be selected in the list. Once items are selected, the list should be scrolled so that the first selected item is in view(In the example,i am hardcoding the scrollposition using data attributes.But in reality directive would do the calculation).The purpose of this directive is just to handle the "scroll to view" part which is why I am somewhat sceptical in keeping a scope property for it. Please note that the current approach is working fine. Just want to see if there is any better approach to this.

like image 990
user700284 Avatar asked Feb 16 '26 19:02

user700284


1 Answers

AngularJS is not really about using DOM querying like event driven libraries do. I would suggest using controller fetching. Since Angular supports OOP standards try nesting your controllers, the scope of the child controllers is inherited from the parent controllers, that means you could observe the state of the which element is triggered. Take a look at this basic example http://jsfiddle.net/qec35dq4/3/ Also , I would suggest instead of observing attributes to pass a model into the directive's scope. That will help you to avoid observing for attribute changing.

Least but not last, you don't really need to watch for element's attribute change. It is available through the attrs of your directive:

app.directive("myDirective", function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            attrs.$observe('myDirective', function (value) {
                if (value === "true") {
                    $("#result").text(attrs.msg);
                }

            });
        }
    };
});

EDIT Here is a demo based on your latest JSFiddle.

like image 92
vorillaz Avatar answered Feb 18 '26 07:02

vorillaz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!