As an angular user, I too shudder at the title of this question, due to the fact that IE8 is evil incarnate and should be put down like a rabid dog.
that being said, I w
There is a way, though it's a bit rough. Below is the code you need to load before angular and your app may run. This is a collection of shims/polyfills, mostly from Mozilla Developer Network some by me.
Please note, that this only allows AngularJS to run, it doesn't update the JS runtime of IE8. So things like somePromise.catch(...)
won't work, you must write somePromise["catch"](...)
.
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(searchElement) {
if (this.length === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (isNaN(n)) {
n = 0;
} else if (n !== 0 && n !== Infinity && n !== -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= this.length) {
return -1;
}
var k = n >= 0 ? n : Math.max(this.length - Math.abs(n), 0);
while (k < this.length) {
if (k in this && this[k] === searchElement) {
return k;
}
++k;
}
return -1;
};
}
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun/*, thisArg*/) {
if (this === undefined || this === null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== 'function') {
throw new TypeError();
}
var res = [];
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t) {
var val = t[i];
if (fun.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
return res;
};
}
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
if (!Array.prototype.every) {
Array.prototype.every = function(callbackfn, thisArg) {
'use strict';
var T, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
var len = O.length >>> 0;
if (typeof callbackfn !== 'function') {
throw new TypeError();
}
if (arguments.length > 1) {
T = thisArg;
}
k = 0;
while (k < len) {
var kValue;
if (k in O) {
kValue = O[k];
var testResult = callbackfn.call(T, kValue, k, O);
if (!testResult) {
return false;
}
}
k++;
}
return true;
};
}
if (!Object.create) {
Object.create = (function() {
var Object = function() {};
return function (prototype) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof prototype != 'object') {
throw new TypeError('Argument must be an object');
}
Object.prototype = prototype;
var result = new Object();
Object.prototype = null;
return result;
};
})();
}
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(fun /*, thisArg */) {
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; ++i) {
if (i in t)
fun.call(thisArg, t[i], i, t);
}
};
}
if (!String.prototype.trim) {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/gm, '');
};
}
(function() {
//$http uses onload instead of onreadystatechange. Need shimming as IE8 doesn't have onload.
if (new XMLHttpRequest().onload === undefined) {
var orig = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
var self = this;
if (!this.onreadystatechange && this.onload) {
this.onreadystatechange = function() {
if (self.readyState === 4) {
self.onload();
}
};
}
orig.apply(self, arguments);
};
}
})();
if (!Date.now) {
Date.now = function() {
return new Date().getTime();
};
}
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {
},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
if (!Object.keys) {
Object.keys = function(object) {
var keys = [];
for (var o in object) {
if (object.hasOwnProperty(o)) {
keys.push(o);
}
}
return keys;
};
}
if (!Object.getPrototypeOf) {
Object.getPrototypeOf = function(object) {
return object.__proto__ || object.constructor.prototype;
};
}
If you have angular-bootstrap, you also need to "patch" the angular.min.js file, because angular-boostrap uses {in: someCondition}
, but because of the older JS runtime the in
keyword is reserved and will fail in the code generation.
Find: var e=(b?"s":'((l&&l.hasOwnProperty("'+a+'"))?l:s)')+"."+a;
Replace: var e=(b?"s":'((l&&l.hasOwnProperty("'+a+'"))?l:s)')+"['"+a+"']";
Github user @fergaldoyle maintains a repo that combines shiming/polyfill and other patch strategies in order to maintain compatibility.
This could be a viable strategy for many solution providers
Per the comments on the question, and Zenorbi's answer, Angular 1.3 does NOT load correctly in IE8 anymore. It was never designed to continue working in IE8, so this should not come as a surprise.
I actually came up with a simple workaround that will make page load times slightly slower for any IE8 users which is an acceptable loss for me.
using this code, I can simply load 1.3 by default, and if any IE8 users load the page, it will simply load angular 1.2 directly afterwards, simply overwriting any duplicated code:
<script type="text/javascript" src="target/libraries/angular.min.js"></script>
<!--[if lt IE 9]>
<script type="text/javascript" src="target/libraries/angular-1.2.min.js"></script>
<![endif]-->
<script type="text/javascript" src="target/libraries/angular-route.min.js"></script>
<!--[if lt IE 9]>
<script type="text/javascript" src="target/libraries/angular-route-1.2.min.js"></script>
<![endif]-->
note: This is terrible practice generally. If we were making a larger effort to support IE8 users, I would go with Zenorbi's answer, since it allows you to load only one version of angular.
From Angular Developer Guide migration docs:
Note: AngularJS 1.3 is dropping support for IE8. Read more about it on our blog. AngularJS 1.2 will continue to support IE8, but the core team does not plan to spend time addressing issues specific to IE8 or earlier.
Based on answers from SamHuckaby and Zenorbi, i came up with acceptable solution which is a combination of their ideas and insights from this article IF Internet Explorer THEN Do Something Else (A How To...) by Phil Nash:
<!--[if !IE]>-->
<script src="/ui/resources/webjars/angularjs/1.4.0/angular.js"></script>
<script src="/ui/resources/webjars/angularjs/1.4.0/angular-route.js"></script>
<!--<![endif]-->
<!--[if gt IE 8]>
<script src="/ui/resources/webjars/angularjs/1.4.0/angular.js"></script>
<script src="/ui/resources/webjars/angularjs/1.4.0/angular-route.js"></script>
<![endif]-->
<!--[if lt IE 9]>
<script type="text/javascript" src="/ui/resources/lib/angularjs/1.2.28/angular.js"></script>
<script type="text/javascript" src="/ui/resources/lib/angularjs/1.2.28/angular-route.js"></script>
<![endif]-->
<script type="text/javascript" src="webjars/es5-shim/4.0.6/es5-shim.js"></script>
<script type="text/javascript" src="webjars/es6-shim/0.20.2/es6-shim.js"></script>
<!--[if !IE]>-->...<!--<![endif]-->
- Conditional comment will be evaluated by IE
, but the scripts within won't get loaded by IE
and will get loaded by all other browsers
<!--[if gt IE 8]>...<![endif]-->
- Conditional comment will be evaluated by IE
and if greater than IE 8, scripts will get loaded
<!--[if lt IE 9]>...<![endif]-->
- Conditional comment will be evaluated by IE
and if less than IE 9, scripts will get loaded.
Both es5-shim
and es6-shim
should be put out of IE8
conditional comment block and checked by all browsers (and it's not expensive operation) as i recently found out that Safari
has issues with String.prototype.startsWith()
Yeah we have some code duplication inside the first and the second conditional comment (and it can't be solved in a different way) but we have zero unwanted scripts loaded and we can close our task here.
I tried L0lander's answer (which was my preferred one), but when using older angular version, other scripts complained, and it ended up not working anyway. So, I checked statistics at my site, and 0,2% only use IE8 or less, and I won't be giving myself headache over such a small crowd, so I simply added a message asking users of IE8 or less to upgrade.
Add following code just after body
tag to all of your pages:
<!--[if lt IE 9]>
<div style="text-align: center; font-size: 22px; padding: 20px; background-color: #d14c4c; color: #f3e3e3;">Your version of Internet Explorer is too old for this site to function properly.<br>Please <a href="https://www.google.com/search?q=update+internet+explorer" target="_blank" style="text-decoration: underline; color: #76c880">click here</a> to upgrade to a newer version.</div>
<![endif]-->