opitzconsulting / jquery-mobile-angular-adapter

jquery mobile angular adapter
MIT License
517 stars 114 forks source link

If base-tag is set IE9 does a redirect (with "#!" in url) which leads to errors in "Angular" #189

Closed JGerke closed 11 years ago

JGerke commented 11 years ago

My problem:

if I set the base-tag to "base href='/'" the page won't be shown by IE9.

Example: If the URL is "http://myServer.net/myFolder/myPage.html" IE9 redirects automatically to "http://myServer.net/#!/myFolder/myPage.html" when page is loaded (-> a #! has been added).

This leads to errors in Angular: Error: 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [["fn: function(){var a=d.url(),b=f.$$replace;if(!l||a!=f.absUrl())l++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),h(a))});f.$$replace=!1;return l}; newVal: 7; oldVal: 6"],[...],["fn: function(){var a=d.url(),b=f.$$replace;if(!l||a!=f.absUrl())l++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),h(a))});f.$$replace=!1;return l}; newVal: 11; oldVal: 10"]]undefined SCRIPT5022: 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [["fn: function(){var a=d.url(),b=f.$$replace;if(!l||a!=f.absUrl())l++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),h(a))});f.$$replace=!1;return l}; newVal: 7; oldVal: 6"],[...],["fn: function(){var a=d.url(),b=f.$$replace;if(!l||a!=f.absUrl())l++,c.$evalAsync(function(){c.$broadcast(\"$locationChangeStart\",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),h(a))});f.$$replace=!1;return l}; newVal: 11; oldVal: 10"]] angular.min.js, Zeile 86 Zeichen 196

Am I doing something wrong?

Here is a jsFiddle:http://jsfiddle.net/ZHKBA/151/ It works fine in Firefox and Chrome, but not in IE9. If you call http://jsfiddle.net/ZHKBA/151/show you will see that the IE9 changes the URL to http://jsfiddle.net/#!/ZHKBA/151/show/ and throws errors

The same jsFiddle without the adapter works fine http://jsfiddle.net/ZHKBA/153

I use JQuery 1.9.0, JQM 1.3.0, Angular 1.0.5 and the Adapter 1.3.0

Thanks for your help

tbosch commented 11 years ago

Hi, here is an updated version of the jsfiddle with the current adapter, angular and jqm versions: http://jsfiddle.net/ZHKBA/157/

The problem still exists here.

tbosch commented 11 years ago

The difference between IE9 and modern browsers is that IE9 does not support the html5 history api. If the history api is deactivated in angular, this error is reproducible in all browser: http://jsfiddle.net/h4Mgq/2/

tbosch commented 11 years ago

This bug is reproducible with plain angular, without jquery mobile and the adapter: http://jsfiddle.net/ZHKBA/160/

tbosch commented 11 years ago

There is an open bug in angular that seems to match: https://github.com/angular/angular.js/issues/1417

tbosch commented 11 years ago

Hi, could you explain in more detail with an example why the <base href="/"> is needed? Maybe there is another way...

Thanks, Tobias

JGerke commented 11 years ago

Hi Tobias,

the mobile shop has different pages. Sometimes I use a <a href to go to the next page and sometimes I use $location.path

Say my loginpage is the following: http://myServer.com/shop/pages/login/login.html

and my searchmask http://myServer.com/shop/pages/search/searchmask.html

ignoring on which page I am and in which folder I am (Search or Basket or anything else) I want to go to the searchmask via Javascript with this call: $location.path("/shop/pages/search/searchmask.html")

In my opinion relative paths would not work because it would be different for each folder-hirarchie. That is why I want to start each path-call with "/shop/page/"

If I set the base-tag to "/" it works. but if I don't set the base-tag the $location.path doesn't work because the url looks like "http://myServer.com/shop/pages/login/shop/pages/search/searchmask.html" instead of "http://myServer.com/shop/pages/search/searchmask.html" I didn't find a way to tell $location that this is an absolute path to the server.

For the call via a-tag everything is fine. The path "/shop/pages/search/searchmask.html" works without problem.

I hope you understand what I mean.

Here is a jsFiddle: http://jsfiddle.net/nMT6Q/27/show/

the a-tag works, Javascript doesn't.

Thanks, Janine

tbosch commented 11 years ago

Hello Janine, ok, now I understand. Some details about $location are important:

  1. jqm always inserts a base tag with the href of the current document. I.e. if you don't insert one by yourself, a page at http://myServer.com/shop/pages/login/login.html gets a <base href="http://myServer.com/shop/pages/login/login.html"> automatically.
  2. $location treats / always relative to the base tag. So if you set $location.url('/shop...') you end up with a url of /shop/pages/login/shop due to the base url.

A good solution would be to create a service like the one below to redirect to pages that do not belong to the same page now to a jqm subpage of the current page. Then you don't have to change the <base> tag any more.

    mod.factory('externalRedirect', ['$window', function($window) {
        return function(href) {
            $window.location.href = href;
        };
    }]);

Usage (e.g. in login.html): externalRedirect('/shop/pages/search/searchmask.html');

Note: By using $window and not window directly you can still unit test this.

Hope this helps, Tobias

JGerke commented 11 years ago

Hello Tobias,

thanks for the example. I will try this and give you feedback.

Janine

JGerke commented 11 years ago

Hi Tobias,

this works, thank you =)

Janine

tbosch commented 11 years ago

Closing this, as the bug is contained in angular, and there is a workaround.

JGerke commented 11 years ago

Hi Tobias,

unfortunately I have another problem with the workaround concerning the communication between two pages.

In my current version I use the following events on each page: ngm-pagebeforeshow="onActivate()" ngm-pagebeforehide="onPassivate()"

and in this methods I'll do the communication.

But with $window.location.href the "onPassivate" Event is never called. A workaround would be to call it myself before doing "$window.location.href" but the new page is called inital with a full pagereload everytime so that all variables are initial instead of having the old data from last pagecall.

Then I tried ngm-shared-controller This works fine with $.mobile.changePage (which shouldn't be used directly concerning the documentation) but it doesn't work with $window either (because of the full page reload).

Is there another way to do the communication?

Why do I have so many trouble with this? Am I doing something total wrong or different to the documentation?? Or is it absolutely necessary to use routing in any case? I don't know much about this, that is why I didn't use it yet.

Here is a jsFiddle: http://jsfiddle.net/nMT6Q/41/show (In my project href is working, too concerning shared Controllers.)

Thanks and BR, Janine

tbosch commented 11 years ago

Hi, there was a misunderstanding: Yes, I though you wanted to reload the whole page for a kind of redirect to another app. With this way, the only way of getting data to the other app is by passing them via url parameters, and then use routes or read $location in the other app.

So, is this one big app, or do you want to jump from one app to the other app?

If it's one big app, your only workaround is to setup a url mapping in your webserver, that will give the following folder layout:

Tobias

JGerke commented 11 years ago

Hi Tobias,

it is one big app.

But we decided to wait for angular to fix the bug or to look for other frameworks to work with. This workarounds take too much time and if the one thing is working there is another problem at a different point.

Thanks for you help =)

BR, Janine

tbosch commented 11 years ago

Your welcome!