angular-ui / angular-google-maps

AngularJS directives for the Google Maps Javascript API
http://angular-ui.github.io/angular-google-maps
2.52k stars 1.07k forks source link

ng-click within windows #356

Closed MauritzKruger closed 10 years ago

MauritzKruger commented 10 years ago

Good day Nicolas

I would like to know how I can use a controller function within the windows directive, tried code as mentioned for window, but did not work.

My markers change depending on search criteria and this is working as my markers increase/decrease depending on the criteria, and each markers info window is correct as well, just the click event that is not working.

My code: HTML: <google-map center="mapObjects.center" zoom="mapObjects.zoom" draggable="true" options="mapObjects.options" control="mapObjects.control"> <markers ng-if="mapObjects.markers.length > 0" models="mapObjects.markers" coords="'self'" icon="'icon'" click="'onClicked'" labelContent="'title'" labelAnchor="22 0" fit="true"> <windows show="'showWindow'" closeClick="'closeClick'" options="mapObjects.windowOptions" ng-cloak> <p ng-controller="InfoWindowController"> Borehole Name: {{windowInfo.boreholeName}}<br/> Area: {{windowInfo.area}}<br/> Sub Area: {{windowInfo.subArea}}<br/> <a ng-click="viewDetails(windowInfo)"></a> </p> </windows> </markers> </google-map>

JavaScript: angular.module( 'globalApp') .controller( 'InfoWindowController', function( $scope, $location ) { $scope.viewDetails= function() { console.log('GOES INTO FUNCTION'); // Does not get here } });

dgavigan commented 10 years ago

First, I would recommend using the single <window></window> directive. I think the <windows></windows> directive will be deprecated soon.

A fix was just released that could help your situation: #333 which would allow you to define a function on your current controller for the page, not the infoWindowController. However, if this doesn't work, you could also define your viewDetails() on the object itself as I had done, which was the only way until the recent fix.

If you still needed a controller on the info window itself, I would use the templateUrl as in my example, then in that template, you could specify your infoWindowController within the root div.

I implemented this in the following way:

  1. Define your onClick function on each object. My getDetails simply takes in an ID from the marker, and passes this info into a selectedItem service.
  2. I have a controller for the info window. This controller takes the currently selected ID from the selectedItem service and makes a call to get the details for the given ID and sets the window variables with the appropriate data.
<google-map center="map.center" zoom="map.zoom"
           draggable='true'>

           <markers models='components'
                           coords="'self'"
                           doCluster='true'
                           click="'getDetails'">
           </markers>

           <window coords="windowCoords"
                         show="displayWindow"
                         templateUrl="'views/info-window.html'"
                         templateParameter="componentDetails">
             </window>
</google-map> 

Hope this helps!

nmccready commented 10 years ago

As for the deprecation I have been going back k and forth on that. One huge reason to possibly keep the windows directive is it is the current only stylable thing. Ie: the window could be used as a styled marker in itself. Where as markers are only .pngs.

phaeton2040 commented 10 years ago

Hi! I also have this problem and I tried studying your example at https://github.com/nlaplante/angular-google-maps/blob/master/example/issue-157-ng-click.html But it's still not working. I made a plunker to illustrate my problem - http://plnkr.co/edit/3RKNmz It is almost the same as the example, but it doesn't work. Appreciate any help

VikasGarg333 commented 10 years ago

Here is a workaround to the above problem:

You can invoke ng-click handler function from inside the info window by using $parent service like this:

examplegooglemap

cthrax commented 10 years ago

Trying to clean up issues, if this still exists, please re-open with a plnkr demonstrating the issue.

justinbc820 commented 10 years ago

The solution by VikasGarg333 worked like a charm for me. Just add $parent before the function call in your html, and it will call the function on the scope. Not sure why this is an issue, but the $parent thing solved it. Thank you

ovidiucp commented 10 years ago

I want to be able to invoke a function from within the ng-click of an a element.

None of the solutions described above work for me when I use ui-gmap-windows instead of ui-gmap-window.

I tried the solution proposed by @dg1202, like this:

main.html

    <ui-gmap-google-map
       center="model.mapInfo.center"
       zoom="model.mapInfo.zoom"
       draggable="true"
       options="model.mapOptions"
       control="model.mapControl"
       bounds="model.mapBounds"
       >
      <ui-gmap-markers models="model.mapMarkers"
                       idkey="'identifier'"
                       coords="'centroid'"
                       icon="'icon'"
                       click="onMarkerClicked"
                       doCluster="true"
                       >

        <ui-gmap-windows show="'showWindow'"
                         templateUrl="templateUrl"
                         ng-cloak>
        </ui-gmap-windows>
      </ui-gmap-markers>
    </ui-gmap-google-map>

main.js

function InfoController($scope, $log) {
  $scope.value = 'InfoController value';
  console.log('InfoController instantiated');
};

angular.module('app')
.controller("MainCtrl", function($scope) {
    $scope.templateUrl = 'views/info.html';

    $scope.onMarkerClicked = function ($markerModel) {
      var marker = $markerModel.model;
      console.log('onMarkerClicked', marker);
      marker.showWindow = true;

      $scope.$apply();
    };
});

info.html

<div ng-controller="InfoController">
  <div ng-cloak>
    Template specific: {{value}}
  </div>
</div>

The onMarkerClicked method gets invoked, but an info window is never shown. I was not able to find any example in the source code that uses ui-gmap-windows with templateUrl, so maybe this is a bug.

The solution proposed by @VikasGarg333 doesn't work either. The viewDetails function is not invoked when it's declared inside the scope of MainCtrl. Here's the code.

main.html

        <ui-gmap-windows show="'showWindow'"
                         ng-cloak>
          <div ng-non-bindable>
            <a ng-click="$parent.viewDetails()">{{nameForMarker()}}</a>
          </div>
        </ui-gmap-windows>

main.js is the same as above, except for the new viewDetails function defined within the scope:

$scope.viewDetails = function() {
  console.log('viewDetails');
};

Any thoughts on how to solve this would be greatly appreciated.

ovidiucp commented 10 years ago

It looks like ui-gmap-windows has a problem. I modified my code to make use of ui-map-window instead, moved it outside the ui-gmap-markers element, and the ng-click works as expected. I'm using templateUrl and templateParameter to describe the InfoWindow in a separate template too, so I'm pretty happy.

The only piece of magic is that the value of the templateParameter is available to the template's controller as $scope.parameter.

alexanderfrey commented 9 years ago

I stumbled upon the same issue within ui-gmap-window . Does someone have an working example or did it already

nmccready commented 9 years ago

It does exist in example.js basically you need to use it with a template where it has a dedicated controller.

alexbonhomme commented 9 years ago

An other way to get access to the parent controller functions is to put a reference to the $scope in the parameter object.

main.js

$scope.map = {
    center: {
        latitude: 50.6278,
        longitude: 3.0583
    },
    zoom: 12,
    markersEvents: {
        click: function(marker, eventName, model) {
            if ($scope.map.window.model != model) {
                $scope.map.window.model = model;

                $scope.map.window.options.visible = true;
            }
            // toggle show/hide
            else {
                $scope.map.window.options.visible = !$scope.map.window.options.visible;
            }
        }
    },
    window: {
        model: {},
        closeClick: function() {
            $scope.map.window.options.visible = false;
        },
        options: {
            visible: false,
            maxWidth: 350
        },
        parent: $scope
    }
};

main.html

<ui-gmap-google-map center="map.center" zoom="map.zoom">
    <ui-gmap-window coords="map.window.model" options="map.window.options" closeClick="map.window.closeClick()" templateUrl="template.html'" templateParameter="map.window"></ui-gmap-window>
    <ui-gmap-markers idKey="'pid'" models="pois" coords="'self'" events="map.markersEvents" onClick="map.window.onClick()"></ui-gmap-markers>
</ui-gmap-google-map>

template.html

<div class="no-padding">
    <button ng-click="parameter.parent.delete(parameter.model)">Delete</button>
</div>
vgrem commented 9 years ago

Hello, recently i stumbled upon the same issue, the following solution worked for me:

First we need to introduce an additional controller:

appMaps.controller('infoWindowCtrl', function($scope) {
   $scope.showInfo = function() {
      console.log('Button clicked!');
  }
});

and then specify the following layout:

<ui-gmap-windows show="show">
  <div ng-controller="infoWindowCtrl">
      <span ng-non-bindable>{{title}}</span>
      <button ng-click="showInfo()">Show info</button>
  </div>
</ui-gmap-windows>

The same solution has been posted in Stack Overlow

Working example

ecbrodie commented 9 years ago

$parent trick worked like a charm for me too! This seemed to be needed for any Angular attribute referencing a scope variable, such as ng-submit, ng-click and ng-model. Parsing of Angular placeholders (between double curly braces) seemed to be able to reference the scope variables, though.

On previous elements that I needed to parse attributes from scope variables, I found myself needing to create an Angular controller just for the window elements. I would then have to write glue code to pass data between my app's main controller and the nested controller for my window. This $parent solution was so much easier for me to use because I didn't have to introduce the new controller.

My main question is why exactly the $parent trick is needed. Is it because the code rendered from the template is somehow on a detached controller? Or something else specific?

vargaendre commented 8 years ago

Hi,

I just ran into this issue. I am using angular 1.5.3. with Ionic. I have a ui-gmap-window next to a ui-gmap-markers element. I use templateUrl for the content and it has its own controller. Maybe it makes a difference that I use infobox styling for the infoWindow. None of the followings work: href, ng-href, hrefs with target=_blank, $parent, ng-click. The expressions get evaluated, so parameters turn into values, ng-href generates href attribute etc. I just can't make a single click event to work. This is quite frustrating, since this should be a simple task. Any help is very much appreciated.

vargaendre commented 8 years ago

Okay, I found out, it works if I remove the boxClass: "infobox" from the options. But I really need the customizable looks, how can I solve this issue? Thank you @nmccready Could you please help me?

vargaendre commented 8 years ago

OK, so I figured it out. You need to add enableEventPropagation: true to the options to enable click events. For the record.