Casey Casey - 4 months ago 15
AngularJS Question

Angular directive to use ng-blur and ng-focus

I'm having trouble understanding Angular directives. I'd like to use a simple attribute to expand into more complicated html, but with some parts of this template being replaceable via parameters.

Given this code:

<form role="form" name="databaseForm">
<input type="text" name="connectionName"
ng-focus="databaseForm.connectionName.$focused = true;databaseForm.connectionName.$blurred = false;"
ng-blur="databaseForm.connectionName.$blurred = true;databaseForm.connectionName.$focused = false;"
>
</form>


I'd like to write it using a more terse directive (such as "blurred-focused"):

<form role="form" name="databaseForm">
<input type="text" name="connectionName"
blurred-focused="'databaseForm.connectionName'"
>
</form>


So that means I can very easily re-use it for other inputs:

<form role="form" name="databaseForm">
<input type="text" name="username"
blurred-focused="'databaseForm.username'"
>
</form>


The expected result from this is that the inputs with this directive will have the $blurred and $focused properties automatically applied to it, based on the user interaction with the input.

Thank you.




Update:
I ended up using MMHunter's version where the scope is non-isolated. I added some logic to automatically find the form and field object, so that I didn't need to specify it all.

My directive:

(function () {
"use strict";

angular
.module("app.shared.widgets")
.directive("blurredFocused", blurredFocused);

blurredFocused.$inject = ["_"];
/* @ngInject */
function blurredFocused(_) {
return {
restrict: "A",
priority: -1,
link: function(scope, element, attributes) {

element.on("blur", function () {
var formFieldName = element[0].form.name + "." + element[0].name;
var target = _.get(scope, formFieldName);
scope.$apply(function() {
target.$blurred = true;
target.$focused = false;
});

});

element.on("focus", function () {
var formFieldName = element[0].form.name + "." + element[0].name;
var target = _.get(scope, formFieldName);
scope.$apply(function() {
target.$blurred = false;
target.$focused = true;
});
});
}
};
}

})();


And an example of its usage:

<form role="form" name="databaseForm">
<input type="text" name="connectionName" blurred-focused>
</form>

Answer

You need is not difficult to achieve with angular directive. But things can be different based on whether isolated scope is used.

With isolated scope, the following code is straightForward. Binding the value to an isolated scope in the 'blurred-focused' directive and listen to the events.

//with isolated scope
app.directive("blurredFocused", [function () {
        return {
            restrict:"A",
            priority:-1,
            scope:{
              blurredFocused:"="
            },
            link:function(scope,ele,attrs){

                ele.on("blur",function(){
                  scope.$apply(function(){
                      scope.blurredFocused.$blurred = true;
                      scope.blurredFocused.$focused = false;
                  })
                })

                ele.on("focus",function(){
                  scope.$apply(function(){
                    scope.blurredFocused.$blurred = false;
                    scope.blurredFocused.$focused = true;
                  })
                })
            }
        }
    }]);

But without isolated scope, things could be a little bit tricky. we need to find the scope value manually by the attributes value.

//without isolated scope
app.directive("blurredFocused", [function () {
    return {
        restrict:"A",
        priority:-1,
        link:function(scope,ele,attrs){

            ele.on("blur",function(){
              var targetField = scope[attrs.blurredFocused];
              scope.$apply(function(){
                targetField.$blurred = true;
                targetField.$focused = false;
              })

            })

            ele.on("focus",function(){
              var targetField = scope[attrs.blurredFocused];
              scope.$apply(function(){
                targetField.$blurred = false;
                targetField.$focused = true;
              })
            })
        }
    }
}]);

Here is the plunker

I would recommend you use the one without isolated scope. Attribute directives are always used together so it may not be a good idea to have isolated scopes.