johnpapa / angular-tour-of-heroes

Angular - Tour of Heroes - The Next Step after Getting Started
Apache License 2.0
826 stars 1.45k forks source link

TOH Tutorial - getHeroesSlowly not working in IE11 #41

Closed MichaelChambers closed 7 years ago

MichaelChambers commented 8 years ago

I'm very happy following the tutorial and learning Angular2. Thanks!!

I got to the bottom of the latest chapter and created my getHeroesSlowly method, but the heroes list wouldn't show up in IE11. I tried refreshing and pasting the URL into a new IE11 to no avail. I tried the URL in Chrome, and it worked fine. Note that for IE11, I have the <script src="node_modules/es6-shim/es6-shim.js"></script> and my package.json has "es6-promise": "^3.0.2", "es6-shim": "^0.33.3",

Also, I got the getHeroesSlowly to work in IE11 once with a 100 milli delay instead. But I'm not sure if I did something magical as I haven't been able to recreate that.

Note that in MS Code, the Typescript wasn't happy with getHeroesSlowly. I didn't know what to do, but searched online and found that I had to change it to return new Promise<Hero[]>... and then import {Hero}... getHeroesSlowly(){ return new Promise<Hero[]>(resolve => setTimeout(()=>resolve(HEROES), 2000) //2 seconds ); } I'm guessing the above is probably because I switched to noImplicitAny=true

wardbell commented 8 years ago

That's the pioneer spirit! Thanks for taking a few arrows for us!

I wish you had a repro on the getHeroesSlowly. I have noImplicitAny=true and it's happy.

It's also returning the promise.

  getHeroesSlowly() {
    return new Promise(resolve =>
      setTimeout(()=>resolve(HEROES), 2000) // 2 seconds
    );
  }

Just tried it in plunker on line 47 of app.component.ts and it worked like a charm.

As for IE11, some people report that older browsers need to load the ES6 Promise shim in the index.html. It's harmless to do so if you don't need it and we are likely to go back and put it in everywhere. Try it just above the polyfills script tag

    <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.34.0/es6-shim.js"></script>
MichaelChambers commented 8 years ago

Thanks. In your plunk, I first added the shim line IE11 worked fine (as it also does in my local). Then I changed the app to call getHeroesSlowly instead, and it is behaving the same as my local - the heroes are NOT showing up - at least not in my IE11. In Chrome and Firefox, they show up fine after the 2 second delay. This plunk just has the es6 shim added to index.html, and the app.component.ts line 47 change: http://plnkr.co/edit/MqhJfsBfY94tpxnWfmGo?p=preview

MichaelChambers commented 8 years ago

Regarding the Typescript, I'm completely new to this, so I could be doing something wrong. VS Code (0.10.5) doesn't show an error in the hero.service.ts file. When hovering over the Promise in getHeroesSlowly, it has a hover tip: Creates a new Promise. var Promise: new PromiseConstructor<{}>(executor: resolve: (value?: {} | PromiseLike<{}>)... The TypeScript unhappiness in my VS Code is in app.component.ts. When I change line 47 to call getHeroesSlowly, I get a red squiggle line under the this.heroes. Hover tip is: Type '{}' is not assignable to type 'Hero[]'... (property) AppComponent.heroes: Hero[]

If I hover over getHeroesSlowly() or then( in this._heroService.getHeroesSlowly().then( I get: (method) HeroService.getHeroesSlowly(): Promise<{}> and then( also shows a lot of PromiseLike<{}>

To make the red squiggle in app.component.ts go away, I just change line 13 in hero.service.ts to be return new Promise<Hero[]>(resolve =>

That makes the hover tip over that Promise change to include: var Promise: new PromiseConstructor<Hero[]>(executor: (value?: Hero[] | PromiseLike<Hero[]>)... which is similar to what hovering over the Promise in getHeroes() shows.

And in app.components.ts, hovering over getHeroesSlowly() now gives (method) HeroService.getHeroesSlowly(): Promise<Hero[]>

wardbell commented 8 years ago

I don't have IE11 which is not an excuse, just a report. We should find out what's wrong.

You are helping. You can help a bit more by drilling behind the scenes. When you launch the developer tools (F12), do you see an error? Can you breakpoint to see if it is going into the timeout, coming out of the timeout?

wardbell commented 8 years ago

You are absolutely right about the typing issue and your fix is a good one. I'll make it to the angular.io source and it should show up soon-ish. John can fix it here too.

MichaelChambers commented 8 years ago

Thanks Ward. I'm glad I was on the right track with the TypeScript. About the IE11 issue, I tried the breakpoint debugging, but didn't notice anything interesting, other than that I often couldn't see the source, so was blindly stepping in/over/out while looking at the stack trace.

So that didn't work, but I have something that may help. I updated the plunk at http://plnkr.co/edit/MqhJfsBfY94tpxnWfmGo?p=preview Changes are in app.component.ts at the call to getHeroesSlowly. The console now logs: about to call getHeroesSlowly at Tue Dec 22 2015 20:40:31 GMT-0500 (Eastern Standard Time) Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode. fulfillment at Tue Dec 22 2015 20:40:33 GMT-0500 (Eastern Standard Time) heroes=[{"id":11,"name":"Mr. Nice"},{"id":12,"name":"Narco"},{"id":13,"name":"Bombasto"},{"id":14,"name":"Celeritas"},{"id":15,"name":"Magneta"},{"id":16,"name":"RubberMan"},{"id":17,"name":"Dynama"},{"id":18,"name":"Dr IQ"},{"id":19,"name":"Magma"},{"id":20,"name":"Tornado"}]

So the fulfillment is happening 2 seconds later, and the data is there. But then it isn't doing something right with the Angular property. Maybe that's just due to my trying to use self.heroes=heroes instead, but I'm not sure what else to try.

Is there a refresh command I can try, to see if it will update things after the self.heroes=heroes; ?

-Michael

MichaelChambers commented 8 years ago

Oh, I got it to show up with the delay! I had to use NgZone to do it, but the heroes now show up after 2 seconds - http://plnkr.co/edit/7zs004cRaz4ebfDZz5nN?p=preview

So probably not the way it ought to work. Maybe needing NgZone is just an artifact from my using self.heroes=heroes instead of a this.heroes=heroes.

johnpapa commented 8 years ago

I ran it with this modification, and it used the 2 second delay.

  getHeroes() {
    //var self = this;
    console.log('about to call getHeroesSlowly at '+new Date());
    this._heroService.getHeroesSlowly()
      .then(heroes => {
        console.log('fulfillment at '+new Date()+' heroes='+JSON.stringify(heroes))
        this.heroes = heroes;
      });
      /*
        function(heroes:Hero[]){
          console.log('fulfillment at '+new Date()+' heroes='+JSON.stringify(heroes))
          self.heroes=heroes;
          self._ngZone.run(() => {console.log('Outside Done!')});
        });
        */
  }
MichaelChambers commented 8 years ago

Thanks John for the better syntax for the promise! Sorry, they're new to me too. I updated the plunk with your syntax, but the heroes still don't show up for me in my IE11 unless I uncomment the this._ngZone.run(... http://plnkr.co/edit/7zs004cRaz4ebfDZz5nN?p=preview

johnpapa commented 8 years ago

Hmmm ... must be an IE11 thing ... its working here on chrome and firefox for me.

MichaelChambers commented 8 years ago

Yeah, the original was working fine for me in Chrome and Firefox too. Just has a problem in IE11. That the ngZone.run does something useful seems to indicate the data is right but Angular isn't picking up the change automatically. And apparently it was the arrow function syntax that I wasn't able to figure out. Now that I've found out what it is, I like how it allows "this" to be the object I wanted. :)

...Oh, and you even added that info to the docs too, perhaps after seeing I was clueless on how to handle it correctly. :) Great!

wardbell commented 8 years ago

This will be great to share with the team. If you need zone, something is amiss.

MichaelChambers commented 8 years ago

I don't know if it's related, but I'm having IE11 problems with other examples too. I'm sure it isn't most appropriate to mention it here, but I'm not sure where to do so. For the Routing, I updated the plunk with the es6 shim - http://plnkr.co/edit/IedH4JQg45z6pP92VvY1?p=preview Just like this one, it works fine in Chrome. But in IE11, I have to click 3 times to switch and show the other top level route: (It loads with neither Crises Center nor Heroes selected) First Click on Dashboard Heroes - I get the HEROES title below but no list Second Click on Dashboard Heroes - the Heroes dashboard button blue background/white text styling shows up Third Click on Dashboard Heroes - the Heroes list shows up. Same 3 clicks to get the Crises Center list. And I can't get to either detail page, because the list goes away on the first click, and I guess it needs more.

I also set up the example locally, and I found that after any first click which changed the URL, I could press F5 refresh to get the page to show correctly.

pegan23 commented 8 years ago

I have the same issue with IE11 .. the code works fine in Chrome, but the view is not updated in IE11 after resolving the Promise on getHeroesSlowly(). The promise resolves, the console.log() executes, indicating the fulfilment has been met, but the view is not updated at: this.heroes = heroes;

adding the _ngZone.run(...) call also fixes the issue for me on IE11

MichaelChambers commented 8 years ago

Thanks @pegan23 for confirming!

claurin commented 8 years ago

IE11 bug for me too. (no list). Fine in evergreens.

HEROES is undefined for me on line 3 using IE11 devtools.

1: getHeroesSlowly() { 2: return new Promise<Hero[]>(resolve => 3: setTimeout(()=>resolve( HEROES ), 2000) // 2 seconds 4: ); 5: }

claurin commented 8 years ago

Setting a stop in IE11 devtools on:

setTimeout(()=>resolve( HEROES ), 2000)

and then hitting continue allows time for HEROES to be defined and render in the component.

GregWoods commented 8 years ago

Same for me. Very simple plunker shows it working in Chrome and IE11 until I put the setTimeout in place. Then it only works in Chrome. So the promise is working fine, but changing the property doesn't change the view - the binding part appears to be broken. http://plnkr.co/edit/ROnn9GBtgJeL6k7jijOY?p=preview IE Developer Tools reports no errors

In this example, {{name}} is updated with 'Fred', but not updated with 'Ginger' In Chrome, both updates work

    //works in IE11 and Chrome
    new Promise(resolve => {
      resolve("Fred")
    })
    .then(r => {
      this.name = r
    })

    //Doesn't work in IE11
    new Promise(resolve => {
      setTimeout(function() {
        resolve("Ginger")  
      }, 3000)
    })
    .then(r => {
      this.name = r
      alert(r + ' updated')
    })  
GregWoods commented 8 years ago

Adding _ngZone.run(...) works for my code too in IE11. Looks like an angular bug to me, but thanks @MichaelChambers .... I can get on with my life

MichaelChambers commented 8 years ago

@GregWoods - you're welcome. May that life be good and fruitful!

johnpapa commented 7 years ago

closing since this was rewritten with the CLI