How to check a Specific Properties of a Shape in BPMNjs and update them dynamically - vue.js

In the bpmnjs I wanted to access or change the right panel properties dynamically on Selection of a Shape or shape type
Below snippet I am trying to use to updated the properties:
updateProperties(e) {
try {
let canvas = this.bpmnModeler.get("canvas");
let rootElement = canvas.getRootElement();
var modeling = this.bpmnModeler.get("modeling");
this.$nextTick(() => {
modeling.updateProperties(e.element, {
id: "ABC",
name: "ABCD",
isExecutable: true,
});
});
} catch (e) {}
}
Please help me to find how to get a specific property of selected shape and update the property in the right panel. Or I have to know how the right panel properties of the bpmnjs is actually configured and loading . I am very much new for the BPMNjs. appreciate for the reply.
I have tried bpmnjs above vuejs framework. I wanted to know how the properties on the right panel of each Task or Shape on the COMUNDA bpmnjs

Related

How to access or get value of specific graph on chart plot by click event?

I use vue-chartjs to draw some chart like line, bar, etc.
In my project, there are many cases using specific value or lable of data in chart.
Using tooltip option of vue-chartjs, I can check that value or label of data item when hovered.
I want to know how to access or get information of specific data matched with point on graph when clicked(not hovered).
Here is my code about chart options.
chartOptions: {
responsive: false,
onClick: function(evt){
//Some logic to get value of label of specific data...(type, label, value, ...)
}
In my case, I use 'onclick' option to access specific data on point triggered 'click' event. In 'onClick' callback, I checked all of chart elements and dataset, etc.
How can I get value of label specific dataItem on point of graph(like line) or bar of graph(like bar) when triggered click event?
I was not able to find a solution that worked for me, but I dug a little bit and this is what I came up with.
onClick: function(evt, array) {
if (array.length != 0) {
var position = array[0]._index;
var activeElement = this.tooltip._data.datasets[0].data[position]
console.log(activeElement);
} else {
console.log("You selected the background!");
}
}
This will get the position in the array that you clicked and grab the data from what position you clicked. This may not be the prettiest or best example, but it worked for me.
This solution use the getElementAtEvent method of chartjs, but to use that you need reference to the Chart itself, not the Vue component. We can get that from the $data._chart property. To use this in a parent Vue component, we use the $refs as seen below`.
So parent defines the chart options
{
...
options: {
onClick: this.handleChartClick
}
...
}
and then parent method, using $refs with $data._chart to get the chart. We get the datasetIndex and value and also the tooltip
handleChartClick(evt, elements) {
var chart = this.$refs.periodChart.$data._chart;
const chartIndex = chart.getElementAtEvent(evt);
if (chartIndex.length !== 0) {
const datasetIndex = chartIndex[0]._datasetIndex;
const position = chartIndex[0]._index;
const info = {
datasetIndex: datasetIndex,
valueIndex: position,
label: chart.tooltip._data.labels[position],
value: chart.tooltip._data.datasets[datasetIndex].data[position]
};
console.log(info);
} else {
console.log("Background clicked");
}

Chartist.js and events

I am trying to add click events on the graphs that I am rendering. From chart.click to chart.on('click', function (e){ }).
What I am trying to do is allow the user to select points on the graph and for me to now what selections the user made. Is that at all possible using chartist.js?
I read through the documentation: CHARTIST.JS
My code:
if (item.GraphType.Description == "Line") {
var chart = new Chartist.Line(
container[0],
{
labels: d.Labels,
series: d.SeriesData
},
{
axisY: {
offset: 60
}
}
);
chart.click(function (e) {
console.log(e);
});
}
It is entirely possible, yes. Chartist renders SVG nodes to the page, so using a library like jQuery you can easily find all nodes that you want and attach events to them. You can be as specific or broad in the nodes you're looking for to only attach events to very specific nodes or elements on the chart.
For completeness sake, here is a short example of how to attach events that log the value of a data point when clicked upon to the console using jQuery:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
You should, however, make sure that the events attach only when the chart is created or drawn if you want to ensure the data points are on the page, which can be triggered by the "created" or "draw" events:
var chart = new Chartist.Line(...);
// attach an event handler to the "created" event of the chart:
chart.on("created", function () {
// attach the necessary events to the nodes:
$('.ct-chart-line .ct-point').click(function () {
var val = $(this).attr("ct:value");
console.log(val);
});
});

Using the same InfoWindow for two AttributeInspectors

I've got two editable feature layers in my application, and I'm trying to attach the appropriate attribute inspector depending on which feature layer my user is trying to edit.
I create the Attribute Inspectors for both feature layers when my application loads and then attach the appropriate attribute inspector to the map's InfoWindow when the user is trying to edit a feature layer.
All works well, until the user tries to edit another feature layer. When I try and attach a different attribute inspector to the infowindow, it just comes up blank.
Here's roughly what I'm doing:
// AttributeEditor1 for FeatureLayer1 in Class1
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor1();
},
configureAttributeEditor1: function() {
this.attributeEditor1 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor1.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 1
attachEditor1: function() {
this.map.infoWindow.setContent(this.attributeEditor1.domNode);
this.map.infoWindow.resize(350, 240);
},
// AttributeEditor2 for FeatureLayer2 in Class2
constructor: function(options) {
this.options = lang.mixin(this.options, options);
this.map = options.map;
this.configureAttributeEditor2();
},
configureAttributeEditor2: function() {
this.attributeEditor2 = new AttributeInspector({
layerInfos: layerInfos
}, domConstruct.create("div"));
// here I add a Save and Delete button and various event handlers
this.attributeEditor2.startup();
},
// I call this when I know that the user wants to edit FeatureLayer 2
attachEditor2: function() {
this.map.infoWindow.setContent(this.attributeEditor2.domNode);
this.map.infoWindow.resize(350, 240);
},
Thanks in advance.
When you update the content of infoWindow using map.infoWindow.setContent, it destroys the previous content and then updated the new content. So basically your AttributeInspector1 will be destroyed when you updated the info window with AttributeInspector2.
You need not create multiple AttributeInspector, while working on multiple FeatureLayer. The layerInfos property is an array type, you could set upd multiple layers.
But, I guess you have different needs/actions to be taken when you switch between layers. The best thing you could do is to either create new AttributeInspector every time you switch, or just update the layerInfos and save and delete events. Make sure you remove the previous save and delete event handles.

dijit.CheckedMenuItem - Changing the checked value in runtime

This is how I create the dropdown menu with checkboxes using dijit.
layerList.reverse();
var menu = new dijit.Menu({
id : 'layerMenu'
});
dojo.forEach(layerList, function(layer) {
menu.addChild(new dijit.CheckedMenuItem({
label : layer.title,
id : layer.title.replace(" ",""),
checked : layer.visible,
onChange : function(evt) {
if (layer.layer.featureCollection) {
//turn off all the layers in the feature collection even
//though only the main layer is listed in the layer list
dojo.forEach(layer.layer.featureCollection.layers, function(layer) {
layer.layerObject.setVisibility(!layer.layerObject.visible);
});
} else {
layer.layer.setVisibility(!layer.layer.visible);
}
}
}));
});
var button = new dijit.form.DropDownButton({
label : i18n.tools.layers.label,
id : "layerBtn",
iconClass : "esriLayerIcon",
title : i18n.tools.layers.title,
dropDown : menu
});
dojo.byId('webmap-toolbar-center').appendChild(button.domNode);
I can access the individual dijit.CheckedMenuItem at runtime when the onChange event fired because I know their id. Since dijit does not has a RadioButton for MenuItem, is there a way I can change the checked status in runtime. Using "this.Id" and "evt", I can know which one is being check/uncheck by the user. Technically I can try to uncheck the other checked items if necessary to simulate the radio button behavior.
Can someone tell me how I can check/uncheck dijit.CheckedMenuItem in runtime? What properties and functions I need to call?
You should be able to just set checked to false on the other CheckedMenuItem widgets
checkedMenuItemWidget.set('checked',false)
To uncheck any given checkedMenuItem.

Dojo/Dijit TitlePane

How do you make a titlePane's height dynamic so that if content is added to the pane after the page has loaded the TitlePane will expand?
It looks like the rich content editor being an iframe that is loaded asynchronously confuses the initial layout.
As #missingno mentioned, the resize function is what you want to look at.
If you execute the following function on your page, you can see that it does correctly resize everything:
//iterate through all widgets
dijit.registry.forEach(function(widget){
//if widget has a resize function, call it
if(widget.resize){
widget.resize()
}
});
The above function iterates through all widgets and resizes all of them. This is probably unneccessary. I think you would only need to call it on each of your layout-related widgets, after the dijit.Editor is initialized.
The easiest way to do this on the actual page would probably to add it to your addOnLoad function. For exampe:
dojo.addOnLoad(function() {
dijit.byId("ContentLetterTemplate").set("href","index2.html");
//perform resize on widgets after they are created and parsed.
dijit.registry.forEach(function(widget){
//if widget has a resize function, call it
if(widget.resize){
widget.resize()
}
});
});
EDIT: Another possible fix to the problem is setting the doLayout property on your Content Panes to false. By default all ContentPane's (including subclasses such as TitlePane and dojox.layout.ContentPane) have this property set to true. This means that the size of the ContentPane is predetermined and static. By setting the doLayout property to false, the size of the ContentPanes will grow organically as the content becomes larger or smaller.
Layout widgets have a .resize() method that you can call to trigger a recalculation. Most of the time you don't need to call it yourself (as shown in the examples in the comments) but in some situations you have no choice.
I've made an example how to load data after the pane is open and build content of pane.
What bothers me is after creating grid, I have to first put it into DOM, and after that into title pane, otherwise title pane won't get proper height. There should be cleaner way to do this.
Check it out: http://jsfiddle.net/keemor/T46tt/2/
dojo.require("dijit.TitlePane");
dojo.require("dojo.store.Memory");
dojo.require("dojo.data.ObjectStore");
dojo.require("dojox.grid.DataGrid");
dojo.ready(function() {
var pane = new dijit.TitlePane({
title: 'Dynamic title pane',
open: false,
toggle: function() {
var self = this;
self.inherited('toggle', arguments);
self._setContent(self.onDownloadStart(), true);
if (!self.open) {
return;
}
var xhr = dojo.xhrGet({
url: '/echo/json/',
load: function(r) {
var someData = [{
id: 1,
name: "One"},
{
id: 2,
name: "Two"}];
var store = dojo.data.ObjectStore({
objectStore: new dojo.store.Memory({
data: someData
})
});
var grid = new dojox.grid.DataGrid({
store: store,
structure: [{
name: "Name",
field: "name",
width: "200px"}],
autoHeight: true
});
//After inserting grid anywhere on page it gets height
//Without this line title pane doesn't resize after inserting grid
dojo.place(grid.domNode, dojo.body());
grid.startup();
self.set('content', grid.domNode);
}
});
}
});
dojo.place(pane.domNode, dojo.body());
pane.toggle();
});​
My solution is to move innerWidget.startup() into the after advice to "toggle".
titlePane.aspect = aspect.after(titlePane, 'toggle', function () {
if (titlePane.open) {
titlePane.grid.startup();
titlePane.aspect.remove();
}
});
See the dojo/aspect reference documentation for more information.