danielsogl / awesome-cordova-plugins

Native features for mobile apps built with Cordova/PhoneGap and open web technologies. Complete with TypeScript support.
https://danielsogl.gitbook.io/awesome-cordova-plugins/
Other
2.41k stars 2.42k forks source link

Google Maps: marker.getPosition() returns undefined #1577

Closed hayuki closed 7 years ago

hayuki commented 7 years ago

I'm submitting a ... (check one with "x") [ x ] bug report [ ] feature request

Current behavior: When a marker is added to the map, then dragged to a different position, and the marker.getPosition() method is called, instead of returning a Promise<LatLng> it returns undefined. And I cannot see any other way to get the moved marker's new location. I looked through the codebase here on GitHub and I see that getPosition() isn't really implemented, it only has return; in the method body. Am I missing something?

Expected behavior: marker.getPosition() should always return a Promise<LatLng>

Steps to reproduce: Create a map, add a draggable marker. Add a MARKER_DRAG_END event on it, and in the success callback of the subscribe() call marker.getPosition()

Related code:

marker.addEventListener(GoogleMapsEvent.MARKER_DRAG_END).subscribe((marker: Marker) => {
      console.log("Marker dragged. Position:");
      console.log(marker.getPosition()); /* prints out undefined */

      // marker.getPosition().then((position: LatLng) => { /* throws an exception saying 'can't find method "then" of undefined' */
      //   this.onLocationSelected.emit(position);
      // });
    })

package.json info:

"dependencies": {
    "@angular/animations": "4.0.2",
    "@angular/common": "4.0.2",
    "@angular/compiler": "4.0.2",
    "@angular/compiler-cli": "4.0.2",
    "@angular/core": "4.0.2",
    "@angular/forms": "4.0.2",
    "@angular/http": "4.0.2",
    "@angular/platform-browser": "4.0.2",
    "@angular/platform-browser-dynamic": "4.0.2",
    "@ionic-native/app-version": "3.8.0",
    "@ionic-native/camera": "3.8.0",
    "@ionic-native/core": "3.8.0",
    "@ionic-native/device": "3.8.0",
    "@ionic-native/google-maps": "3.8.0",
    "@ionic-native/in-app-browser": "3.8.0",
    "@ionic-native/keyboard": "3.8.0",
    "@ionic-native/splash-screen": "3.8.0",
    "@ionic-native/status-bar": "3.8.0",
    "@ionic-native/toast": "3.8.0",
    "@ionic/storage": "2.0.1",
    "animate.css": "3.5.2",
    "core-js": "2.4.1",
    "crypto-js": "3.1.9-1",
    "feature-toggles": "1.4.0",
    "highcharts": "5.0.9",
    "intl": "1.2.5",
    "ionic-angular": "3.1.0",
    "ionicons": "3.0.0",
    "lodash": "4.17.4",
    "moment": "2.18.0",
    "momicons": "0.0.13",
    "ng2-translate": "^5.0.0",
    "rxjs": "5.1.1",
    "sw-toolbox": "3.4.0",
    "zone.js": "0.8.5"
  },
  "devDependencies": {
    "@angular/language-service": "4.0.2",
    "@ionic/app-scripts": "1.3.6",
    "@types/crypto-js": "^3.1.32",
    "@types/jasmine": "2.5.37",
    "@types/node": "^7.0.12",
    "angular2-template-loader": "^0.6.0",
    "awesome-typescript-loader": "^3.1.2",
    "concurrently": "^3.1.0",
    "css-loader": "^0.28.0",
    "fs-extra": "^2.0.0",
    "glob": "^7.1.1",
    "istanbul-instrumenter-loader": "2.0.0",
    "jasmine-core": "^2.5.2",
    "jasmine-spec-reporter": "^3.2.0",
    "json-loader": "^0.5.4",
    "karma": "^1.2.0",
    "karma-chrome-launcher": "^2.0.0",
    "karma-coverage": "^1.1.1",
    "karma-jasmine": "^1.0.2",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-remap-coverage": "^0.1.1",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "^2.0.2",
    "phantomjs-prebuilt": "^2.1.13",
    "plist": "^2.0.1",
    "raw-loader": "0.5.1",
    "replace-in-file": "^2.3.2",
    "source-map-loader": "^0.2.1",
    "string-replace-loader": "^1.0.5",
    "stubby": "^4.0.0",
    "to-string-loader": "^1.1.4",
    "ts-helpers": "^1.1.1",
    "ts-loader": "^2.0.3",
    "ts-node": "^3.0.2",
    "tslint": "^5.0.0",
    "tslint-loader": "^3.5.2",
    "typedoc": "^0.5.1",
    "typescript": "2.2.1",
    "webpack": "2.2.1"
  }
hayuki commented 7 years ago

There is another way to get the marker's position - you need to call marker.get('position') which will retrieve the position you set on the marker through MarkerOptions. However, that value does not change as the marker is dragged around, so it serves no purpose if you want to capture the marker's new position after it's been dragged somewhere.

ihadeed commented 7 years ago

marker.getPosition() is an async method that returns a promise that resolves with a GoogleMapLatLng object.

hayuki commented 7 years ago

@ihadeed I understand that, but what happens is, if I use it as expected - marker.getPosition().then((latlng) => { ... }); I get an error that says "could not find method 'then' of undefined". I think the promise never resolves.

ihadeed commented 7 years ago

@hayuki I will try to reproduce this issue now and figure out what the problem is.

ihadeed commented 7 years ago

Ok, now I see what's wrong here.

This is wrong:

marker.on(GoogleMapsEvent.MARKER_DRAG_END).subscribe((marker: Marker) => { ... })

When the marker emits the event, it doesn't return back an object typeof Marker. It returns back the original Marker object from the actual plugin and not from Ionic Native. So instead of the above, you need to do this:

marker.on(GoogleMapsEvent.MARKER_DRAG_END).subscribe(() => { ... })

This will make marker refer to the original marker variable that you had defined earlier (which was produced by Ionic Native.

The signature for marker.getPosition on the original object is getPosition(callback) and it doesn't return anything (it returns the LatLng object through the callback).


For reference, the code was tested here: https://github.com/ihadeed/ionic-native-playground/blob/ionic-native-1577/src/pages/google-maps/google-maps.ts#L17-L29

hayuki commented 7 years ago

I did what you said and now it works perfectly, thank you! :)

Final working code:

private setUpDraggableMarker(marker: Marker) {
    marker.on(GoogleMapsEvent.MARKER_DRAG_END).subscribe(() => {

      marker.getPosition().then((pos: LatLng) => {
        this.onLocationSelected.emit(pos); /* changes as expected */
        this.map.animateCamera({target: pos, zoom: this.defaultZoom, duration: 8});
      });

    })
  }
nagababu7 commented 7 years ago

I got same error.I did what u said.But not solved this type of error.My code is like this.

this.map.on(GoogleMapsEvent.MY_LOCATION_BUTTON_CLICK).subscribe((map: GoogleMap) => {

    if (this.isViewLoaded) {

      this.map.getCameraPosition().then((camera: CameraPosition) => {

        let target: LatLng = <LatLng> camera.target;
        this.marker.setPosition(target);
      });
    }

  });
Domingos-Masta commented 6 years ago

On my case error is : Property 'then' does not exist on type 'CameraPosition'.

my code :
this.map.on(GoogleMapsEvent.MY_LOCATION_BUTTON_CLICK).subscribe(() => {

    if (this.isViewLoaded) {

      this.map.getCameraPosition().then((camera) => {

        let target: LatLng = <LatLng>camera.target;
        this.marker.setPosition(target);
      });
    }

  });
wf9a5m75 commented 6 years ago
camera = this.map.getCameraPosition();