shrw
shrw

Reputation: 1805

Angular ng-blur not working with ng-hide

Using a directive focus-me="inTextModeInput" in a text input

app.directive('focusMe', function($timeout) {
    /*focuses on input
     <input type="text" focus-me="focusInput">
     */
        return {
            scope: { trigger: '=focusMe' },
            link: function(scope, element) {
                scope.$watch('trigger', function(value) {
                    if(value === true) {
                        $timeout(function() {
                            element[0].focus();
                            scope.trigger = false;
                        });
                    }
                });
            }
        };
    });

Actually having 2 inputs, both uses focus-me When i programatically set the value to focus on an input the ng-blur of other is not called.

NOTE : i am also using this in an ng-repeat.

Upvotes: 0

Views: 2754

Answers (1)

null
null

Reputation: 7926

Isolated scope

The blur is called, but you're not seeing that because you've created a directive with an isolated scope. The ng-blur is executed on the $parent scope. You should only use an isolated scope when the directive is implementing re-useable templates.

Two way binding on trigger

The line 'scope.trigger = false' is also setting a different boolean value because it's on a different scope. If you want to assign a value to a variable from a directive you should always wrap the value inside another object: var focus = { me: true } and set it like trigger=focus.me.

A better solution

But I wouldn't set the trigger to false at all. AngularJS is a MVC/MVVM based framework which has a model state for the user interface. This state should be idempotent; meaning that if you store the current state, reload the page and restore the state the user interface should be in the exact same situation as before.

So what you probably need is a directive that

  • Has no isolated scope (which allows all other directives to work: ng-blur, ng-focus, ...)
  • Keeps track of a boolean, which indicates the focus state
  • Sets this boolean to false when the element has lost focus

It's probably easier to see this thing in action: working plunker.

Maybe this (other) plunker will give you some more insight on scopes and directives.

Code

myApp.directive('myFocus', function($parse, $timeout) {

  return {
    restrict: 'A',
    link: function myFocusLink($scope, $element, $attrs, ctrls) {

        var e = $element[0];

        // Grab a parser from the provided expression so we can
        // read and assign a value to it.

        var getModel = $parse($attrs.myFocus);
        var setModel = getModel.assign;

        // Watch the parser -- and focus if true or blur otherwise.

        $scope.$watch(getModel, function(value) {
          if(value) {
            e.focus();
          } else {
            e.blur();
          }
        });

        function onBlur() {
          $timeout(function() {
            setModel($scope, false);  
          });
        }

        function onFocus() {
          $timeout(function() {
            setModel($scope, true);  
          });
        }

        $element.on('focus', onFocus);
        $element.on('blur', onBlur);

        // Cleanup event registration if the scope is destroyed

        $scope.$on('$destroy', function() {
          $element.off('focus', onFocus);
          $element.off('blur', onBlur);
        });
    }
  };
});

Upvotes: 2

Related Questions