I am using primefaces to manage a gmap.
I display some markers on the map that result of a query using some parameters passed by the user.
I would like to display more informations when a user click on the marker but I don't succeed in displaying the marker.data.
map.xhtml :
<p:gmap center="53.483959, -2.244644" zoom="7" type="HYBRID" style="width:100%;height:800px" model="#{poc_InputManager.mymap}" >
<p:ajax event="overlaySelect" listener="#{poc_InputManager.onMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow">
<p:outputPanel style="text-align: center; display: block; margin: auto">
<h:outputText value="#{poc_InputManager.marker.data}" />
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
java code :
public MapModel getMymap() throws Exception {
mymap=new DefaultMapModel();
ArrayList<POC_LocationsPostalCode> ad = lpcdao.getCodesFiltered(selectedsta);
for (int i = 0 ;i<ad.size();i++){
LatLng tmpcoord = new LatLng(ad.get(i).getLat(),ad.get(i).getLng());
Marker m = new Marker(tmpcoord, ad.get(i).getLocationcode());
m.setData("TEST");
mymap.addOverlay(m);
}
return mymap;
}
In this example, when the user click on the marker it should display "TEST".
Ultimately the goal is to display some informations that are retrieved by a query using the title of the marker.
You should try something like this:
<p:gmap ... >
<p:ajax event="overlaySelect" listener="#{locationManager.onMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow" >
<p:outputPanel style="text-align: left; display: block; margin: auto">
<p:outputLabel value="${locationManager.myMarker}" />
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
#ViewScoped
#Managedbean
public class LocationManager {
private String myMarker; //Your object
//Getter and Setters...
//your listener
public void onMarkerSelect(OverlaySelectEvent event) {
marker = (Marker) event.getOverlay();
myMarker = (String) marker.getData();
}
}
Related
I'm using PrimeFaces 8.0.3. The first time the page loads, the gmap has no markers because the table where I store the coordinates is empty. When a new marker is added, the page refreshes but the map still doesn't show the marker. This problem only happens when I run the application on the server, because when I run it locally, the new marker is shown without problems. The page refreshes every ten seconds to check if there are new rows in the table.
Html:
<script type="text/javascript" src="https://maps.google.com/maps/api/js?key=[provided api key]"></script>
<h:form>
<p:panel>
<p:gmap center="-0.2727324,-78.5489364" zoom="18" type="ROADMAP" style="width:90%;height:700px" model="#{mapaCtrl.simpleModel}" />
<p:poll interval="10" listener="#{contadorCtrl.recargarMapa()}" />
</p:panel>
</h:form>
MapaCtrl:
#ManagedBean
#RequestScoped
public class MapaCtrl implements Serializable
{
private MapModel simpleModel;
...
public void dibujarMarcadores()
{
for(int i = 0; i < listaSolicitud.size(); i++)
{
LatLng coord = new LatLng(Double.parseDouble(listaSolicitud.get(i).getLatitud()), Double.parseDouble(listaSolicitud.get(i).getLongitud()));
simpleModel.addOverlay(new Marker(coord, listaSolicitud.get(i).getDescripcionsolicitud()));
}
}
}
ContadorCtrl:
#ManagedBean
#RequestScoped
public class MapaCtrl implements Serializable
{
...
public void recargarMapa()
{
...
if(solicitudesActuales != MapaCtrl.solicitudesIniciales)
{
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
try
{
ec.redirect(((HttpServletRequest) ec.getRequest()).getRequestURI());
}
catch(IOException ex)
{
Logger.getLogger(ContadorCtrl.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
How can I show the new markers in the map?
You need to assign an id to your map component, and then update it when polling:
<p:gmap id="myMap" center="-0.2727324,-78.5489364" zoom="18" type="ROADMAP" style="width:90%;height:700px" model="#{mapaCtrl.simpleModel}" />
<p:poll interval="10" listener="#{contadorCtrl.recargarMapa()}" update="myMap"/>
I have a page (page1.xhtml) with a tabView and a dataTable within one of the tabs. The dataTableuses lazy loading and should provide multisort mode.
Therefore I use a List<SortMeta> for the sortBy attribute of dataTable as found here (Initial sortorder for PrimeFaces datatable with multisort).
The List<SortMeta> is created in getPreSortOrder() but findComponent() for clientId "myForm:tabs:data:colName" always returns null!
In another constellation (page2.xhtml) where I have the dataTable not in a tabView findComponent() always returns the correct column component!
So the problem seems to be the combination with tabView?!
Any hints welcome - Thank you!
page.xhtml:
<html>
<f:metadata>
<f:viewAction action="#{model.loadData}"/>
</f:metadata>
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="content">
<h:form id="myForm">
<p:panelGrid>...</p:panelGrid>
<p:tabView id="tabs">
<p:tab id="tab1">...</p:tab>
<p:tab id="tab2">...</p:tab>
<p:tab id="tab3">
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple" sortBy="#{model.tableMode.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}"> // <-- findComponent for "myForm:tabs:data:colName" always returns null !!!
<h:outputText value="#{item.name}"/>
</p:column>
<p:column id="colAddress" sortBy="#{item.address}">
<h:outputText value="#{item.address}"/>
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
</h:form>
</ui:define>
</ui:composition>
</html>
page2.xhtml:
<html>
<f:metadata>
<f:viewAction action="#{model.loadData}"/>
</f:metadata>
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="content">
<h:form id="myForm">
<p:panelGrid>...</p:panelGrid>
<p:outputPanel id="tables">
<p:fieldset>
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple" sortBy="#{model.tableMode.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}"> // <-- findComponent for "myForm:data:colName" always component
<h:outputText value="#{item.name}"/>
</p:column>
<p:column id="colAddress" sortBy="#{item.address}">
<h:outputText value="#{item.address}"/>
</p:column>
</p:dataTable>
<p:fieldset>
</p:outputPanel>
</h:form>
</ui:define>
</ui:composition>
</html>
Model.java:
#Named // javax.inject.Named
#ViewScoped // javax.faces.view.ViewScoped
public class Model implements Serializable {
private static final String COL_NAME_CLIENT_ID = "myForm:tabs:data:colName";
#Inject PersonTableDataModel personTableDataModel; // with getter & setter
public void loadData() {
List<SortMeta> preSortOrder = getPreSortOrder(COL_NAME_CLIENT_ID, "name", SortOrder.ASCENDING);
personTableDataModel.setPreSortOrder(preSortOrder);
}
private List<SortMeta> getPreSortOrder(String columnId, String sortField, SortOrder sortOrder) {
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
UIComponent column = viewRoot.findComponent(columnId); // <-- ALWAYS RETURNS NULL
if (Objects.isNull(column)) {
return Collections.emptyList();
}
List<SortMeta> preSortOrder = new ArrayList<>();
SortMeta sm = new SortMeta();
sm.setSortBy((UIColumn) column);
sm.setSortField(sortField);
sm.setSortOrder(sortOrder);
preSortOrder.add(sm);
return preSortOrder;
}
}
PersonTableDataModel.java:
public class PersonTableDataModel extends TableModel<Person> {
}
TableModel.java:
public class TableModel<T> extends LazyDataModel<T> {
private List<SortMeta> preSortOrder; // with getter & setter
}
I am using Primefaces 6.1 on Wildfly 10.0.0.Final
EDIT:
I added a TabChange event listener changeTab() and traversed the UIComponents and at the end the correct clientId is written to the output?!
Model.java:
public void changeTab(TabChangeEvent event) {
TabView tabView = (TabView) event.getComponent();
logger.entry(tabView.getActiveIndex());
Tab tabProzesse = tabView.findTab("myForm:tabs:tab3");
if (Objects.nonNull(tabProzesse)) {
List<UIComponent> childs = tabProzesse.getChildren();
Optional<UIComponent> c = childs.stream().filter(child -> child.getClientId().equals("myForm:tabs:data")).findFirst();
if (c.isPresent() && c.get() instanceof DataTable) {
DataTable t = (DataTable) c.get();
Optional<UIColumn> optColName = t.getColumns().stream().filter(col -> col.getClientId().contains("colName")).findFirst();
optColName.ifPresent(colName -> {
logger.debugf("colName.clientId=%s", colName.getClientId()); // <-- output colName.clientId=myForm:tabs:data:colName
});
}
}
}
I fixed it by this work-around:
added tabChange event listener to tabView and update datatable data
added binding to initial sort column with id colName
set preSortOrder for tableModel in onTabChange listener
page.xhtml:
<p:tabView id="tabs">
<p:ajax event="tabChange" listener="#{model.onTabChange}" update="data"/>
<p:tab id="tab1">...</p:tab>
<p:tab id="tab2">...</p:tab>
<p:tab id="tab3">
<p:dataTable id="data" lazy="true"
value="#{model.personTableModel}" var="item"
sortMode="multiple"
sortBy="#{model.personTableModel.preSortOrder}">
<p:column id="colName" sortBy="#{item.name}" binding="#{mode.colName}">
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
Model.java:
private UIComponent colName;
public UIComponent getColName() {
return colName;
}
public void setColName(UIComponent colNameProzess) {
this.colName = colName;
}
public void onTabChange(TabChangeEvent event) {
TabView tabView = (TabView) event.getComponent();
UIComponent uiComponent = findComponent(tabView, colName.getId());
if (Objects.nonNull(uiComponent) && uiComponent instanceof org.primefaces.component.api.UIColumn) {
List<SortMeta> preSortOrder = getPreSortOrder(uiComponent, "name", SortOrder.ASCENDING);
personTableDataModel.setPreSortOrder(preSortOrder);
}
}
private List<SortMeta> getPreSortOrder(UIColumn column, String sortField, SortOrder sortOrder) {
List<SortMeta> preSortOrder = new ArrayList<>();
SortMeta sm = new SortMeta();
sm.setSortBy(column);
sm.setSortField(sortField);
sm.setSortOrder(sortOrder);
preSortOrder.add(sm);
return preSortOrder;
}
private UIComponent findComponent(UIComponent uiComponent, String id) {
FacesContext context = FacesContext.getCurrentInstance();
UIComponent base = Objects.nonNull(uiComponent) ? uiComponent : context.getViewRoot();
final UIComponent[] found = new UIComponent[1];
base.visitTree(VisitContext.createVisitContext(context), (context1, component) -> {
if (component.getId().equals(id)) {
found[0] = component;
return VisitResult.COMPLETE;
}
return VisitResult.ACCEPT;
});
return found[0];
}
I have a problem with Primefaces whose version is 5.2. I used gmap and gmapInfoWindow. I need that from the Managed Bean open the gmapInfoWindow of a specific marker.
Here is the Code
infoWindow.xhtml
<h:form>
<p:gmap id="gmap" center="36.890257,30.707417" zoom="13" type="HYBRID" model="#{infoWindowView.advancedModel}" style="width:100%;height:400px">
<p:ajax event="overlaySelect" listener="#{infoWindowView.onMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow">
<p:outputPanel style="text-align: center; display: block; margin: auto">
<p:graphicImage name="/demo/images/antalya/#{infoWindowView.marker.data}" height="150" />
<br />
<h:outputText value="#{infoWindowView.marker.title}" />
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
<!-- Preload for demo -->
<p:outputPanel style="display:none">
<p:graphicImage name="/demo/images/antalya/konyaalti.png" />
<p:graphicImage name="/demo/images/antalya/ataturkparki.png" />
<p:graphicImage name="/demo/images/antalya/kaleici.png" />
<p:graphicImage name="/demo/images/antalya/karaalioglu.png" />
</p:outputPanel>
</h:form>
and My ManagedBean InfoWindowView.java
package org.primefaces.showcase.view.data.gmap;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;
#ManagedBean
#ViewScoped
public class InfoWindowView implements Serializable {
private MapModel advancedModel;
private Marker marker;
#PostConstruct
public void init() {
advancedModel = new DefaultMapModel();
//Shared coordinates
LatLng coord1 = new LatLng(36.879466, 30.667648);
LatLng coord2 = new LatLng(36.883707, 30.689216);
LatLng coord3 = new LatLng(36.879703, 30.706707);
LatLng coord4 = new LatLng(36.885233, 30.702323);
//Icons and Data
advancedModel.addOverlay(new Marker(coord1, "Konyaalti", "konyaalti.png", "http://maps.google.com/mapfiles/ms/micons/blue-dot.png"));
advancedModel.addOverlay(new Marker(coord2, "Ataturk Parki", "ataturkparki.png"));
advancedModel.addOverlay(new Marker(coord4, "Kaleici", "kaleici.png", "http://maps.google.com/mapfiles/ms/micons/pink-dot.png"));
advancedModel.addOverlay(new Marker(coord3, "Karaalioglu Parki", "karaalioglu.png", "http://maps.google.com/mapfiles/ms/micons/yellow-dot.png"));
}
public MapModel getAdvancedModel() {
return advancedModel;
}
public void onMarkerSelect(OverlaySelectEvent event) {
marker = (Marker) event.getOverlay();
}
public Marker getMarker() {
return marker;
}
}
I have a <p:gmap> with specific markers. I would like to crop a part of that <p:gmap>. I can't do it with <p:imageCropper>, because it crops an image, not a Google Map. How can I capture a specific part of the Google Map?
This is my map bean:
#ManagedBean
#ViewScoped
public class InfoWindowView implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
GestionAnalyseLocal m;
private MapModel advancedModel;
private Marker marker;
#PostConstruct
public void init() throws IOException {
advancedModel = new DefaultMapModel();
List<Analyse> alys = new ArrayList<Analyse>();
alys = m.findAll();
for (int i = 2; i <= alys.size(); i++) {
Double x = null;
Double y = null;
try {
x = Double.parseDouble(alys.get(i).getLongitude());
y = Double.parseDouble(alys.get(i).getLatitude());
LatLng coord1 = new LatLng(y, x);
if (alys.get(i).getUu_HandoffOk() == 1) {
advancedModel.addOverlay(new Marker(coord1, "test", "point.png",
"http://maps.gstatic.com/mapfiles/ridefinder-images/mm_20_blue.png "));
} else {
if (alys.get(i).getUu_OutgoingCallOk() == 1) {
advancedModel.addOverlay(new Marker(coord1, "test", "phone",
"http://maps.google.com/mapfiles/kml/pal4/icon52.png"));
}
}
} catch (Exception e) {
System.out.println("err");
}
}
}
public MapModel getAdvancedModel() {
return advancedModel;
}
public void onMarkerSelect(OverlaySelectEvent event) {
marker = (Marker) event.getOverlay();
}
public Marker getMarker() {
return marker;
}
}
And this is the JSF page:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
xmlns:p="http://primefaces.org/ui">
<h:head>
<script src="http://maps.google.com/maps/api/js?sensor=true|false" type="text/javascript" ></script>
</h:head>
<h:body>
<h:form >
<h:commandButton action="#{infoWindowView.init()}" value="Generate" />
</h:form>
<h:form>
<p:growl id="growl" showDetail="true" />
<h:panelGrid columns="2" columnClasses="left,right" style="width:100%">
<p:chart type="pie" model="#{chartView.pieModel1}" style="width:400px;height:300px">
<p:ajax event="itemSelect" listener="#{chartView.itemSelect}" update="growl" />
</p:chart>
</h:panelGrid>
</h:form>
<h:form>
<p:gmap id="gmap" center="36.8189700,10.1657900" zoom="12" type="HYBRID" model="#{infoWindowView.advancedModel}" style="width:100%;height:400px">
<p:ajax event="overlaySelect" listener="#{infoWindowView.onMarkerSelect}" />
<p:gmapInfoWindow id="infoWindow">
<p:outputPanel style="text-align: center; display: block; margin: auto">
<h:graphicImage value="resources/images/orange.png" height="150" />
<br />
<h:outputText value="#{infoWindowView.marker.title}" />
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
<!-- Preload for demo -->
<p:outputPanel style="display:none">
<p:graphicImage name="images/#{orange.png}" title="orange.png" />
</p:outputPanel>
</h:form>
</h:body>
</ui:composition>
By cropping map you mean you still want all the map facilities but for the selected region then you can do something like this(take another map when user tries to crop the map and get the coordinates from original map build set the selected region to new map and show to the user) user still will be able to use the map facilities.
the situation is the following: I've got a treeTable with 3 different type of objects. The table contains the p:ajax with event="select". I wrote 3 different contextMenus, one for each type... and all works well.
My problem is that I want to enable/disable some of the menuItems; to do that I use the attribute "rendered" with condition based on properties of selected node.
All works, but only the second time I right-click on the same object (the first time the contextMenu isn't filtered).
Here is the code... (I'm including only one type of object for semplicity)
treeTable page:
<h:form id="form" prependId="false">
<p:treeTable value="#{documentsController.root}" var="document" id="docs"
selectionMode="single" selection="#{documentsController.selectedNode}">
<p:ajax event="select" process="#this" update=":form:menus"/>
<p:column headerText="#{msg['name']}">
<h:outputText value="#{document.name}" />
</p:column>
</p:treeTable>
<h:panelGroup id="menus">
<ui:include src="/menu/document_menu.xhtml"/>
</h:panelGroup>
<p:dialog id="document-rename-dialog" widgetVar="documentRenameDialog" header="#{msg.rename}">
<h:panelGrid id="doc-rename" columns="2">
<h:outputLabel for="name" value="#{msg.name}:" />
<h:inputText id="name" value="#{documentsController.name}"/>
</h:panelGrid>
<div class="spacer-10" />
<h:panelGroup layout="block">
<p:commandLink onclick="documentRenameDialog.hide();" value="#{msg.cancel}"/>
<p:commandLink actionListener="#{documentsController.renameDocument(documentsController.selectedNode.data)}"
process="#this :form:document-rename-dialog:doc-rename"
update=":form:docs"
oncomplete="documentRenameDialog.hide();"
value="#{msg.check}">
</h:panelGroup>
</common:dialog>
</h:form>
document_menu page:
<p:contextMenu id="contextMenuDocument" for="docs" nodeType="document">
<p:menuitem value="#{msg.rename}" process="#this docs" update=":form:document-rename-dialog:doc-rename"
actionListener="#{documentsController.setName(documentsController.selectedNode.data.name)}"
rendered="#{documentsController.canWrite}"
icon="ui-icon-pencil" oncomplete="documentRenameDialog.show();"/>
</p:contextMenu>
DocumentsController class:
#ManagedBean
#ViewScoped
public class DocumentsController {
private TreeNode root;
private TreeNode selectedNode;
private String name;
public TreeNode getSelectedNode() {
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode) {
this.selectedNode = selectedNode;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void renameDocument(ArterDocument selectedDocument) {
if(name != null && !name.equals("")) {
System.out.println("Document renamed in: "+name);
((MyDocument)selectedNode.getData()).setName(name);
}
else
addErrorMessage("Error renaming document.");
}
public static boolean canWrite() {
if(((MyDocument)selectedNode.getData()).isWriteable())
return true;
return false;
}
}
The MyDocument class is a simple class with a String (name) and a boolean (writeable).
Can anyone tell me how I can show filtered contextMenu at first shot?
Thank you!