Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - issue with ng-blur on iPhone/iPad

I use AngularJS 1.4.7

I have editable input. If we focus on input and after click outside of this input field, script will do function "save()" in ng-blur. Everything work correctly, but on iPhone 5/6 and iPad don't work (not execute anything in ng-blur). I don't know why, but I deduce that problem is in focus/touch action. Someone know where is the problem?

like image 566
Albatros Avatar asked Feb 09 '23 03:02

Albatros


2 Answers

Fix ng-blur not working on empty space and most elements with iOS

Goal

In my app, we wanted to hide open menus or search results when clicking away from the menu or search box.

Problem

iOS Safari does not blur properly when clicking away from the current element.

Note

You do not need a special directive. The problem is not with ng-blur, which works fine. The problem is that a blur event never occurs because of Apple's unusual design on iOS, regardless of whether you use ng-blur or a native DOM blur event.

Reason for Issue

Apple has designed mobile Safari to perform event bubbling differently than desktop browsers do. According to official Apple docs, if an element that is clicked has no click listener attached to it, then no click event is triggered. Without a click event, focus does not change and no blur event occurs, so the current element does not lose focus even though the user really did click elsewhere on the page.

The blur will only happen if the user clicked an element with a click event listener. Some elements like hyperlinks and inputs have "built-in" event listeners for click, and so will always register a click, causing blur to work.

Normally in desktop browsers, the click event is blindly fired whether there is a registered listener or not in the element's DOM hierarchy. That is why ng-blur works as expected in desktop browsers, even on "empty space".

Apple says that for iOS Safari they only dispatch the event if they find an element registered to listen for it.

Apple Docs - go to Figure 6-4

Apple's documentation makes it sound like they are looking for a registered event listener and handled on the target element, but that is not the case. I found the answers in the following article, and more importantly, one of the comments to it.

Quirksmode Article on iOS event delegation

First, observe that placing a listener on the document or body does not cause the click event to be dispatched on iOS Safari, if the target element has no click event listener and handler. It works in most browsers, but not on iOS.

It appears that Apple is checking the DOM hierarchy up to the <body> tag before dispatching the click event, but is not checking the <body> tag or above. Therefore, you need a click event listener attached to an element somewhere below the <body>.

Solution/Workaround

The solution then is very simple. All you need to do is to wrap all of the page content in a "master" container element just below the <body> element, and put the listener there instead of on the body or the document. It can even be an empty handler function. Apple is only checking to see if one is registered. The reason for wrapping all content is so that no matter where in the page the user clicks, the bubble-up process will eventually reach the master container.

If you do that, then ng-blur will work as expected in iOS, because the click event on empty space (an element with no click event listener) will pass the iOS check when it finds the parent container's click event listener and a click event will be dispatched normally, like it would be in any other browser.

Caution

This solution effectively causes iOS Safari to see a click event listener on every DOM element's hierarchy, tricking it into dispatching the click event on every element, just like a normal browser. I do not know if Apple has a performance reason they avoid this in iOS, or if it is just an aesthetic/developer type preference (see example). You will be changing the default iOS behavior in your app by using this workaround.

For example, iOS users may accidentally select text on your page that they did not mean too, and which would not normally occur without a click and hold gesture.

like image 50
Daniel Nalbach Avatar answered Feb 10 '23 15:02

Daniel Nalbach


I don't know why that problem occurs. but do one thing. create one small directive 'fake-blur' . then call your method in that directive

App.directive('fakeBlur', function(){
   return {
     restrict: 'A',
     link: function(scope, element, attrs) {
         element.blur(function(){
          // call you function ex:
            scope.save();
          
          })
      }
   }
});
<input type="text" fake-blur/>
like image 34
saikumar Avatar answered Feb 10 '23 15:02

saikumar