mjaric / ng2-heremaps

Here maps for Angular 2, 4, 5
MIT License
6 stars 12 forks source link

Map gets destroyed after calling map.getViewPort().resize() #4

Closed elvirusHDS closed 6 years ago

elvirusHDS commented 6 years ago

Hello Milan, hello guys,

Project: Displaying map data in an Angular 6 project I have a problem here and I really don't know, where to look for the solution: I am displaying a here map and everything is working quite well. I want the map to resize whenever the outer container grows or shrinks. So, according to the docs, I have to call map.getViewPort().resize() for this functionality. (see here developer docs: map-viewport-resize)

I call the function in my MapComponent like so:

this.hereMapsManager.getMap('fh.here-maps-0').then((map) => {
  map.getViewPort().resize();
});

This is working, the map gets resized accordingly. But, when I navigate to another page via the angular router and then navigate back, the map cannot be initialized anymore. This does not happen if .resize() is not called prior.

Error Message:

Error: Uncaught (in promise): InvalidArgumentError: H.map.DataModel#add (Argument #0 [object Object]) Error at new C (https://js.api.here.com/v3/3.0/mapsjs-core.js:11:460) at B (https://js.api.here.com/v3/3.0/mapsjs-core.js:7:55) at Di.add (https://js.api.here.com/v3/3.0/mapsjs-core.js:180:380) at new Q (https://js.api.here.com/v3/3.0/mapsjs-core.js:300:269) at https://localhost:5001/vendor.js:143922:40 at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (https://localhost:5001/polyfills.js:2741:26) at Object.onInvoke (https://localhost:5001/vendor.js:58219:33) at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (https://localhost:5001/polyfills.js:2740:32) at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (https://localhost:5001/polyfills.js:2491:43) at https://localhost:5001/polyfills.js:3225:34

Do you have any ideas?

jedsmith13 commented 6 years ago

So it looks like there is an issue with the code. I will create a pull request for this.

It is actually related to the loader being called when you run the getMap command, it isn't actually related the resize function.

So while we are waiting for the pull-request and for npm to be updated. There is a fairly easy workaround, if you don't mind violating TypeScript privacy settings of variables temporarily.

Instead of:

this.hereMapsManager.getMap('fh.here-maps-0').then((map) => {
  map.getViewPort().resize();
});

try:

this.hereMapsManager._maps.get('fh.here-maps-0').getViewPort().resize();
mjaric commented 6 years ago

Fixed, v0.2.2 Please give it a try and let us know if it works now.

Thanks

elvirusHDS commented 6 years ago

Works like a charm.

elvirusHDS commented 6 years ago

Hi guys,

sorry I have to reopen this issue. At first, it seems to be working now but unfortunately it is not.

Here is a screenshot of my application: image What I am basically doing is the following: There is a sidebar-button and when this is clicked and the sidebar opens, I want the map to resize accordingly. This works. Whenever I click one of the menu items on the left and navigate via router to another page and return back to the map, resizing does not work anymore. The error is: After calling this.hereMapsManager.getMap('fh.here-maps-0'), the returned map is undefined. And also, I have the impression that there are two instances of the map somehow because I always end up hitting the breakpoint twice. This is not the case when resize is working!

I appreciate any help from you guys!

Best regards, elvirus

jedsmith13 commented 6 years ago

That does sound like an error from loading the map twice. The problem before was that the map was being loaded twice in the module causing it to load some stuff into one map and the rest into the other which broke everything. However, that shouldn't be the case after the last fix. Are you doing anything at the component level that might be loading the map twice?

Do you have some code examples you could share, maybe a git repo, a plunker, or stackblitz where we could see the error? I am not sure how you are running into the error. I would love to help but I am busy the next couple of days but if I had an easy way to reproduce it I could squeeze in some time to take a look, but I don't have the potential hours it could take to find a bug.

mjaric commented 6 years ago

@elvirusHDS Is there any code of yours that is accessing the here map object outside promise "then" callback?

Would be really good if we can have example that can reproduce issue, otherwise it will be endless guessing.

mjaric commented 6 years ago

@elvirusHDS I just realized what did you do. Please don't use mapManager to get map by name since it is for internal use only. Every time you destroy maps host component (by navigating or ng-if condition change ...) map will be destroyed, and we internally need that map name so manager can dispose properly previously instantiated map, it's kind of reference counter.

Instead, use @ViewChild(MapComponent) private mapComponent and then call this.mapComponent.getMap().then(map => {.... do something with map...})

elvirusHDS commented 6 years ago

Hey Milan,

thank you so much! I was not aware of the fact that HereMapsManager is just internal! With the way you provided, everything is working well now!

In one place I am using

this.heremapsManager.onApiLoad().then((platform: H.service.Platform) => {
... new H.map.Icon(...)
}

Is this ok? I cannot instantiate an Icon too early because Angular needs some time before "H" is known, else I get a reference error. How should I do it the right way?

Thank you

jedsmith13 commented 6 years ago

I am using custom icons as well. The marker component actually has an input for an icon.

Here is how I do it: Component

  attractionIcon = `<svg> ... </svg>`;

HTML:

<here-map-marker *ngFor="let attraction of attractions" [icon]="attractionIcon" [position]="attraction.coordinates" (click)="openBubble(attraction)"></here-map-marker>

In the component I am loading an SVG because that is what I have. The input checks for either a string or an actual H.map.Icon.

You could use the suggestion above about the viewcomponent to get the map if you want to custom build the Icon.

It isn't documented yet but if you want to put something together I am sure Milan would appreciate it.

elvirusHDS commented 6 years ago

I see. That's actually nice but what is with the rest of an icon's definition, like anchor and size?

So the thing is, the types from heremaps (like H) are not immediately available. What is the official way to assert that the types are available at runtime? The only thing I found was working for me is

this.heremapsManager.onApiLoad().then((platform: H.service.Platform) => {
... new H.map.Icon(...)
}

or just wait a little time...

mjaric commented 6 years ago

Hi @elvirusHDS ,

Yes, that is the only way to ensure heremaps api is properly loaded and available to call.

elvirusHDS commented 6 years ago

Thank you!

CU later... ;-)