0

I have this fiddle that shows a directive that has an alert for now. There is also a controller that has alert. This is all working fine except for the fact that the binding is being lost for the text to be shown on the button. Any ideas to help me?

<div ng-app="directiveApp" ng-controller="MainController">
 <button ng-click="doStuff()" unsaved-warning-trigger>
    {{buttonText}}
 </button>
</div>

var app = angular.module("directiveApp", []);

app.directive('unsavedWarningTrigger',
    function() {
        return {
            priority: 1,
            terminal: true,
            link: function (scope, element, attr) {
                var clickAction = attr.ngClick;
                element.bind('click',function () {
                    if (window.confirm("Sure?")) {
                        scope.$eval(clickAction)
                    }
                });
            }
        };
    }
);

MainController = function($scope) {
  $scope.buttonText = 'bound button';

  $scope.doStuff = function () {
    alert("doing stuff");
  };
}

http://jsfiddle.net/9tWr7/3/

pertrai1
  • 4,146
  • 11
  • 46
  • 71

2 Answers2

1

That is happening to you because of setting the "terminal" property to "true". By doing this, you are preventing any other directives that come later to execute (even if they are not explicit).

Think about your requirements and whether you really need to set

'terminal: true'

Otherwise, you should follow a different scope approach.

I attach a jsFiddle where you can see the binding work by removing that property:

http://jsfiddle.net/RJq3N/

and a good post about the terminal and priority properties:

How to understand the `terminal` of directive?

EDIT:

However, to achieve the whole functionality you want, you can write your directive as:

    app.directive('unsavedWarningTrigger',
     function() {
        return {
            priority: 1,
            terminal: true,
           link: function (scope, element, attr) {                   

               element.text(scope.buttonText);

                var clickAction = attr.ngClick;
                element.bind('click',function () {
                    if (window.confirm("Sure?")) {
                        scope.$eval(clickAction)
                    }
                });
            }
        };
    }
);

See jsFiddle:

http://jsfiddle.net/KsT5f/

Take into account that with this implementation, the button text is only set once at the directive link time. Since the binding with buttonText has been broken by the property 'terminal: true', if you want the button text to update upon changes of the variable buttonText, you would need to set a $watch for it and execute the element.text(scope.buttonText) within it.

Best.

Community
  • 1
  • 1
E. Valencia
  • 447
  • 2
  • 6
  • Thank you for the reply, the fiddle, and the link. Right now the problem is that I need Stuff? to alert before "doing stuff". That is where I am stuck and need help. Thank you again and hope there is a way to solve this. – pertrai1 Apr 28 '14 at 18:41
  • You specifically asked about the text in the button so I think the answer is accurate and deserves acceptance. I'll try and look into your other issue, though. – E. Valencia Apr 28 '14 at 18:55
  • Yes you are correct and this is the answer. I am hoping not to have to start a new question to get the total answer I need. I am going to accept this answer and hope that you can help me with the other issue. – pertrai1 Apr 28 '14 at 18:58
  • 1
    Perfect. Thank you again so much for the help and the information. Helped me to understand more about the directive I was working with. – pertrai1 Apr 28 '14 at 20:25
1

'terminal: true' prevents all directives with a lower priority on that element from being executed. But it also prevents directives from child elements from being executed.

Angular adds a directive for an {{expression}}. In your case the directive is added to the text node, the child of the button element. But because of terminal: true, that directive is never executed.

a better oliver
  • 26,330
  • 2
  • 58
  • 66