makkasi
makkasi

Reputation: 7328

How to refresh gmap markers in primefaces p:gmap after updating the gmap with new markers

I have problem on a project with Gmap component of Primefaces 3.5 I'm using JSF2.0. I have this command Button that do filtering on the markers and most important updates mapForm

<h:form id="epsFilterForm">
      <p:commandButton action="#{mapMB.filterProjects}" value="#{bundle['filter'] }" update=":mapForm" />
</h:form>

mapForm:

<h:form id="mapForm">  
<p:gmap id="googleMap" center="48.849988,2.3805715" zoom="11"  type="TERRAIN" fitBounds="false" model="#{mapMB.advancedModel}" 
    widgetVar="wmap" style="width:1000px;height:700px;display: inline-block;" >

    <p:ajax event="overlaySelect"  listener="#{mapMB.onMarkerSelect}" />   
    <p:gmapInfoWindow>  
        <p:outputPanel style="text-align:center;display:block;margin:auto:">
            <p:panelGrid columns="2" styleClass="InfoTable" >

                <p:outputLabel value="#{bundle['ep.operation.name'] }" />
                <p:outputLabel value="#{mapMB.selectedEp.opName}" />
            </p:panelGrid>
        </p:outputPanel>  
    </p:gmapInfoWindow> 
</p:gmap>

MapMB - scope - Session scope populateAdvancedModel()

public void populateAdvancedModel(List<EP> eps) {
    advancedModel = new DefaultMapModel();
    int count = 0;
    Marker marker;
    for (EP ep :eps) {
        //advancedModel.addOverlay(new Marker(coord1, "Konyaalti", "konyaalti.png", "http://maps.google.com/mapfiles/ms/micons/blue-dot.png"));
        System.out.println("Integer.toString(ep.getId()):"+Integer.toString(ep.getId()));
        marker =  new Marker(new LatLng(  Double.parseDouble(ep.getLatitude()) ,  Double.parseDouble(ep.getLongitude())));
        marker.setTitle( Integer.toString(count));
        advancedModel.addOverlay(marker);
        count++;
    }
}

filterProjects()

public String filterProjects() {
    //FilterMB filterMB = (FilterMB) JSFUtil.getManagedObject("filterMB");
    eps = EPDAO.filterEPs(client, architect, realizationType, state, selectedCert);
    populateAdvancedModel(eps);
    return null;
}

onMarkerSelect()

public void onMarkerSelect(OverlaySelectEvent event) {
    Marker marker = (Marker) event.getOverlay();
    String markerTitle = marker.getTitle();
    selectedEp = eps.get(Integer.parseInt(markerTitle));
}

When I load the page for first time everything is OK. Info (p:gmapInfoWindow ) window is loading and information for EP variable is there. But when I click the command button in epsFilterForm (that has some input fields that i haven't posted here) the map is updated and the filtered markers are there and they obviously have title when i hover on them, but overlaySelect event is not working in the same way. I thing that when page is loading for the first time there is some initial script that puts that behavior on the markers but when I refresh the map this initial script is not running again and that's is why when I click on the marker and overlaySelect event is fired I have null pointer Exception in onMarkerSelect() method (marker is null). IMPORTANT - this is working without a problem on local server but when I deploy it to google app engine it's working as i described above.

Upvotes: 3

Views: 7577

Answers (3)

TomTom
TomTom

Reputation: 41

I have a similar situation. In fact what I am trying to do is to update the markers in gmap after the gmap is rendered. As @yannicuLar said, the mapModel is retrieved once at the beginning when map is rendered. Later update on mapModel is not reflected on the map.

My solution is to use primefaces functionality to trigger executing javascript from server side.

In xhtml:

            var markers = [];
            function clearMarkers() {
                for (var i = 0; i &lt; markers.length; i++) {
                      markers[i].setMap(null);
                 }
                markers=[];
            }
            function addMarkers() {
                for (var i = 0; i &lt; markers.length; i++) {
                    PF('yourMap').addOverlay(markers[i]);
                   }
            }

In java/server side, at the place where you are supposed to update your mapModel with lat/lng, you add codes as below:

To clear the markers:

RequestContext.getCurrentInstance().execute("clearMarkers()");

Suppose you have multiple marks, to iteratively add all the markers to marker array:

RequestContext.getCurrentInstance().execute("var currentMarker = new google.maps.Marker({ position:new google.maps.LatLng("
                    + latitude + ", " + longitude
                    + "), map:PF('yourMap').getMap()});"
                    + "markers.push(currentMarker);");

To add markers to map after the marker array is populated:

RequestContext.getCurrentInstance().execute("addMarkers()");

It is tested, and works for me.

Upvotes: 0

Ntobeko Mkhize
Ntobeko Mkhize

Reputation: 112

I use the onGeocode event, in the backing bean check if there are any loaded markers. Remove these markers before adding your new markers. Hope this helps.

public void onGeocode(GeocodeEvent event) {

    try {

        List<GeocodeResult> results = event.getResults();

        if (results != null && !results.isEmpty()) {
            LatLng center = results.get(0).getLatLng();
            centerGeoMap = center.getLat() + "," + center.getLng();

            List<Marker> markers = geoModel.getMarkers();

            if (markers != null && markers.size() > 0) {

                geoModel.getMarkers().removeAll(markers);
            }

            for (int i = 0; i < results.size(); i++) {
                GeocodeResult result = results.get(i);
                geoModel.addOverlay(new Marker(result.getLatLng(), result.getAddress()));

            }
        }
    } catch (Exception e) {
        logger.error("Could not update GMap from geoCode", e);
    }
}

Upvotes: 0

yannicuLar
yannicuLar

Reputation: 3133

The DefaultMapModel of the gmap (referenced from 'model' attribute in p:gmap element) has no proper functionality to clear, unlike other Model objects, like e.g. the EventModel of p:schedule.

IF you provide that object from a SessionScoped controller, even if you recreate that object from scratch, the p:gmap for some reason is keeping reference to the first mapModel that was provided. Practically this means that all new/updated mapmodel objects are not being used, except the first one.

So, a tricky point of gmap that is going to be updated (adding/removing markers, overlays etc) is that the mapmodel object should be retrieved from a RequestScoped object.

Now, another option, would be iterating through all the markers. You can find similar posts here. This way you can keep your backing bean as SessionScoped, but again, you are not supposed to create a new mapModel.

EDIT: I'm m getting the impression that the view fails to update the markers, not the mapModel itself. Anyway, the solution is the same. It's just that sometimes you can't drop the bean Scope to request (e.g. fetching an info window on overlaySelect), so you end up refreshing the markers

Upvotes: 2

Related Questions