Routing in angular app that worked in ios8, produces a [$rootScope:infdig] error in ios9. I have tried both ngRoute and ui.router but the result is the same.
Error: [$rootScope:infdig] http://errors.angularjs.org/1.4.3/$rootScope/infdig?p0=10&p1=%5B%5D
Any solution to this?
Even though this is marked as a duplicate of this question. This is the best way to resolve this issue.
ionic app iOS 9 problems [$rootScope:infdig] 10 $digest() iterations reached
The selected answer in this post directs you over to this plugin which patches all the iOS9 issues with angular.
https://gist.github.com/IgorMinar/863acd413e3925bf282c
This Patch works for Angular 1.2.0 – 1.4.5 and all newer versions of angular will have this fix embedded.
This answer from Clever Coder on angular issue 12241 based on Angular v1.4.3
diff --git a/src/ng/browser.js b/src/ng/browser.js
index 928de95..3b9957e 100644
--- a/src/ng/browser.js
+++ b/src/ng/browser.js
## -87,7 +87,9 ## function Browser(window, document, $log, $sniffer) {
var cachedState, lastHistoryState,
lastBrowserUrl = location.href,
baseElement = document.find('base'),
- reloadLocation = null;
+ reloadLocation = null,
+ pendingHref = null,
+ pendingHrefTimer = null;
cacheState();
lastHistoryState = cachedState;
## -124,6 +126,18 ## function Browser(window, document, $log, $sniffer) {
if (location !== window.location) location = window.location;
if (history !== window.history) history = window.history;
+ // Schedule cleaning up pendingHref on the next run loop for setting URL. This is to handle
+ // the case where the browser doesn't update the location.* properties immediately
+ if (!pendingHrefTimer && pendingHref && url) {
+ pendingHrefTimer = setTimeout(function () {
+ if (location.href == pendingHref) {
+ console.log('Actual href updated... setting pendingHref to null from setTimeout');
+ pendingHref = null;
+ }
+ pendingHrefTimer = null;
+ }, 0);
+ }
+
// setter
if (url) {
var sameState = lastHistoryState === state;
## -147,6 +161,7 ## function Browser(window, document, $log, $sniffer) {
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
} else {
+ pendingHref = url;
if (!sameBase || reloadLocation) {
reloadLocation = url;
}
## -161,10 +176,22 ## function Browser(window, document, $log, $sniffer) {
return self;
// getter
} else {
+ var href = location.href.replace(/%27/g, "'");
+ if (pendingHref) {
+ //console.log('.. using pendingHref for url() return value');
+ href = pendingHref;
+ }
+
+ if (location.href == pendingHref) {
+ console.log('Actual href updated... setting pendingHref to null in getter');
+ pendingHref = null;
+ }
+
+ //var href = location.href.replace(/%27/g,"'");
// - reloadLocation is needed as browsers don't allow to read out
// the new location.href if a reload happened.
// - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
- return reloadLocation || location.href.replace(/%27/g,"'");
+ return reloadLocation || href;
}
};
Apparently resolves the issue, but not in other versions of Angular.
Related
function getHTMLSource(url) {
return $http.get(url).then(function(response) {
var html = response.data;
url = getDetailPage(html)
return url ;
}
)};
getHTMLSource('http://www.footpatrol.co.uk/s:282524/search=282524/')
Whenever I attempt the above code, I get the following error message in my console GET http://localhost:9000/templates/footpatrol.co.uk/_assets/images/content/footpatrol_logo.png 404 (Not Found).
The image appears to exist at http://www.footpatrol.co.uk/templates/footpatrol.co.uk/_assets/images/content/footpatrol_logo.png but as I am running the scipt on localhost with Chrome's Allow-Control-Allow-Origin plugin, it appears to not play nicely. I do not want to GET the image I just want the source code, is there anyway around this?
UPDATE: I think it might be my parser causing the problem, because the error message is thrown here
function getDetailPage(html) {
var temp = document.createElement('div');
temp.innerHTML = html;
var a = temp.querySelector('a[class*=\'fp-product-thumb-link\']');
var partOfUrl = a.href;
var splitUrl = partOfUrl.split('/');
var url = 'http://www.footpatrol.co.uk/' + splitUrl[3] + '/' + splitUrl[4];
var url = 'http://www.footpatrol.co.uk/' + splitUrl[3] + '/' + splitUrl[4];
$log.debug('Detail page url found: ' + url);
return url;
}
Instead of creating an element, use the DOMParser API:
function getDetailPage(html) {
//var temp = document.createElement('div');
//temp.innerHTML = html;
var parser = new DOMParser();
var temp = parser.parseFromString(html, "text/html");
var a = temp.querySelector('a[class*=\'fp-product-thumb-link\']');
//var partOfUrl = a.href;
//console.log(partOfUrl);
//var splitUrl = partOfUrl.split('/');
//var url = 'http://www.footpatrol.co.uk/' + splitUrl[3] + '/' + splitUrl[4];
var elem = angular.element(a);
var url = 'http://www.footpatrol.co.uk/' + elem.attr('href');
console.debug('Detail page url found: ' + url);
return url;
}
Detail page url found: http://www.footpatrol.co.uk//footwear/282524-air-retro-15-obsidian.html
I am using ngMock for unit testing and I need to use the $timeout.flush function in one of my tests, so I have added the two following lines to my test:
$timeout.flush();
$timeout.verifyNoPendingTasks();
as indicated on http://www.bradoncode.com/blog/2015/06/11/unit-testing-code-that-uses-timeout-angularjs/.
$timeout.flush() does flush the timeout as expected, however I am now getting an exception from angular-mocks.js every time I run my test:
LOG: 'Exception: ', Error{line: 1441, sourceURL: 'http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd', stack: '$httpBackend#http://localhost:9876/base/node_modules/angular-mocks/angular-mocks.js?05a191adf8b7e3cfae1806d65efdbdb00a1742dd:1441:90
....
global code#http://localhost:9876/context.html:336:28'}, 'Cause: ', undefined
Does anyone know where this exception could come from? I get it as many times as I use the $timeout.flush() function.
Looking at the angular-mocks.js file, it looks like it comes from the $httpBackend function. I have tried to update the ngMock version but it does not change anything. I have tried version 1.4.7 (which is my angular version) and version 1.6.2.
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
xhr.$$events = eventHandlers;
xhr.upload.$$events = uploadEventHandlers;
function prettyPrint(data) {
return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
? data
: angular.toJson(data);
}
function wrapResponse(wrapped) {
if (!$browser && timeout) {
if (timeout.then) {
timeout.then(handleTimeout);
} else {
$timeout(handleTimeout, timeout);
}
}
return handleResponse;
function handleResponse() {
var response = wrapped.response(method, url, data, headers, wrapped.params(url));
xhr.$$respHeaders = response[2];
callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
copy(response[3] || ''));
}
function handleTimeout() {
for (var i = 0, ii = responses.length; i < ii; i++) {
if (responses[i] === handleResponse) {
responses.splice(i, 1);
callback(-1, undefined, '');
break;
}
}
}
}
if (expectation && expectation.match(method, url)) {
if (!expectation.matchData(data)) {
throw new Error('Expected ' + expectation + ' with different data\n' +
'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
}
if (!expectation.matchHeaders(headers)) {
throw new Error('Expected ' + expectation + ' with different headers\n' +
'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
prettyPrint(headers));
}
expectations.shift();
if (expectation.response) {
responses.push(wrapResponse(expectation));
return;
}
wasExpected = true;
}
var i = -1, definition;
while ((definition = definitions[++i])) {
if (definition.match(method, url, data, headers || {})) {
if (definition.response) {
// if $browser specified, we do auto flush all requests
($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
} else if (definition.passThrough) {
originalHttpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers);
} else throw new Error('No response defined !');
return;
}
}
throw wasExpected ?
new Error('No response defined !') :
new Error('Unexpected request: ' + method + ' ' + url + '\n' +
(expectation ? 'Expected ' + expectation : 'No more request expected'));
}
have a some data one my page that is in a ng-repeat.
When the page and data 1st loads the data shows up.
When I move away from the page (using Angular Routing) make a change to the data (gets saved in db) then come back into the page (make call to db get new data) the ng-repeat data does not refresh. I can see the new data loading into the array and it is the new data.
I start the process on the page with
var sp = this;
sp.viewData = [];
sp.employee = [];
sp.ViewDataTwo = [];
$(document).ready(function () {
var testHeader = setInterval(function () { myTimer() }, 1000);
function myTimer() {
if (addHeaderToken() != undefined) {
clearInterval(testHeader);
sp.usageText = "";
if (sessionStorage.getItem(tokenKey) != null) {
sp.associatedInfo = JSON.parse(getassociatedInfo());
loadDataOne();
loadDataTwo();
}
}
}
});
I do this because I need to get my security toke from a JS script that I have no power over changes. So I need to make sure the code has ran to get me the token.
here are the functions I call..
function loadPasses() {
$http.defaults.headers.common.Authorization = "Bearer " + addHeaderToken();
$http.get('/api/Employee/xxx', { params: { employeeId: sp.employeeId } }).then(function (data) {
sp.viewData = data.data;
for (var i = 0; i < $scope. viewData.length; i++) {
sp.passes[i].sortDateDisplay = (data.data.status == "Active" ? data.data.DateStart + "-" + data.data[i].DateEnd : data.data[i].visitDate);
sp.passes[i].sortDate = (data.data[i].status == "Active" ? data.data[i].DateStart: data.data[i].visitDate);
}
});
}
function loadDataTwo () {
$http.defaults.headers.common.Authorization = "Bearer " + addHeaderToken();
if (sessionStorage.getItem(tokenKey) != null) $http.get('/api/Employee',
{
params: { employeeId: sp.employeeId }
}).then(function (data) {
sp.employee = data.data;
var tempPassString = "";
sp.ViewDataTwo = [];
var totalA = 0;
var totalU = 0;
for (var p = 0; p < sp.employee.dataX.length; p++) {
sp.ViewDataTwo.push(sp.employee.dataX[p].description + "(" + /** math to update description **// + ")");
totalA += parseInt(parseInt(sp.employee.dataX[p].Anumber));
totalU += parseInt(sp.employee.dataX[p].Bnumber));
}
sp.usageArr.push(" Total: " + totalA- totalU) + "/" + totalA + " Available");
//$scope.$apply();
});
}
One my view sp.viewData and sp.ViewDataTwo are both in ng-repeats.
Works well on load.. when I go out and come back in. I see the data reloading. But the view does not.
I have hacked the Dom to get it to work for now. But I would like to do it the right way..
Any help.
I have used
$scope.$apply();
But it tells me the digest is already in process;
the views are in a template..
Please help
I have a pretty basic Angular Controller:
function PirateController($scope, $http) {
$scope.DetermineBooty = function () {
$scope.Processing = true;
$scope.SavedCount = $scope.PirateCount;
$scope.PirateCount = 'Please wait for Booty...';
$http.get('http://www.Suamere.com/Apps/SCA/API/Booty/' + $scope.SavedCount).
success(function (data) {
if (data != '"0"') {
$scope.ResultText = $scope.SavedCount + ' Pirates found a minimum of ' + data + ' coins.';
$scope.PirateCount = $scope.SavedCount;
} else {
$scope.ResultText = $scope.SavedCount + ' - There is no reason to calculate with that value.';
$scope.PirateCount = "";
}
$scope.Processing = false;
}).
error(function (data) {
$scope.ResultText = $scope.SavedCount + ' - There is no reason to calculate with that value.';
$scope.PirateCount = "";
$scope.Processing = false;
});
};
}
When I publish this to my website, the Error never hits, and that's good. Also, the Success hits and process correctly every time, and that's good.
But when I'm running this on my localhost in VS2013, the error always hits. And the data is always empty.
However, in Fiddler, the result appears to be comming back correctly either on my website or on my localhost. So why, only in my VS2013, is Angular catching empty when the HTTP Return obviously has something in it.
If you are using an absolute URL as shown then when you run on localhost you are making a cross domain request.
Use relative URL's or set the domain using a variable
I am trying to implement named routes, so I don't have to write the whole path (often changes).
I was thinking I could get away with writing a service that would return the list of defined routes and a filter that would transform object to aroute
The use example would look like:
<a ng-href="{id:1}|route:'detail'">Click here!</a>
Provided I have added name:'detail' to my route definition, this would generate the following result :
Click here!
I think this is quite simple, but:
How can I get the list of defined routes ?
I was thinking I can make use of routeProvider , but AFAIK it has no public methods or attributes I can access.
turns out this is pretty straight forward:
http://plunker.co/edit/GNZxcvK4hfQ9LrlSvasK?p=preview
Components.filter('url', function ($route) {
function resolveRoute(options, route) {
var parts = route.split('/');
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part[0] === ':') {
parts[i] = options[part.replace(':', '')];
if (parts[i] == undefined) throw Error('Attribute \'' + part + '\' was not given for route \'' + route + '\'')
}
}
return parts.join('/');
}
return function (options, routeName) {
var routes = [];
angular.forEach($route.routes,function (config,route) {
if(config.name===routeName){
routes.push(route);
}
});
if (routes.length == 1) {
return resolveRoute(options, routes[0]);
}
else if (routes.length == 0) {
throw Error('Route ' + routeName + ' not found');
}
throw Error('Multiple routes matching ' + routeName + ' were found');
}
});