I am trying to implement some drag and drop functionallity from a Tree Panel to a View but I have not been able to do this. I am new using ExtJs and maybe I am doing something wrong.
I have my tree defined like this:
var treeMeasures = Ext.create('Ext.tree.Panel', {
id: 'treeMeasuresPanel',
title: 'Measures',
region: 'north',
store: dsMeasures,
rootVisible: true,
width: '100%',
height: '50%',
useArrows: true,
enableDD: true,
allowDrop: false,
collapsible: true,
border: 0,
style: 'border-right:1px solid #99BCE8;border-top:none;border-left:none;border-bottom: none;',
viewConfig: {
listeners: {
render: initializeFieldsDragZone
},
plugins: {
ptype: 'treeviewdragdrop',
ddGroup: 'fieldsToAreas',
enableDrag: true,
enableDrop: false,
containerScroll: true
}
}
});
The initializeFieldsDragZone function:
function initializeFieldsDragZone(v, record, item, index, evt, eOpts) {
v.dragZone = Ext.create('Ext.dd.DragZone', v.getEl(), {
getDragData: function (e) {
var sourceEl = e.getTarget(v.itemSelector, 10), d;
if (sourceEl) {
d = sourceEl.cloneNode(true);
d.id = Ext.id();
return v.dragData = {
sourceEl: sourceEl,
repairXY: Ext.fly(sourceEl).getXY(),
ddel: d,
controlData: v.getRecord(sourceEl).data
};
}
},
// Provide coordinates for the proxy to slide back to on failed drag.
// This is the original XY coordinates of the draggable element.
getRepairXY: function () {
return this.dragData.repairXY;
}
});
}
The View:
var filterAreaView = Ext.create('Ext.view.View', {
store: dsFilterArea,
tpl: "",
ddGroup: 'fieldsToAreas',
bodyStyle: {
background: 'ffffff'
},
listeners: {
render: initializeAreasDropZone
}
});
And the initializeAreasDropZone function is:
function initializeAreasDropZone(area) {
var view = area.getEl();
view.dropZone = Ext.create('Ext.dd.DropZone', area.el, {
getTargetFromEvent: function (e) {
return e.getTarget('.x-grid-row');
},
onNodeEnter: function (target, dd, e, data) {
},
onNodeOut: function (target, dd, e, data) {
},
onNodeOver: function (target, dd, e, data) {
return true;
},
onNodeDrop: function (target, dd, e, data) {
// My Code
return true;
}
});
}
And the problem is that when I drag the node from the tree and try to drop into the view nothing happens.
Does anyone knows if I am doing something wrong?
Thanks,
Alberto
I think you may be overthinking this. I created a working model of DD between two panels (Ext.tree.Panel) each containing a root, with multiple folders, and multiple leaves in each folder. Simply by adding the plugin to each tree enabled DD:
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
ddGroup: 'myDDGroup',
appendOnly: true,
sortOnDrop: true,
containerScroll: true
}
},
After doing this, when I click and drag a leaf from one tree to the other, it dutifully adds the leaf to the target folder upon release of the mouse button. I didn't have to do anything else as far as monitoring events.
if you use TreePanel for Drag Zone, i think we don't need to create function initializeFieldsDragZone, just use plugin "treeviewdragdrop".
The problem from your code is initializeAreasDropZone must have ddgroup same as the plugin:
function initializeAreasDropZone(area) {
var view = area.getEl();
view.dropZone = Ext.create('Ext.dd.DropZone', area.el, {
getTargetFromEvent: function (e) {
return e.getTarget('.x-grid-row');
},
onNodeEnter: function (target, dd, e, data) {
},
onNodeOut: function (target, dd, e, data) {
},
onNodeOver: function (target, dd, e, data) {
return true;
},
onNodeDrop: function (target, dd, e, data) {
console.log(data);
},
ddGroup: 'fieldsToAreas'
});
}
cheers
Related
Is there a solution to extend the KeyMap of the ItemSelector?
I would like to add a keymap(like pageUp and pageDown keyEvent in itemselector) that when I press the letter 'A-Z' will take me to the item that starts with the letter pressed and select it.
You can use the following override (fiddle sample) to achieve it. It will not work correctly on view sore reload. And you will have to define the record search record field. In case of complicated view templates you can remove hardcoded search function and use it as a setting.
Ext.define('overrides.view.NavigationModel', {
override: 'Ext.view.NavigationModel',
searchRecordField: false,
initKeyNav: function (view) {
var me = this;
// Drive the KeyNav off the View's itemkeydown event so that beforeitemkeydown listeners may veto.
// By default KeyNav uses defaultEventAction: 'stopEvent', and this is required for movement keys
// which by default affect scrolling.
var keyNavConfig = {
target: view,
ignoreInputFields: true,
eventName: 'itemkeydown',
defaultEventAction: 'stopEvent',
processEvent: me.processViewEvent,
up: me.onKeyUp,
down: me.onKeyDown,
right: me.onKeyRight,
left: me.onKeyLeft,
pageDown: me.onKeyPageDown,
pageUp: me.onKeyPageUp,
home: me.onKeyHome,
end: me.onKeyEnd,
space: me.onKeySpace,
enter: me.onKeyEnter,
A: {
ctrl: true,
// Need a separate function because we don't want the key
// events passed on to selectAll (causes event suppression).
handler: me.onSelectAllKeyPress
},
F: me.onAlphabetKeyPress,
scope: me
};
if(this.view.searchRecordField) {
keyNavConfig = Ext.Object.merge(keyNavConfig, this.getAdditionalKeyNav());
}
me.keyNav = new Ext.util.KeyNav(keyNavConfig);
},
getAdditionalKeyNav: function() {
var keyNav = {};
this.view.getStore().each(function(record) {
var firstLetter = record.get(this.view.searchRecordField)[0].toUpperCase();
if(!keyNav[firstLetter]) {
keyNav[firstLetter] = this.onAlphabetKeyPress
}
}, this);
return keyNav;
},
onAlphabetKeyPress: function(keyEvent) {
const key = keyEvent.event.key;
var foundRecordIndex = this.view.getStore().findBy(function(record) {
return record.get('title').toLowerCase().indexOf(key) === 0;
}, this);
if(foundRecordIndex > -1) {
this.setPosition(foundRecordIndex, keyEvent);
}
}
});
Ext.application({
name: 'Fiddle',
launch: function () {
Ext.define('ListItem', {
extend: 'Ext.data.Model',
fields: [{
name: 'src',
type: 'string'
}, {
name: 'caption',
type: 'string'
}]
});
Ext.create('Ext.data.Store', {
id: 'ListItemsStore',
model: 'ListItem',
data: [{
title: "One"
}, {
title: "Two"
}, {
title: "Three"
}, {
title: "Four"
}, {
title: "Three"
}, ]
});
var imageTpl = new Ext.XTemplate(
'<tpl for=".">',
'<div style="margin-bottom: 10px;" class="thumb-wrap">',
'<span>{title}</span>',
'</div>',
'</tpl>'
);
Ext.create('Ext.view.View', {
store: Ext.data.StoreManager.lookup('ListItemsStore'),
tpl: imageTpl,
itemSelector: 'div.thumb-wrap',
emptyText: 'No images available',
// Search Record Field
searchRecordField: 'title',
renderTo: Ext.getBody()
});
}
});
Code mirror is not bind in extjs 6.
I already tried to subcribe the get and set methods, only the set works, when the component is opened the value is set, but when it changes the value of the codemirror, it does not bind with the value
My component:
Ext.define('Ext.form.field.CodeMirror', {
extend: 'Ext.form.field.TextArea',
alias: 'widget.codemirror',
getValue: function () {
var me = this;
if (me.codeEditor) {
return me.codeEditor.getValue();
}
},
setValue: function (value) {
this.codeEditor.setValue(value);
},
listeners: {
afterrender: function (textarea) {
var me = this;
me.codeEditor = CodeMirror.fromTextArea(textarea.inputEl.dom, {
mode: "xml",
htmlMode: true,
theme: "default",
lineNumbers: true,
lineWrapping: true,
matchTags: {
bothTags: true
},
autoCloseTags: true,
extraKeys: {
"F11": function (cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function (cm) {
if (cm.getOption("fullScreen")) {
cm.setOption("fullScreen", false);
}
}
},
foldGutter: {
rangeFinder: new CodeMirror.fold.combine(CodeMirror.fold.indent)
},
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
});
}
}
});
Use the component (Default bind is value on Extjs):
xtype: 'codemirror',
name: 'xml',
bind: '{model.arquivoNfceWrapper.xml}',
listeners: {
afterrender: function (textarea) {
var me = this;
me.codeEditor = CodeMirror.fromTextArea(textarea.inputEl.dom, {
mode: "xml",
htmlMode: true,
theme: "default",
lineNumbers: true,
lineWrapping: true,
matchTags: {
bothTags: true
},
autoCloseTags: true,
extraKeys: {
"F11": function (cm) {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Esc": function (cm) {
if (cm.getOption("fullScreen")) {
cm.setOption("fullScreen", false);
}
}
},
foldGutter: {
rangeFinder: new CodeMirror.fold.combine(CodeMirror.fold.indent)
},
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"]
});
me.codeEditor.on('change', function (cMirror) {
me.updateBindValue(cMirror.getValue());
});
me.codeEditor.setValue(me.getBindValue());
}
},
getBindValue: function () {
return this.bind.value.getValue();
},
updateBindValue: function (value) {
this.bind.value.setValue(value)
}
I created a Custom ListItem, which has some ChildWidgets. One of these is a Combobox Widget.
I want to set the Model by a Controller, for this I used qx.data.controller.List.
With the bindItem and controller.bindProperty("", "model", null, item, index); I bind my Model to the List.
My Problem is, that I have one Property in my Model (text) which should be binded to the Combobox Value Property.
I tried controller.bindProperty("text", "value", null, item.getChildControl("combobox"), index); but I didn't get it to work.
What am I doing wrong?
Here's the final answer to your question, including the ability to delete items:
qx.Class.define("CustomListItem", {
extend: qx.ui.core.Widget,
include: [qx.ui.form.MModelProperty],
properties: {
isDistribution: {
init: true,
check: "Boolean",
event: "distributionChange"
},
isFilter: {
init: false,
check: "Boolean",
event: "symbolEvent"
},
isColumn: {
init: false,
check: "Boolean",
event: "symbolEvent"
},
isRow: {
init: false,
check: "Boolean",
event: "changeRow"
},
isFilterPatientCases: {
init: true,
check: "Boolean",
event: "symbolEvent"
},
isShow: {
init: true,
check: "Boolean",
event: "symbolEvent"
},
isUnkownFilter: {
init: true,
check: "Boolean",
event: "symbolEvent"
},
value: {
init: "",
event: "changeValue"
}
},
members: {
_createChildControlImpl: function(id) {
var control;
switch (id) {
case "alertimage":
control = new qx.ui.basic.Image();
control.setWidth(16);
this._add(control);
break;
case "suchecombobox":
control = new qx.ui.form.ComboBox();
this._add(control, {
flex: 1
});
break;
case "deletebutton":
control = new qx.ui.form.Button("Del");
control.setMaxWidth(40);
this._add(control);
break;
case "imagecomposite":
control = new qx.ui.container.Composite(new qx.ui.layout.HBox(0));
this._add(control);
break;
}
return control || this.base(arguments, id);
}
},
construct: function() {
this.base(arguments);
this._setLayout(new qx.ui.layout.HBox(0));
this._showImage = new qx.ui.basic.Image();
this._showImage.setMaxHeight(25);
this._showImage.setMaxWidth(25);
this._showImage.setScale(true);
this._filterImage = new qx.ui.basic.Image();
this._filterImage.setMaxHeight(25);
this._filterImage.setMaxWidth(25);
this._filterImage.setScale(true);
this._createChildControl("alertimage");
this._createChildControl("suchecombobox");
this._createChildControl("imagecomposite");
this._createChildControl("deletebutton");
this.getChildControl("deletebutton").addListener("execute", function(e) {
var itemModel = this.getModel();
data.remove(itemModel);
}, this);
}
});
var dataRaw = {
isColumn: false,
isFilter: false,
isFilterPatientCases: true,
isRow: true,
isShow: true,
isUnkownFilter: true,
position: "row",
queryText: "Dia:I50_:_Herzinsuffizienz",
textType: ""
};
var data = qx.data.marshal.Json.createModel([dataRaw]);
var list = new qx.ui.form.List();
list.setWidth(200);
var listController = new qx.data.controller.List(null, list);
listController.setDelegate({
bindItem: function(controller, item, index) {
controller.bindProperty("", "model", null, item, index);
controller.bindProperty("queryText", "value", null, item.getChildControl("suchecombobox"), index);
controller.bindProperty("isFilter", "isFilter", null, item, index);
controller.bindProperty("isColumn", "isColumn", null, item, index);
controller.bindProperty("isRow", "isRow", null, item, index);
controller.bindProperty("isFilterPatientCases", "isFilterPatientCases", null, item, index);
controller.bindProperty("isShow", "isShow", null, item, index);
controller.bindProperty("isUnkownFilter", "isUnkownFilter", null, item, index);
controller.bindProperty("queryText", "value", null, item, index);
},
createItem: function() {
return new CustomListItem();
}
});
listController.setModel(data);
listController.addListener("changeSelection", function(e) {
console.log(e.getData().toArray());
}, this);
var doc = this.getRoot();
var button = new qx.ui.form.Button("AddItem");
var newIndex = 1;
button.addListener("execute", function(e) {
dataRaw.queryText = "New (" + (newIndex++) + ")";
data.append(qx.data.marshal.Json.createModel([dataRaw]));
}, this);
doc.add(list, {
left: 0,
top: 0
});
doc.add(button, {
left: 200,
top: 0
});
I'm working on a project which uses Highcharts and Angularjs and fetches data using SignalR. The problem is the pie chart initializes correctly but can not update the diagram with the data comes from server. here is my code:
'use strict';
angular.module('mbCharts').directive('mbGauge', [
'mbWebMetricsService',
function (mbWebMetricsService) {
return {
//
// scope is inherited from the widget using this directive
//
templateUrl: '/ext-modules/mbCharts/mbGaugeTemplate.html',
link: function (scope, el, attrs) {
Highcharts.chart(el[0], {
chart: {
type: 'pie'
},
title: {
text: scope.title
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
data: [{
name: "Microsoft Internet Explorer",
y: 100
}, {
name: "Chrome",
y: 0,
sliced: true,
selected: true
}]
}]
});
// locate the widget showing this gauge
var widget = el.closest('.gridster-item');
// monitor the widget's size
widget.resize(function () {
//if (scope.chart != null) {
// scope.chart.chartWidth = widget.width();
// scope.chart.chartHeight = widget.height();
//}
});
//scope.title = mbWebMetricsService.getTitleForMetric(scope.metric);
scope.title = "CPU percentage";
scope.initialized = false;
scope.$on('mbWebMetricsService-received-data-event', function (evt, data) {
var val = Math.round(data[scope.metric]);
scope.chart.series[0].data[0].y = val;
scope.chart.series[0].data[1].y = 100 - val;
});
}
};
}
]);
The problem is how you want to update data. It's not about changing options in chart object, but using proper API. To update points, use chart.series[index].data[pointsIndex].update().
So in your case, first store a chart object:
var myChart = new Highcharts.Chart(el[0], { ... });
Then update points:
scope.$on('mbWebMetricsService-received-data-event', function (evt, data) {
var val = Math.round(data[scope.metric]);
myChart.series[0].data.update(val);
myChart.series[0].data.update(100 - val);
});
I have a scenario where I need to show a pie-chart in a popup modal (used ui-bootstrap modal). I used c3.js for my pie-chart requirement (inside a directive).
The pie-chart is not loading inside the pop up. But to my surprise when I tried to debug the issue when I opened the console it is loading. When I re-size the window it is loading.
How can i fix this issue?
'use strict';
angular.module('App')
.directive('pieChartDirective', function() {
return {
restrict: 'A',
scope: {
chartdata: '=',
},
link: function(scope, elem, attrs) {
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
}
};
});
Html:
<div pie-chart-directive chartdata="oChartData">
<div id="chart"></div>
</div>
Are you shure, that you include your directive properly in your html code as
<div pie-chart-directive></div>
Maybe you have to change your restriction to 'E' to use your directive as a tag elment
<pie-chart-directive chartdata="myData"></pie-chart-directive>
The reason could be, that at the moment you try to generate the chart, your '#chart' div isn't yet present in the dom tree. Therefore you have to resize to trigger a new draw. Try to wait until the dom is loaded
$('#chart').ready(function() {
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
});
I got it by giving size property:
link: function(scope, elem, attrs) {
var chart = c3.generate({
bindto: '#chart',
size: {
width:400,
height:350
},
data: {
columns: [
['Javascript', scope.chartdata.Javascript],
['HTML', scope.chartdata.HTML],
['Css', scope.chartdata.Css],
['Angular', scope.chartdata.Angular],
['Bootstrap', scope.chartdata.Bootstrap],
['Jquery', scope.chartdata.Jquery],
['Communication', scope.chartdata.Communication]
],
type: 'pie',
},
legend: {
show: false
},
tooltip: {
format: {
value: function(value, ratio, id, index) {
return value;
}
}
}
});
}