Primefaces: Cloning of Diagram Element does not work properly - primefaces

i want to add multiple elements on an existing diagram in primefaces but it overwrites the created one all the time. It creates the first one and after that it keeps overwriting whenever i drop a new element on the diagram.
I'm using the panel via drag'n drop to add new element to the diagram.
See below my code (diagram.xhtml):
<h:form id="elementForm">
<p:panel id="epnl" header="Draggable Panel">
<h:outputText value="New Workflow Task" />
</p:panel>
<p:draggable for="epnl" helper="clone" />
<p:outputPanel id="selectedElements" style="height:600px">
<p:diagram id="diagramV" value="#{diagramFlowChartView.model}"
style="height:600px" styleClass="ui-widget-content" />
</p:outputPanel>
<p:droppable for="diagramV" widgetVar="dropWV">
<p:ajax listener="#{diagramFlowChartView.onElementDrop}"
update="elementForm, selectedElements, diagramV" />
</p:droppable>
</h:form>
<script type="text/javascript">
//<![CDATA[
PrimeFaces.widget.Droppable.prototype.bindDropListener = function() {
var _self = this;
this.cfg.drop = function(event, ui) {
if (_self.cfg.onDrop) {
_self.cfg.onDrop.call(_self, event, ui);
}
if (_self.cfg.behaviors) {
var dropBehavior = _self.cfg.behaviors['drop'];
if (dropBehavior) {
var ext = {
params : [ {
name : _self.id + '_dragId',
value : ui.draggable.attr('id')
}, {
name : _self.id + '_dropId',
value : _self.cfg.target
}, {
name : ui.draggable.attr('id') + '_left',
value : ui.position.left
}, {
name : ui.draggable.attr('id') + '_top',
value : ui.position.top
} ]
};
console.log(ui);
dropBehavior.call(_self, ext);
}
}
};
}
// ]]>
</script>
The related Bean (FormChartView.java):
#ManagedBean(name = "diagramFlowChartView")
#RequestScoped
public class FlowChartView {
private DefaultDiagramModel model;
private Element elm = new Element("", "25em", "10em");
private List<Element> elements = new ArrayList<Element>();
public void onElementDrop(DragDropEvent ddEvent) {
String dargId = ddEvent.getDropId();
System.out.println("dargId = " + dargId);
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String left = params.get(dargId + "_left");
String top = params.get(dargId + "_top");
elment = new Element("Test", left, top);
elment.setId(UUID.randomUUID().toString());
System.out.println("elm.id = " + elm.getId());
model.addElement(elm);
}
#PostConstruct
public void init() {
model = new DefaultDiagramModel();
elm = new Element("", "25em", "10em");
model.setMaxConnections(-1);
FlowChartConnector connector = new FlowChartConnector();
connector.setPaintStyle("{strokeStyle:'#C7B097',lineWidth:3}");
model.setDefaultConnector(connector);
Element start = new Element("Fight for your dream", "20em", "6em");
start.addEndPoint(new BlankEndPoint(EndPointAnchor.BOTTOM));
start.addEndPoint(new BlankEndPoint(EndPointAnchor.LEFT));
start.setDraggable(true);
start.setStyleClass("background-color: #98AFC7");
Element trouble = new Element("Do you meet some trouble?", "20em", "18em");
trouble.addEndPoint(new BlankEndPoint(EndPointAnchor.TOP));
trouble.addEndPoint(new BlankEndPoint(EndPointAnchor.BOTTOM));
trouble.addEndPoint(new BlankEndPoint(EndPointAnchor.RIGHT));
trouble.setDraggable(true);
Element giveup = new Element("Do you give up?", "20em", "30em");
giveup.addEndPoint(new BlankEndPoint(EndPointAnchor.TOP));
giveup.addEndPoint(new BlankEndPoint(EndPointAnchor.LEFT));
giveup.addEndPoint(new BlankEndPoint(EndPointAnchor.RIGHT));
Element succeed = new Element("Succeed", "50em", "18em");
succeed.addEndPoint(new BlankEndPoint(EndPointAnchor.LEFT));
succeed.setStyleClass("ui-diagram-success");
Element fail = new Element("Fail", "50em", "30em");
fail.addEndPoint(new BlankEndPoint(EndPointAnchor.LEFT));
fail.setStyleClass("ui-diagram-fail");
model.addElement(start);
model.addElement(trouble);
model.addElement(giveup);
model.addElement(succeed);
model.addElement(fail);
elements.add(start);
elements.add(trouble);
elements.add(giveup);
elements.add(succeed);
elements.add(fail);
model.connect(createConnection(start.getEndPoints().get(0), trouble.getEndPoints().get(0), null));
model.connect(createConnection(trouble.getEndPoints().get(1), giveup.getEndPoints().get(0), "Yes"));
model.connect(createConnection(giveup.getEndPoints().get(1), start.getEndPoints().get(1), "No"));
model.connect(createConnection(trouble.getEndPoints().get(2), succeed.getEndPoints().get(0), "No"));
model.connect(createConnection(giveup.getEndPoints().get(2), fail.getEndPoints().get(0), "Yes"));
}
public DefaultDiagramModel getModel() {
return model;
}
public void setModel(DefaultDiagramModel model) {
this.model = model;
}
public Element getElment() {
return elment;
}
public void setElment(Element elment) {
this.elment = elment;
}
public List<Element> getElements() {
return elements;
}
public void setElements(List<Element> elements) {
this.elements = elements;
}
private Connection createConnection(EndPoint from, EndPoint to, String label) {
Connection conn = new Connection(from, to);
conn.getOverlays().add(new ArrowOverlay(20, 20, 1, 1));
if(label != null) {
conn.getOverlays().add(new LabelOverlay(label, "flow-label", 0.5));
}
return conn;
}
}

My fault.
This is caused by the element list to be reinitialized each time an (ajax)request was made. Which in turn was caused by the bean scope being #RequestScoped
Changing #RequestScoped to #ViewScoped solved the issue.

Related

primefaces org.primefaces.component.diagram override

I have a problem with org.primefaces.component.diagram, i want to add an action when click on any overlay or connector, i make this using jquery, but the problem is that there is no identifier for the connection, after search i was able to get the ids of the 2 end points of the connection but if there is many connection between the same points then i cannot distinguish between them, i tried to override the diagram and add "connectionId" attribute on the connection but i got an exception in the front end :
Uncaught ReferenceError: connectionId590236 is not defined at eval (eval at (jquery.js.xhtml?ln=primefaces&v=5.2:14), :1:1488)
screenshot
The closet solution would be is to use setId on Element in the DefaultDiagramModel creation.
An example would be as the following:
Element elementA = new Element("A", "20em", "6em");
elementA.setId("element-a");
Element elementB = new Element("B", "10em", "18em");
elementB.setId("element-b");
Element elementC = new Element("C", "40em", "18em");
elementC.setId("element-c");
...
Since PrimeFaces doesn't provide the control you are searching for, and the original component comes from jsPlumb, you may rely on that to achieve what you are looking for.
First make sure that the <p:diagram> has a widgetVar value, es. diagramWV
An example would be the following:
$(document).ready(function () {
//timeout makes sure the component is initialized
setTimeout(function () {
for (var key in PF('diagramWV').canvas.getAllConnections()) {
if (PF('diagramWV').canvas.getAllConnections().hasOwnProperty(key)) {
//Elemenets Events
// on source just once
$(PF('diagramWV').canvas.getAllConnections()[key].source).off('click').on('click', function () {
console.log($(this).attr('id'))
});
// on target just once
$(PF('diagramWV').canvas.getAllConnections()[key].target).off('click').on('click', function () {
console.log($(this).attr('id'))
});
//Connection Event
PF('diagramWV').canvas.getAllConnections()[key].bind("click", function (conn) {
console.log("source " + conn.sourceId);
console.log("target " + conn.targetId);
});
}
}
}, 500);
});
Note: The canvas property of the widgetVar is the current instance of jsPlumbInstance
Here's an online demo, and a small working example on github.
finally i found an acceptable solution :
-> add an label overlay on the connection and set the identifier on it.
org.primefaces.model.diagram.Connection conn = new org.primefaces.model.diagram.Connection(
EndPointA, EndPointB);
LabelOverlay labelOverlay = new LabelOverlay(connection.getId(), "labelOverlayClass", 0.3);
conn.getOverlays().add(labelOverlay);
-> then add JS function to handle on dbclick action on the connection and get the id from its related overlay using the classes "._jsPlumb_overlay" and "._jsPlumb_hover"
<p:remoteCommand name="connectionClicked"
actionListener="#{yourBean.onConnectionDoubleClick}" />
<script type="text/javascript">
var connectionId;
$('._jsPlumb_connector').on('dblclick', function(e) {
$('._jsPlumb_overlay._jsPlumb_hover').each(function() {
connectionId = $(this).text();
});
connectionClicked([ { name : 'connectionId', value : connectionId } ]);
});
});
</script>
-> finally in the bean you extract the id and do whatever you want
public void onConnectionDoubleClick() {
Map<String, String> params = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
String connectionId = params.get("connectionId");
if(StringUtils.isBlank(connectionId))
return;
.........
I was able to add a click event to Overlay by extending the primefaces Overlay class. If you make a change to the toJS() class (taking heavy inspiration from the Primefaces LabelOverLay) then you can write your own overlay with the jsplumb overlay constructor. Here's my implementation of a ClickableLabelOverlay.
public class ClickableLabelOverlay implements Overlay {
private String label;
private String styleClass;
private double location = 0.5;
private String onClick;
public ClickableLabelOverlay() {
}
public ClickableLabelOverlay(String label) {
this.label = label;
}
public ClickableLabelOverlay(String label, String styleClass, double location, String onClick) {
this(label);
this.styleClass = styleClass;
this.location = location;
this.onClick = onClick;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getStyleClass() {
return styleClass;
}
public void setStyleClass(String styleClass) {
this.styleClass = styleClass;
}
public double getLocation() {
return location;
}
public void setLocation(double location) {
this.location = location;
}
public String getOnClick() {
return onClick;
}
public void setOnClick(String onClick) {
this.onClick = onClick;
}
public String getType() {
return "Label";
}
public String toJS(StringBuilder sb) {
sb.append("['Label',{label:'").append(label).append("'");
if(styleClass != null) sb.append(",cssClass:'").append(styleClass).append("'");
if(location != 0.5) sb.append(",location:").append(location);
if(onClick != null) sb.append(",events:{click:function(labelOverlay, originalEvent){").append(onClick).append("}}");
sb.append("}]");
return sb.toString();
}
}
Put any javascript you want to execute inside of the onClick variable and it'll run when you click on the overlay. For convenience I added it to the set of default overlays for my diagram.
diagram.getDefaultConnectionOverlays().add(new ClickableLabelOverlay(...)

I want to create highchart widget by Eclipse RAP and i follow "RAP/Custom Widgets FAQ",but there is error?

i want to create some highchart widget by Eclipse RAP ,and i follow the official guide like this
handlejs:
var CKEDITOR_BASEPATH = "rwt-resources/";
(function(){
'use strict';
rap.registerTypeHandler( "rap.sunline.HighCharts", {
factory : function( properties ) {
var parent = rap.getObject( properties.parent );
// var element = document.createElement( "div" );
// parent.append( element );
// $(element).html("askldfjaskljdk");
return {};
}
});
}());
widget.java:
public class HightChartComposite extends Composite {
private static final String RESOURCES_PATH = "resources/";
private static final String REGISTER_PATH = "hightcharts/";
private static final String[] RESOURCE_FILES = { "jquery-2.1.0.min.js", "highcharts.js","ChartPaintListener.js" };
private static final String REMOTE_TYPE = "rap.sunline.HightCharts";
private final RemoteObject remoteObject;
private final OperationHandler operationHandler = new AbstractOperationHandler() {
#Override
public void handleSet(JsonObject properties) {
// JsonValue textValue = properties.get("text");
// if (textValue != null) {
// text = textValue.asString();
// }
}
};
public HightChartComposite(Composite parent, int style) {
super(parent, style);
registerResources();
loadJavaScript();
Connection connection = RWT.getUISession().getConnection();
remoteObject = connection.createRemoteObject(REMOTE_TYPE);
remoteObject.setHandler(operationHandler);
remoteObject.set("parent", WidgetUtil.getId(this));
}
private void registerResources() {
ResourceManager resourceManager = RWT.getResourceManager();
boolean isRegistered = resourceManager.isRegistered(REGISTER_PATH + RESOURCE_FILES[0]);
if (!isRegistered) {
try {
for (String fileName : RESOURCE_FILES) {
register(resourceManager, fileName);
}
} catch (IOException ioe) {
throw new IllegalArgumentException("Failed to load resources", ioe);
}
}
}
private void loadJavaScript() {
JavaScriptLoader jsLoader = RWT.getClient().getService(JavaScriptLoader.class);
ResourceManager resourceManager = RWT.getResourceManager();
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "jquery-2.1.0.min.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "highcharts.js"));
jsLoader.require(resourceManager.getLocation(REGISTER_PATH + "ChartPaintListener.js"));
}
private void register(ResourceManager resourceManager, String fileName) throws IOException {
ClassLoader classLoader = HightChartComposite.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(RESOURCES_PATH + fileName);
try {
resourceManager.register(REGISTER_PATH + fileName, inputStream);
} finally {
inputStream.close();
}
}
// //////////////////
// overwrite methods
#Override
public void setLayout(Layout layout) {
throw new UnsupportedOperationException("Cannot change internal layout of CkEditor");
}
}
the error is occur:
Uncaught Error: Operation "create" on target "r6" of type "null" failed:
No Handler for type rap.sunline.HightCharts
Properties:
parent = w5
and i have a question about this , what differents from extends Canvas and Composite;
You forget to implement setters in your javascript code.
The created object is stored by the framework under its object id. This object has to implement setter methods that match the properties defined in the handler, which will then be called when the server sends a set operation for a given property.

primefaces selectOneMenu not outputting correctly

I am creating a SelectOneMenu. The menu outputs correctly. However, along with the menu being outputted is an InputBox and then all the items of the menu being printed as text. I don't know what is causing it. I have included a image of the output below.
Here is my JSF code:
<p:panelGrid columns="2">
<h:outputLabel for="trader" value="Trader:" />
<p:selectOneMenu id="trader" value="#{fixBean.trader}">
<f:selectItem itemLabel="Select" itemValue="0" />
<f:selectItems value="#{fixBean.traderOption}" />
</p:selectOneMenu>
</p:panelGrid>
Below is the code to my Bean:
private SelectItem[] traderOption = createFilterOptions(traders);
private final static String[] traders;
private static String trader = "";
static {
traders = new String[9];
traders[0] = "Dowd";
traders[1] = "Dwyer";
traders[2] = "Edelman";
traders[3] = "Hughes";
traders[4] = "Kelley";
traders[5] = "Nauyokas";
traders[6] = "Options";
traders[7] = "Rafferty";
traders[8] = "Russillo";
}
public String getTrader() {
return trader;
}
public void setTrader(String trader) {
this.traderOption = trader;
}
public void setTraderOption() {
traderOption = createFilterOptions(traders);
}
private SelectItem[] createFilterOptions(String[] data) {
SelectItem[] options = new SelectItem[data.length + 1];
options[0] = new SelectItem("", "Select");
for(int i = 0; i < data.length; i++) {
options[i + 1] = new SelectItem(data[i], data[i]);
}
return options;
}
public SelectItem[] getTraderOption() {
return traderOption;
}
The SelectMenu has the correct options in it however, I don't know why the rest of the output is being create (i.e. InputBox and text list).
****update****
I rebuilt the page using the primfaces SelectOneMenu example and built out from there. That resolved the issue. Though still not sure what was causing the issue

event.getOverlay returns null eventhough the overlay is added

My xhtml code snippet
<p:gmap id="gMap" center="17.483333,78.416667" zoom="15" type="ROADMAP" model="#{routeMapngSysMBean.simpleModel}" style="width: 1150px; height: 450px;">
<p:ajax event="overlaySelect" listener="#{routeMapngSysMBean.onMarkerSelect}" />
<p:gmapInfoWindow>
<p:outputPanel style="text-align:center;display:block;">
<h:outputText value="#{routeMapngSysMBean.marker.data}" />
</p:outputPanel>
</p:gmapInfoWindow>
</p:gmap>
RouteMappingMBean.java
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(name = "routeMapngSysMBean")
#SessionScoped
public class RouteMapngSysMBean extends AdminCommonMBean implements
Serializable, WebConstants, ErrorConstants {
private MapModel simpleModel;
public RouteMapngSysMBean() {
initiliaze();
String zone_cd = httpServletRequest
.getParameter("routeMapForm:location");
String vendor_cd = httpServletRequest
.getParameter("routeMapForm:vendor");
String dDate = httpServletRequest.getParameter("routeMapForm:date");
String slot = httpServletRequest.getParameter("routeMapForm:timeslot");
try {
if (orderMgmtBusn == null) {
orderMgmtBusn = (OrderMgmtBusn) BeansUtil.getBean(facesContext,
"orderMgmtBusn");
}
simpleModel = new DefaultMapModel();
if (ValidateUtil.isFieldNotEmpty(vendor_cd)
&& ValidateUtil.isFieldNotEmpty(zone_cd)
&& ValidateUtil.isFieldNotEmpty(dDate)
&& ValidateUtil.isFieldNotEmpty(slot)) {
mapDetails = orderMgmtBusn.getMapDetails(vendor_cd,slot,dDate, zone_cd);
}
List<GMapDetails> latlang = mapDetails;
for (GMapDetails var : latlang) {
if (ValidateUtil.isFieldNotEmpty(var.getLatitude()) && ValidateUtil.isFieldNotEmpty(var.getLongitude())) {
firstName = var.getCustomerFName();
customerId = var.getCustomerId();
orderId = var.getOrderId();
orderValue = var.getOrderValue();
String Customerdetails = "\n CustomerName:"+firstName+"\n CustomerId:"+customerId+"\n OrderId:"+orderId+"\n OrderValue:"+orderValue;
lat = Double.parseDouble(var.getLatitude());
lng = Double.parseDouble(var.getLongitude());
LatLng coord1 = new LatLng(lat, lng);
simpleModel.addOverlay(new Marker(coord1, var.getLocationName(),Customerdetails));
}
}
} catch (EMartBusnException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void initiliaze() {
try {
WebApplicationContext springContext = WebApplicationContextUtils
.getWebApplicationContext((ServletContext) facesContext
.getExternalContext().getContext());
if (emartAppBaseBusn == null) {
emartAppBaseBusn = (EmartAppBaseBusn) springContext
.getBean("emartAppBaseBusn");
}
avilableStoreTypes = BeanMappingUtil
.filterVendorZones(emartAppBaseBusn.retriveZones());
retriveAllVendorsList = emartAppBaseBusn.retriveAllVendorsList();
zonesList = BeanMappingUtil.filterVendorZones(emartAppBaseBusn
.getZones());
} catch (EMartBusnException e) {
logger.error(e);
}
}
public void onMarkerSelect(OverlaySelectEvent event) {
marker = (Marker) event.getOverlay();
}
public MapModel getSimpleModel() {
return simpleModel;
}
public void setSimpleModel(MapModel simpleModel) {
this.simpleModel = simpleModel;
}
public Marker getMarker() {
return marker;
}
Please try transforming 'simpleModel' field declaration from:
private MapModel simpleModel;
to:
private final static MapModel simpleModel = new DefaultMapModel();
...and of course remove this: 'simpleModel = new DefaultMapModel();' from the constructor.

Binding StringElement (MT.D) with MvvmCross

We are using some MT.D StringElements, and their Value Property is bound to properties in the ViewModel.
The initial value is correctly shown but when the ViewModel changes some values and triggers PropertyChanged then the StringElements contain the good value but the display is not refreshed.
If we scroll the Controller or touch the StringElement then it is refreshed: the correct value is displayed.
Do you have any idea?
This is our ViewController
public class ContactView : MvxDialogViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
var bindings = this.CreateInlineBindingTarget<ContactViewModel> ();
Root = new RootElement()
{
new Section()
{
new StringElement("Company Name").Bind(bindings, vm => vm.CompanyName)
}
}
}
}
This is our ViewModel (simplified)
public class ContactViewModel : MvxViewModel
{
private string companyName;
public string CompanyName{
get{return companyName;}
set{companyName = value; RaisePropertyChanged(() => CompanyName);}
}
public async Task Init(string id)
{
var contact = await someService.SomeMethodAsync();
CompanyName = contact.CompanyName;
}
}
I found two solutions to my problem:
If I use UIView.Transition to replace the content then, in the new View, nothing is refreshed when I change the ViewModel (unless I scroll or tap it) UNLESS if the ViewModel properties have some default value non null and non empty
If I don't transition but use another method like this one to replace the content:
Sample code
MasterNavigationController.PopToRootViewController(false);
MasterNavigationController.ViewControllers = new UIViewController[] { viewController };
In this case the content is replaced and the view is refreshed when a ViewModel property changes: everything works correctly in this case.
I tried a viewmodel like:
public class FirstViewModel
: MvxViewModel
{
private Timer _timer;
private int _count;
public FirstViewModel()
{
_timer = new Timer(DoThis, null, 1000, 1000);
}
private void DoThis(object state)
{
_count++;
TextProperty = _count.ToString();
}
private string _textProperty = "T";
public string TextProperty
{
get { return _textProperty; }
set { _textProperty = value; RaisePropertyChanged(() => TextProperty); }
}
}
with a dialog view defined like:
Root = new RootElement("Example Root")
{
new Section("Debut in:")
{
new EntryElement("Login", "Enter Login name").Bind(bindings, vm => vm.TextProperty)
},
new Section("Debug out:")
{
new StringElement("Value is:").Bind(bindings, vm => vm.TextProperty),
};
It worked fine - ticking up every second...