Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

support blur and focus events #1277

Closed
gops opened this issue Aug 20, 2012 · 48 comments
Closed

support blur and focus events #1277

gops opened this issue Aug 20, 2012 · 48 comments

Comments

@gops
Copy link

gops commented Aug 20, 2012

Almost all events are supported by angularjs but blur and focus events are left out. please add support for this.

@avimar
Copy link

avimar commented Sep 10, 2012

ToDoMVC wrote angular directives for blur/focus:

https://github.com/addyosmani/todomvc/blob/master/architecture-examples/angularjs/js/directives/

<body ng-app="editer">


var editer = angular.module('editer', []);


editer.directive('ngBlur', function() {
  return function( scope, elem, attrs ) {
    elem.bind('blur', function() {
      scope.$apply(attrs.ngBlur);
    });
  };
});

editer.directive('ngFocus', function( $timeout ) {
  return function( scope, elem, attrs ) {
    scope.$watch(attrs.ngFocus, function( newval ) {
      if ( newval ) {
        $timeout(function() {
          elem[0].focus();
        }, 0, false);
      }
    });
  };
});

Also see other example here:
http://jsfiddle.net/vmjj4/1/

@andershessellund
Copy link
Contributor

ngFocus should definitely not work like this.

Angular is based on bidirectional data binding, which means that if the focus attribute is bound to a model, the model should be updated when the element looses focus.

An ngFocus which works analogous to the ngBlur directive above would be a good idea.

A directive which focuses an element when it becomes visible could be a good idea.

@narenana
Copy link

Any updates on this ?

@philips
Copy link

philips commented Dec 31, 2012

Thanks for posting this even if it isn't a great longterm solution. I needed ng-focus too. 👍

@arcanis
Copy link

arcanis commented Jan 2, 2013

I'm using the following snippet to support blur, focus, keydown, keyup and keypress. Almost all the code comes from the original source code of angular, except that I'm using Array#reduce to avoid creating a named temporary object to store the directives.

.directive( [ 'focus', 'blur', 'keyup', 'keydown', 'keypress' ].reduce( function ( container, name ) {
    var directiveName = 'ng' + name[ 0 ].toUpperCase( ) + name.substr( 1 );

    container[ directiveName ] = [ '$parse', function ( $parse ) {
        return function ( scope, element, attr ) {
            var fn = $parse( attr[ directiveName ] );
            element.bind( name, function ( event ) {
                scope.$apply( function ( ) {
                    fn( scope, {
                        $event : event
                    } );
                } );
            } );
        };
    } ];

    return container;
}, { } ) );

@andriytyurnikov
Copy link

@andershessellund or someone else, could you please give deeper explanation about why model should care about element focus or blur at all?

Any HTML element is able to get focus - link or table header cell.

From what I understand now, it will be enough if one should be able to trigger 'change' event manually.

Also, as far as I know ngChange and ngModel directives are implemented only for input, select, and textarea tags.
And keyboard and focus events can be used with any DOM element, and not necessary will modify models (think about gestures, hotkey shortcuts and key-combos).

@saden1
Copy link

saden1 commented Jan 16, 2013

@andriytyurnikov

One use-case I can think of is the ability to increase the number of rows in a textarea when it's focused and reduce it when it loses focus. Sorta like the tweet box on twitter.

@andershessellund
Copy link
Contributor

@andriytyurnikov

Just to clarify, I think that ngFocus and ngBlur should simply bind events to event handlers, like the code by @arcanis . My point was if one was to write a directive that that binds the focus status of an element to a boolean value on the model, it should be two-way. The code snippet posted by @avimar above, which is an ng-focus directive that sets focus on an element when a boolean attribute on the model changes to true should be handled using an event instead.

A two-way binding directive could perhaps be implemented, but it would be different than directives such as ng-selected or ng-disabled, because elements do not actually have a 'focused' property. In my opinion, such a directive does not really belong in core angular.

A directive that sets focus on an element when it becomes visible could be a good idea.

A directive that sets focus on an element when an angular event occurs could also be a good idea.

@amfern
Copy link

amfern commented Mar 28, 2013

+1

@ganarajpr
Copy link

So I have been working on an implementation of ngFocus that is two way bound to a boolean. I would like to solicit comments and feedback before I bring in a pull request of the same.

Here is a plunk which contains an implementation of the same.

http://plnkr.co/edit/CvPCVxy4MfJEM1UksrrA?p=preview

Points of consideration :

  1. Multiple objects / elements cannot have focus at the same time. So if we set the same variable to multiple elements it creates a race condition and goes into an infinite loop with focus jumping between the elements infinitely. This has to be prevented.
  2. Its two way data-binding. So we cannot be assigning a function to focus unless the function is also a setter.

Feedback and comments are welcome. I would like to push this to the core if it is approved.

Is this the right way to handle focus and blur? ( we would create ngFocus and ngBlur like ngShow and ngHide ). Are there any problems with this implementation ?

@defel
Copy link

defel commented Apr 11, 2013

+1 for @ganarajpr solution

@chadwhitacre
Copy link
Contributor

+1

@fabsor
Copy link

fabsor commented Apr 14, 2013

@ganarajpr Solution looks good. Would it work with jqlite if we change $(element).focus and $(element).blur to element.bind("focus") and element.bind("blur") ?

@fabsor
Copy link

fabsor commented Apr 14, 2013

This seems to work without Jquery as a dependency.
http://plnkr.co/edit/3ZyYAvgQTQh1vJ1hFiw9

@ganarajpr
Copy link

@fabsor Thank you. I was going to update my plunk with a version that is a bit more advanced. But was not sure if it was necessary or not.

Here is a plunk

http://plnkr.co/edit/bntEsfngnJKuneg2raD1

This one is without jquery and also there is one additional thing. If the developer assigns the same model to multiple ng-focus directives ( anywhere in the app! ) that means that focus will start jumping between these. I have put in a kind of hack to prevent this. I dont know whether we want to put these in or if there is a more clean way of ensuring that a model is assigned to just one ng-focus.

@fabsor
Copy link

fabsor commented Apr 14, 2013

@ganarajpr Ugh, a timer doesn't seem like a good solution.
I don't know exactly how to implement this, but it might be possible to check that only one element can be focused per $digest(), and if more than one element is focused, we could throw an error?

@ganarajpr
Copy link

@fabsor The intersting question is how we could achieve that!

If @IgorMinar / @mhevery / @vojtajina have any opinions about this it would be awesome. I think focus and blur are one of the most common things people currently miss in the framework and an opinion in that matter would be great.

@eliotsykes
Copy link

Gist to get ngFocus and ngBlur directives if you need them now https://gist.github.com/eliotsykes/5394631

@saada
Copy link

saada commented Apr 26, 2013

👍

2 similar comments
@vanb
Copy link

vanb commented May 1, 2013

+1

@ninjacato
Copy link

+1

@sanfords
Copy link
Contributor

ganarajpr's solution is working amazingly well. Bravo!

@uri
Copy link

uri commented May 16, 2013

+1

1 similar comment
@e-oz
Copy link

e-oz commented May 20, 2013

+1

@zhuangya
Copy link

+1

5 similar comments
@dariusk
Copy link

dariusk commented Jun 6, 2013

+1

@romanesko
Copy link

+1

@zabojad
Copy link

zabojad commented Jun 14, 2013

+1

@matekdk
Copy link

matekdk commented Jun 17, 2013

+1

@shangxiao
Copy link

+1

@romanesko
Copy link

ganarajpr, it doesn't work for child scopes

@weiher
Copy link

weiher commented Jun 20, 2013

childscope for focus/blur?

@romanesko
Copy link

yes

@ganarajpr
Copy link

@8026787 It should work with child scopes as well. It works very similiar to how ng-model works. If you can provide more details as to what you are trying and in what scenario it doesnt work with child scopes it would be helpful.

@gregpakes
Copy link

Just want to add to the conversation. For my use case, I need to bind to a function and do not require the 2-way data-binding nature of @ganarajpr 's solution. For me @avimar 's solution was a better fit. I'm still just learning Angular.

@romanesko
Copy link

I'm sorry, my fault. It works good with child scopes.

So the easiest way to get blur event in controller - it's to add the $watch()?

I mean if I need to save field data after it losts focus:

template:

<input ng-model="name" ng-focus="focus.name">

controller:

$scope.$watch('focus.name', function(newval){
    if(newval===false) onBlur('name')
})

and for every field I need to add separate watch...
is it possible to make ng-focus accept functions directly? like

<input ng-model="name" ng-focus="onFocus('name')">

@arcanis
Copy link

arcanis commented Jul 1, 2013

ngFocus and ngBlur should not be setters, or it would break consistency with other native browser events.

@IgorMinar / @mhevery / @vojtajina, is there a particular reason for not including these events ? I saw that you mentionned them in the #314, but they seem to have been forgotten since then :)

@palmkevin
Copy link

+1

@uri
Copy link

uri commented Jul 4, 2013

@arcanis I've been using your solution for a while now and it's great! The only issue is that reduce is only supported in IE 9 or lower.

@rayshan
Copy link

rayshan commented Jul 6, 2013

+1

@leefernandes
Copy link
Contributor

+100,000

@tanweihao
Copy link

+1 for arcanis's solution. This should really be in the default API.

@mbielski
Copy link

If the purpose is setting the focus or causing a blur on a specific element, @ganarajpr has the best solution. I am using this directive and am happy with it, but there are no unit tests for it, and I am going to end up writing them myself unless the author posts some. There is also a good checklist for submitting a PR to be found here: #2979.

If the purpose is reacting to a focus or blur event, the folks at AngularUI have a very good solution: https://github.com/angular-ui/ui-utils/blob/master/modules/event/event.js. I use this module in several places and am very happy with it.

@29x10
Copy link

29x10 commented Jul 18, 2013

@ganarajpr thanks +1

@pkozlowski-opensource
Copy link
Member

Read only support for blur / focus events just landed in master. Let's move the discussion about setting focus to #2012

ctrahey pushed a commit to ctrahey/angular.js that referenced this issue Jul 22, 2013
Added directives for focus and blur events.

Closes angular#1277
@Narretz
Copy link
Contributor

Narretz commented Sep 6, 2013

for anyone else wondering where exactly the commit landed: 2bb27d4

@andreas-gruenbacher
Copy link
Contributor

@ganarajpr: thanks for your solution, it works well enough given how hard Angular makes this kind of thing. (The hack for detecting multiple bound elements is an abomination though.)

An issue I have with setting focus in JavaScript with .focus() in general is that it doesn't behave the same as when the user sets the focus on a text field (when jumping between fields or clicking on a label): when the user jumps to a field, the field automatically gets selected, but .focus() doesn't .select() the text; it doesn't even focus to the end of the text. I need consistent behavior for this.

So whichever directive eventually gets added to Angular should either implement "focus and select" or should allow to customize what happens.

@fopsdev
Copy link

fopsdev commented Oct 20, 2013

@andreas-gruenbacher yes having the same issue here. i've workarounded it by also sending a "cklick" event.
would be great to have focus & click in an angular way

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests