66

I am new to angularjs. How can I detect userAgent in angularjs. Is it possible to use that in controller? Tried something like below but no luck!

  var browserVersion = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);

I need to detect IE9 specifically!

3
  • 6
    i think the question here is why would you want to detect the browser using angular? is there a particular feature you want to sniff for? Commented Apr 8, 2014 at 20:35
  • 1
    Can't speak for OP; the need that led me to this related question is described in this question: (stackoverflow.com/questions/16098430/…). Essentially IE performs aggressive caching; I'm not aware of Modernizr style features that can be checked for this. Commented May 16, 2014 at 15:28
  • My specific case for detecting browser is that IE is not detecting change in localStorage (event storage) if developer console is switched off. I do not know why yet. So when using "real" browsers I am on relying on storage event but in case of IE I have to use interval to check localStorage periodically. Commented Sep 19, 2016 at 9:22

11 Answers 11

69

Like Eliran Malka asked, why do you need to check for IE 9?

Detecting browser make and version is generally a bad smell. This generally means that you there is a bigger problem with the code if you need JavaScript to detect specific versions of browser.

There are genuine cases where a feature won't work, like say WebSockets isn't supported in IE 8 or 9. This should be solved by checking for WebSocket support, and applying a polyfill if there is no native support.

This should be done with a library like Modernizr.

That being said, you can easily create service that would return the browser. There are valid cases where a feature exists in a browser but the implementation is outdated or broken. Modernizr is not appropriate for these cases.

app.service('browser', ['$window', function($window) {

     return function() {

         var userAgent = $window.navigator.userAgent;

        var browsers = {chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer/i};

        for(var key in browsers) {
            if (browsers[key].test(userAgent)) {
                return key;
            }
       };

       return 'unknown';
    }

}]);

Fixed typo broswers

Note: This is just an example of how to create a service in angular that will sniff the userAgent string. This is just a code example that is not expected to work in production and report all browsers in all situations.

UPDATE

It is probably best to use a third party library like https://github.com/ded/bowser or https://github.com/darcyclarke/Detect.js. These libs place an object on the window named bowser or detect respectively.

You can then expose this to the Angular IoC Container like this:

angular.module('yourModule').value('bowser', bowser);

Or

detectFactory.$inject = ['$window'];
function detectFactory($window) {
    return detect.parse($window.navigator.userAgent);
} 
angular.module('yourModule').factory('detect', detectFactory);

You would then inject one of these the usual way, and use the API provided by the lib. If you choose to use another lib that instead uses a constructor method, you would create a factory that instantiates it:

function someLibFactory() {
    return new SomeLib();
}
angular.module('yourModule').factory('someLib', someLibFactory);

You would then inject this into your controllers and services the normal way.

If the library you are injecting does not exactly match your requirements, you may want to employ the Adapter Pattern where you create a class/constructor with the exact methods you need.

In this example we just need to test for IE 9, and we are going to use the bowser lib above.

BrowserAdapter.$inject = ['bowser']; // bring in lib
function BrowserAdapter(bowser) {
    this.bowser = bowser;
}

BrowserAdapter.prototype.isIe9 = function() {
    return this.bowser.msie && this.browser.version == 9;
}

angular.module('yourModule').service('browserAdapter', BrowserAdapter);

Now in a controller or service you can inject the browserAdapter and just do if (browserAdapter.isIe9) { // do something }

If later you wanted to use detect instead of bowser, the changes in your code would be isolated to the BrowserAdapter.

UPDATE

In reality these values never change. IF you load the page in IE 9 it will never become Chrome 44. So instead of registering the BrowserAdapter as a service, just put the result in a value or constant.

angular.module('app').value('isIe9', broswerAdapter.isIe9);
Sign up to request clarification or add additional context in comments.

16 Comments

typo in forEach: broswers, replace with browsers
Two further problems: 1. The angular.forEach() loop won't work, as it just loops through every item. Better off with an old-fashioned for...in construct. 2. The regex /internet explorer/i won't detect IE 11 and the code instead reports it as Chrome, see stackoverflow.com/questions/17907445/how-to-detect-ie11 Searching for /trident/i I believe works for all versions of IE compatible with Angular. For now.
Sometimes browsers implement the same features with different behaviours (e.g. placeholder hides on focus OR keydown). So you have to walkt this way
The latest version of Chrome reports this: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36". So, depending on the order in which your forEach statement retrieves keys, it can return different results.
"Detecting browser make and version is generally a bad smell." No it doesn't when you consider that the purpose of detecting the browser version 99 out of 100 times it is intended for the abomination that is Internet Explorer. In my 6 years of web development, I've only needed this feature because of Internet Explorer, due to IE pretending to be Mozilla since 1995, that goes to show you that it's Microsoft's fault, not the web developer's.
|
26

Angular library uses document.documentMode to identify IE . It holds major version number for IE, or NaN/undefined if User Agent is not IE.

/**
* documentMode is an IE-only property
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
*/
var msie = document.documentMode;

https://github.com/angular/angular.js/blob/v1.5.0/src/Angular.js#L167-L171

Example with $document (angular wrapper for window.document)

// var msie = document.documentMode;
var msie = $document[0].documentMode;
// if is IE (documentMode contains IE version)
if (msie) {
  // IE logic here

  if (msie === 9) {
    // IE 9 logic here

  }
}

1 Comment

Several times I come across large complicated answers with regular expression testing on window.navigator etc. When it is only IE we wish to defeat, this appears to be the singular best way.
16

you should use conditional comments

<!--[if IE 9]>
<script type="text/javascript">
    window.isIE9 = true;
</script>
<![endif]-->

You can then check for $window.isIE9 in your controllers.

1 Comment

OP said: I need to detect IE9 specifically!
13

Not sure why you specify that it has to be within Angular. It's easily accomplished through JavaScript. Look at the navigator object.

Just open up your console and inspect navigator. It seems what you're specifically looking for is .userAgent or .appVersion.

I don't have IE9 installed, but you could try this following code

//Detect if IE 9
if(navigator.appVersion.indexOf("MSIE 9.")!=-1)

2 Comments

If you have IE10 or IE11 installed you can use IE's F12 feature to render as IE9.
Currently deprecated
12

You can easily use the "ng-device-detector" module.

https://github.com/srfrnk/ng-device-detector

var app = angular.module('myapp', ["ng.deviceDetector"]);
app.controller('DeviceCtrl', ["$scope","deviceDetector",function($scope,deviceDetector) {
      console.log("browser: ", deviceDetector.browser);
      console.log("browser version: ", deviceDetector.browser_version);
      console.log("device: ", deviceDetector.device);
}]);

Comments

7

So, you can declare more utilities for angular by create file with content (I follow RGraph Library)

(function(window, angular, undefined) {'use strict';
    var agl = angular || {};
    var ua  = navigator.userAgent;

    agl.ISFF     = ua.indexOf('Firefox') != -1;
    agl.ISOPERA  = ua.indexOf('Opera') != -1;
    agl.ISCHROME = ua.indexOf('Chrome') != -1;
    agl.ISSAFARI = ua.indexOf('Safari') != -1 && !agl.ISCHROME;
    agl.ISWEBKIT = ua.indexOf('WebKit') != -1;

    agl.ISIE   = ua.indexOf('Trident') > 0 || navigator.userAgent.indexOf('MSIE') > 0;
    agl.ISIE6  = ua.indexOf('MSIE 6') > 0;
    agl.ISIE7  = ua.indexOf('MSIE 7') > 0;
    agl.ISIE8  = ua.indexOf('MSIE 8') > 0;
    agl.ISIE9  = ua.indexOf('MSIE 9') > 0;
    agl.ISIE10 = ua.indexOf('MSIE 10') > 0;
    agl.ISOLD  = agl.ISIE6 || agl.ISIE7 || agl.ISIE8; // MUST be here

    agl.ISIE11UP = ua.indexOf('MSIE') == -1 && ua.indexOf('Trident') > 0;
    agl.ISIE10UP = agl.ISIE10 || agl.ISIE11UP;
    agl.ISIE9UP  = agl.ISIE9 || agl.ISIE10UP;

})(window, window.angular);

after that, in your function use can use it like

function SampleController($scope){
    $scope.click = function () {
        if(angular.ISCHROME) {
        alert("is chrome");
    }
}

2 Comments

Monkey patching angular is considered a bad practice.
Yes Martin, we can instead window.angular by another variable. No need window.angular
4

I modified the above technique which was close to what I wanted for angular and turned it into a service :-). I included ie9 because I was having some issues in my angularjs app, but could be something I'm doing, so feel free to take it out.

angular.module('myModule').service('browserDetectionService', function() {

 return {
isCompatible: function () {

  var browserInfo = navigator.userAgent;
  var browserFlags =  {};

  browserFlags.ISFF = browserInfo.indexOf('Firefox') != -1;
  browserFlags.ISOPERA = browserInfo.indexOf('Opera') != -1;
  browserFlags.ISCHROME = browserInfo.indexOf('Chrome') != -1;
  browserFlags.ISSAFARI = browserInfo.indexOf('Safari') != -1 && !browserFlags.ISCHROME;
  browserFlags.ISWEBKIT = browserInfo.indexOf('WebKit') != -1;

  browserFlags.ISIE = browserInfo.indexOf('Trident') > 0 || navigator.userAgent.indexOf('MSIE') > 0;
  browserFlags.ISIE6 = browserInfo.indexOf('MSIE 6') > 0;
  browserFlags.ISIE7 = browserInfo.indexOf('MSIE 7') > 0;
  browserFlags.ISIE8 = browserInfo.indexOf('MSIE 8') > 0;
  browserFlags.ISIE9 = browserInfo.indexOf('MSIE 9') > 0;
  browserFlags.ISIE10 = browserInfo.indexOf('MSIE 10') > 0;
  browserFlags.ISOLD = browserFlags.ISIE6 || browserFlags.ISIE7 || browserFlags.ISIE8 || browserFlags.ISIE9; // MUST be here

  browserFlags.ISIE11UP = browserInfo.indexOf('MSIE') == -1 && browserInfo.indexOf('Trident') > 0;
  browserFlags.ISIE10UP = browserFlags.ISIE10 || browserFlags.ISIE11UP;
  browserFlags.ISIE9UP = browserFlags.ISIE9 || browserFlags.ISIE10UP;

  return !browserFlags.ISOLD;
  }
};

});

Comments

3

There is a library ng-device-detector which makes detecting entities like browser, os easy.

Here is tutorial that explains how to use this library. Detect OS, browser and device in AngularJS

ngDeviceDetector

You need to add re-tree.js and ng-device-detector.js scripts into your html

Inject "ng.deviceDetector" as dependency in your module.

Then inject "deviceDetector" service provided by the library into your controller or factory where ever you want the data.

"deviceDetector" contains all data regarding browser, os and device.

Comments

1

Why not use document.documentMode only available under IE:

var doc = $window.document;
if (!!doc.documentMode)
{
  if (doc.documentMode === 10)
  {
    doc.documentElement.className += ' isIE isIE10';
  }
  else if (doc.documentMode === 11)
  {
    doc.documentElement.className += ' isIE isIE11';
  }
  // etc.
}

2 Comments

Sorry, may be a duplicate answer from Bohdan but with some extra…
or $document[0] instead $window.document
1

Browser sniffing should generally be avoided, feature detection is much better, but sometimes you have to do it. For instance in my case Windows 8 Tablets overlaps the browser window with a soft keyboard; Ridiculous I know, but sometimes you have to deal with reality.

So you would measure 'navigator.userAgent' as with regular JavaScript (Please don't sink into the habit of treating Angular as something distinct from JavaScript, use plain JavaScript if possible it will lead to less future refactoring).

However for testing you want to use injected objects rather than global ones. Since '$location' doesn't contain the userAgent the simple trick is to use '$window.location.userAgent'. You can now write tests that inject a $window stub with whatever userAgent you wan't to simulate.

I haven't used it for years, but Modernizr's a good source of code for checking features. https://github.com/Modernizr/Modernizr/issues/878#issuecomment-41448059

1 Comment

Hey, thx for your anser. Could you pls be so kind and provide a code snippet or a link for further reading?
0

Detection ie9+

var userAgent, ieReg, ie;
  userAgent = $window.navigator.userAgent;
  ieReg = /msie|Trident.*rv[ :]*11\./gi;
  ie = ieReg.test(userAgent);

if (ie) {
   // js for ie9,10 and 11
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.