Hiding all info windows on click with angular-google-maps - javascript

I am using the angular google maps api defined here:
https://angular-ui.github.io/angular-google-maps/#!/api
I have the following DOM structure
<ui-gmap-markers models="destinationMarkers" coords="'self'" idKey='self.idkey' >
<div ui-gmap-windows models="destinationMarkers" control="infoWindows">
<div ng-non-bindable>
<!-- {{contents}} -->
</div>
</div>
</ui-gmap-markers>
I am trying to make it so that the info window closes when any other part of the map is clicked on, or when another window is opened. The closest I have gotten is calling: scope.infoWindows.getChildWindows() which gives access to the marker objects, however calling the associated hideWindow functions appears to do nothing. Does anyone know how to do this?

I have just come across exactly the same issue and after a little messing around i have a solution (sorry if im a little late to the game)
You must set the controller property on the window like so...
<ui-gmap-window ng-if="m.response" control="googlemap" >
The 'googlemap' control must be a member of the Scope, and 'control' must be defined as an empty object on the map object like so...
$scope.googlemap = {};
$scope.map = {
zoom: 5,
center: getMapCenter(response),
options: {
// draggable: false
},
control: {}
};
Now we can attach an event to the Marker which will enable us to iterate over the list of windows and hide them like so...
markers.push({
id: i,
...
...
events: {
click: function(e){
var windows = $scope.googlemap.getChildWindows();
for (var i = 0; i < windows.length; i++){
windows[i].hideWindow()
}
}
}
});

Related

How to extend Leaflet Icon Class to add data-open attribute to marker HTML?

I'm trying to trigger some functionality based on the click of a marker on a GeoJSON layer in Leaflet. The eventual functionality I'm trying to implement is a flyout, or scroll out type modal populated from the individual feature's JSON attributes. Essentially, I'm trying to implement the functionality in this Tutsplus Tutorial with dynamic feature content based on the marker click.
I THINK I've figured out most of the pieces I need, but I'm struggling with how to add a data attribute, specifically data-open, to the individual marker. Building on an earlier question of mine I've realized it's not enough to just update a DOM element's CSS, but rather my app should be implementing changes based on data attributes to fully get the functionality I want.
From this question I know that this should be done by extending the L.Icon class that Leaflet provides, but the answer is a bit too terse for my current JS skills. I apologize for this effectively being a "ELI5" of a previously asked question, but I'm not sure where the options and slug come into function. I think they're implied by the question, rather than the answer I'm citing and being set on the marker itself.
Here's a simplified version of the the click handler on my markers, which grabs and zooms to location, gets feature info, and populates that info to a div. The zoom functionality works, as does extracting and placing the feature info, but I'm struggling with how to connect the functionality to trigger the modal and place the div with the feature info over the map.
function zoomToFeature(e) {
var latLngs = [e.target.getLatLng()];
var markerBounds = L.latLngBounds(latLngs);
var street = e.target.feature.properties.str_addr;
document.getElementById('street').textContent = street;
mymap.fitBounds(markerBounds);
//where the modal trigger should be
document.getElementById('infoBox').classList.add('is-visible');
}
Here are the event listeners taken from the linked tutorial, which are currently not firing, but I have them working in a standalone implementation:
const openEls = document.querySelectorAll("[data-open]");
const closeEls = document.querySelectorAll("[data-close]");
const isVisible = "is-visible";
//this is the event I want to trigger on marker click
for (const el of openEls) {
el.addEventListener("click", function() {
const modalId = this.dataset.open;
console.log(this);
document.getElementById(modalId).classList.add(isVisible);
});
}
for (const el of closeEls) {
el.addEventListener("click", function() {
this.parentElement.parentElement.parentElement.classList.remove(isVisible);
});
}
document.addEventListener("click", e => {
if (e.target == document.querySelector(".modal.is-visible")) {
document.querySelector(".modal.is-visible").classList.remove(isVisible);
}
});
So, where I'm trying to get is that when my markers are clicked, the trigger the modal to appear over the map. So, I think I'm missing connecting the marker click event with the event that triggers the modal. I think what's missing is adding the data attribute to the markers, or some way chain the events without the data attributes. As there's no direct way to add an attribute to the markers, I try to add slug option on my circle markers:
var circleMarkerOptions = {
radius: 2,
weight: 1,
opacity: 1,
fillOpacity: 0.8,
slug: 'open',
}
and If I read the previously asked question's answer correctly, than extending the Icon Class this way should add a data-open attribute.
L.Icon.DataMarkup = L.Icon.extend({
_setIconStyles: function(img, name) {
L.Icon.prototype._setIconStyles.call(this, img, name);
if (options.slug) {
img.dataset.slug = options.slug;
}
}
});
A stripped down version of my code is here (thanks #ghybs). My full implementation pulls the markers from a PostGIS table. It's a bit hard to see in the Plunker, but this code adds my class to my modal, but doesn't trigger the functionality. It does trigger the visibility if the class is manually updated to modal.is-visible, but the current implementation which renders modal is-visbile doesn't, which I think is because the CSS is interpreted on page load(?) and not in response to the update via the dev tools, while the concatenated css class matches extactly(?). When I do trigger the modal via the dev tools, the close modal listeners don't seem to work, so I'm also missing that piece of the puzzle.
So, it's a work-around to setting the data attribute, but I realized I was shoe-horning a solution where it wasn't needed. Assuming someone ends up with the same mental block. Appropriate listeners on the modal close button and another function passed to the existing marker click listener produce the desired functionality.
const closeM = document.querySelector(".close-modal");
closeM.addEventListener("click", closeMe);
var modal = document.getElementById('infoBox');
and
function modalAction(){
modal.style.display = 'block';
}
function closeMe(){
modal.style.display = 'none';
}

Google Maps not correctly initialising within Angular directive

I am trying to use the Google Maps API to display a map within an Angular site but it appears to not initialise correctly.
My html page uses bootstrap nav nav-tabs and I use an Angular controller to switch between them.
<ul class="nav navbar-nav">
<li ng-class="{ active:myCtrl.isSet('map') }">
<a href ng-click="myCtrl.setTab('map')">Show Map</a>
</li>
</ul>
With one of the tabs containing only the google map canvas element - set up using an angular directive
Module.directive('mapPage', function() {
return {
restrict: 'E',
template: '<div id="map-canvas"></div>'
};
});
Within my angular controller I set up a listener for the window 'load' event to initialise the map as follows:
google.maps.event.addDomListener(window, 'load', myCtrl.initMap);
myCtrl.initMap = function() {
var mapOptions = {
zoom: 12,
center: new google.maps.LatLng(55.937879, -3.241619),
};
myCtrl.map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(55.937879, -3.241619),
map: myCtrl.map
});
myCtrl.map.setCenter(new google.maps.LatLng(55.937879, -3.241619));
}
What I see on screen is the map element showing a grey area with the location marker not centered correctly (it's just off screen).
If I move the map-canvas div to the main section of my index.html page (rather than a sub page within the app) it loads correctly, so I know my Google API js code and html is correct. The map also shows if the page is resized.
It just doesn't work when used on a page that is not rendered immediately. I have tried searching for similar questions/answers but could not find this particular issue.
I have created a simple fiddle that demonstrates the issue.
http://jsfiddle.net/johntough/nc0u7h2c/5/
Any help appreciated!
The issue is, you are loading Map on window load whereas the container will appear on click. Google Map has behavior (never seen documented yet but I have observed it many time though) that if the container is hidden on load, it does not load map in there. I changed your "load" to "click" and its working. The only change is as below,
google.maps.event.addDomListener(window, 'click', myCtrl.initMap);
See fiddle and verify yourself. http://jsfiddle.net/anandgh/nc0u7h2c/6/

Showing a google map in angular-ui modal?

Trying to load a simple google map within an angular-ui modal. However no luck. The data get's passed in fine, but nothing works in terms of the map... Please help.
$modalInstance.opened.then(function() {
var mapOptions = {
center: new google.maps.LatLng(34.834442, -82.3686479),
zoom: 8
};
new google.maps.Map(document.getElementById("eventMap"), mapOptions);
});
Inside the modal html:
<div class="row clearfix">
<div class="col-md-5" id="eventMap" style="display: block; height: 150px;"></div>
</div>
I tried this in the regular page HTML and worked fine...
What am I missing?
Thank you in advance!
You can use angularjs-google-maps; an AngularJS directive for Google maps that is very flexible and powerful and easy to use. I've prepared a working demo for your case:
http://plnkr.co/edit/eEtaGH?p=preview
I hope this helps.
To remove the grayness, according to https://angular-ui.github.io/angular-google-maps/#!/faq:
If rendering starts before elements are full size, google maps calculates according to the smaller size. This is most commonly the case with a hidden element (eg, ng-show). To fix this, use "ng-if" instead, as this will wait to attach to the DOM until the condition is true, which should be after everything has rendered fully.
I've modified your plunker http://plnkr.co/edit/JetUBY?p=preview to remove the grayness.
Controller:
var ModalInstanceCtrl = function ($scope, $modalInstance, lat, lng) {
$scope.render = true;
// code here
}
Template:
<map ng-if="$parent.render" center="[{{$parent.lat}}, {{$parent.lng}}]" zoom-control="true" zoom="8"> </map>
You need to trigger 'resize' event. Follow these lines:
var map = new google.maps.Map(document.getElementById("eventMap"), mapOptions);
google.maps.event.trigger(map, 'resize', function () {
// your callback content
});
I too ran Into a similar situation, where I am loading a map in an angular modal instance. I too searched many places and did't get the correct simple solution for it.
So I gone deeper and found a simple solution for this issue.
The issue is that, the map is trying to get the div from the modal before it gets loaded, and the solution is:
In your controller take a $timeout angular parameter,
function MyController($scope,$cookies,$modal,$window,roomService,$timeout) {
**** after all your model code is defined ****
$modalInstance.opened.then(function() {
function initialize() {
var latlng = new google.maps.LatLng(-34.397, 150.644);
var myOptions = {
zoom: 8,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("eventMap"),
myOptions);
}
$timeout(function() {
initialize()
}, 1000);
});
*** use the time out to make the div load and then call the map ***
}
This time out made the map to load perfectly in the modal. A simple solution.

Get Id of TitlePane programatically defined to show/hide

I am very new to Dojo and this is what I am trying to do. I have a titlepane which is programatically declared using the code below:
var pane = this._createTitlePane(config.widgets.title, config.widgets.position,
config.widgets.open);
_createTitlePane: function (title, position, open, optclass) {
var tp = new TitlePane({
title: title,
open: open
}).placeAt(this.sidebar, position);
domClass.add(tp.domNode, 'titlePaneBottomFix titlePaneRightFix');
if (optclass) {
domClass.add(tp.domNode, optclass);
}
tp.startup();
return tp;
},
Later I am trying to hide this title pane when a button is clicked using esri.hide. My question is how do I get a reference to this title pane? There's no Id when it is defined.
When I look in the chrome debugger, I see the below line highlights the widget
<div class="titlePaneBottomFix titlePaneRightFix dijitTitlePane" title="" role="group" id="dijit_TitlePane_1" widgetid="dijit_TitlePane_1">
If I try to do something like esri.hide(dojo.byId("dijit_TitlePane_1")), then it hides the widget. But can I refer to the title pane using this widget Id?
You may want to just give the title pane its own id in the function:
_createTitlePane: function (title, position, open, optclass, paneId) {
var tp = new TitlePane({
title: title,
id: paneId, // TitlePane id here
open: open
}).placeAt(this.sidebar, position);
domClass.add(tp.domNode, 'titlePaneBottomFix titlePaneRightFix');
if (optclass) {
domClass.add(tp.domNode, optclass);
}
tp.startup();
return tp;
}
Then you can refer to it with and hide it with:
esri.hide(dijit.byId("theIdYouGaveIt").domNode);
To understand the difference between dojo.byId and dijit.byId, this link may help.
Also, if you're creating this in your own custom widget, you can also make the title pane a local reference, ie: this.tp = new TitlePane({...}). Anywhere you need to access it from inside the widget, you can simply call "this.tp". Outside of the widget, you can access it using dot notataion: myWidget.tp.doSomething(). Better yet, if you create it declaratively in a template like this: <div data-dojo-type=dijit/TitlePane" data-dojo-attach-point="tp" ...></div>, when the widget is instantiated it will automatically have a handle to "this.tp" via the attach point.

Create Google Map v3 After Clicking On An Element

What I would like to do is create a map after an element is clicked on. I'm using Google Maps v3.
I have a Realty listing page that shows 15 results/properties per page. Instead of generating 15 maps I would like 1 map to be created when I click on an element. Once clicked on, the map generation process takes place. The map canvas/div is initially hidden.
I was thinking that the click element and map element relationship would be something like this:
<span id="12-1234" lat="10.101010" lng="-25.252525" class="view-map">View Map</span>
... other markup ...
<div id="12-1234-map" class="google-map"></div>
Using HTML5 I add custom attributes to the element about the property like id, latitude and longitude so I can change the icon and center the map.
I've got a functioning map from which I load markers from a dynamically generated XML file based on the search parameters.
I've been looking at addListener and addDomListener but haven't had any luck. Most searches just pull up issues related to markers.
I had a wonky thing that sort of worked that used jQuery. Something like this:
$('.view-map').click(function(){
google.maps.event.addDomListener( this, 'click', initialize );
$("#" + this.id + "-map").toggle();
});
Obviously this wasn't perfect as you'd have to click the element a couple more times before seeing the map as you've bound another click event to it after having already clicking on it.
I feel like I'm missing something obvious.
function initialize(link) {
var mapDiv = $('#' + link.attr('id') + '-map');
mapDiv.toggle();
var options = {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: new google.maps.LatLng(link.attr('lat'), link.attr('lng'))
};
var map = new google.maps.Map(mapDiv[0], options);
}
$('.view-map').click(function(){
initialize(this);
});
In your view-map click function, just call a map initialize method, passing in the appropriate values. This initialize function can then show the map div, and then initialize the map appropriately.
Ugly and unchecked example:
var params = {
lat : 47.5,
lng : -122.5 }
$('.view-map').click(params, function(){
params.id = this.id //e.g. 1234
initialize(params);
});
function initialize(params){
// show the 1234-map div, initialize the map
}

Categories

Resources