Extjs 6 adding chart mouse listener - javascript

I am making a bar chart, and I want to so that clicking it would toggle between shortening long labels and not. However the listener does not seem to be working. I googled around and found a lot of people talking about it being a bug, however those posts are on old version (5) and I don't know if that still holds. Here is complete chart class:
Ext.define ('SenchaApp.view.barchart.BarChart', {
extend : 'Ext.chart.CartesianChart',
requires : [ 'SenchaApp.store.Personnel' ],
xtype : 'bar_chart',
reference : 'bar_chart',
itemId : 'bar_chart',
plugins: {
ptype: 'chartitemevents',
moveEvents: true
},
store : {
type : 'personnel'
},
label_length : 10,
shorten_labels : true,
flipXY : true,
axes: [{
type: 'numeric',
position: 'bottom',
fields: 'phone',
title: {
text: 'Inventory',
fontSize: 15
},
grid: {
odd: {
fillStyle: 'rgba(255, 255, 255, 0.06)'
},
even: {
fillStyle: 'rgba(0, 0, 0, 0.03)'
}
},
}, {
type: 'category',
position: 'left',
title: {
text: 'People',
fontSize: 15
},
fields: 'name',
label : {
hidden : false
},
renderer : function (axis, data) {
var str = data;
var chart = axis.getChart();
if (str.length > chart.label_length && chart.shorten_labels) {
str = str.substring(0, chart.label_length-1)+"...";
}
return str;
},
style: {
estStepSize : 1
}
}],
series: {
type: 'bar',
xField: 'name',
yField: 'phone',
listeners: {
itemtap : function(series) {
var chart = series.getChart();
alert('mouse down event');
chart.shorten_labels = !chart_shorten_labels;
}
}
},
initComponent : function () {
this.callParent(arguments);
this.axes[1].override_label_bbox (true, 2);
}
})

First step if a listener doesn't work as expected: read the listener docs carefully:
Fires when a tap event occurs on a series item. Note: This event requires the Ext.chart.plugin.ItemEvents plugin be added to the chart.
Second step is a look in the Sencha code to find the following:
chart.addElementListener({
click: handleEvent,
dblclick: handleEvent,
mousedown: handleEvent,
mousemove: handleEvent,
mouseup: handleEvent,
mouseover: handleEvent,
mouseout: handleEvent,
// run our handlers before user code
priority: 1001,
scope: this
});
together with
handleEvent: function (e) {
...
chart.fireEvent('item' + e.type, chart, item, e);
item.series.fireEvent('item' + e.type, item.series, item, e);
tap event isn't registered, so itemtap cannot be fired at all. If you bind to itemclick, on the other hand...
It's working!

Related

Extjs: how to render a progress bar with a tooltip in a grid

I have a grid and one of the columns prepresents a progress bar. I need to set a tooltip "Progress 4 of 10" over the progress bar. Initially it was like this:
columns: [
{
translatable: {
text: 'progress'
},
tdCls: 'highlight',
xtype: 'widgetcolumn',
dataIndex: 'progress',
widget: {
cls: 'percentage-bar',
text: ' ',
align: 'center',
xtype: 'progressbar',
defaultListenerScope: true,
listeners: {
afterrender: function (bar) {
var tip = Ext.create('Ext.tip.ToolTip', {
target: bar,
html: Dict.translateAndReplace(
'step',
[
bar.getWidgetRecord().get('current_step') === 0 ? 1 : bar.getWidgetRecord().get('current_step'),
bar.getWidgetRecord().get('total_steps')
],
'%d'
)
});
if (bar.getValue() === 1) {
bar.addCls('progress-complete')
}
},
},
},
width: 100
},
The issue is - it works only for a single page. When there are several pages or I apply filtering or sorting, event "afterrender" is not triggered. So it's triggred only then the grid is loaded, not the content. I need either to change to target element or use renderer. I tried to play arroung with renderer, but also stuck. How to get current cell container?
columns: [
{
translatable: {
text: 'progress'
},
tdCls: 'highlight',
xtype: 'widgetcolumn',
dataIndex: 'progress',
width: 100,
widget: {
cls: 'percentage-bar',
text: ' ',
align: 'center',
xtype: 'progressbar',
defaultListenerScope: true,
},
renderer: function (value, metaData, record) {
let HowToGetTheContainer = "?????";
var tip = Ext.create('Ext.tip.ToolTip', {
target: HowToGetTheContainer,
html: Dict.translateAndReplace(
'step',
[
record.get('current_step') === 0 ? 1 : record.get('current_step'),
record.get('total_steps')
],
'%d'
)
});
if (value === 1) {
Ext.down().addCls('progress-complete')
}
}
},
How to get that variable "HowToGetTheContainer"?
Within the renderer function, you can add a tooltip with this code (this works on other column types as well, not only on widgetcolumn):
metaData.tdAttr = Ext.String.format('data-qtip="{0}"', 'This is my tooltip here');
This was not a part of your question, but to customise the widget in the widgetcolumn, for example to add the progress-complete style, instead of using Ext.down(), you can use the onWidgetAttach function of the column:
columns: [{
xtype: 'widgetcolumn',
onWidgetAttach: function(col, widget, record) {
widget.setIconCls('xxx')
widget.addCls('xxx')
widget.setText('xxx');
// etc
},
}]

Extjs application is crashed when dynamically adding one defective item

When an item is dynamically added to the created component, if there is an error in the item, the application crashes.
This problem does not exist when the item is not created.
Ext.define('Test', {
extend: 'Ext.panel.Panel',
initComponent: function () {
// make error
// this.callParent();
}
});
Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
width: 400,
height: 300,
title: 'Application',
layout: {
type: 'vbox',
align: 'center',
},
defaults: {
margin: 10,
},
items: [{
xtype: 'button',
iconCls: 'x-fa fa-cog',
handler: function (btn) {
let mainPanel = btn.up('panel'),
item = Ext.create('Test');
// bug
mainPanel.add(item);
},
}],
});
sencha fiddle
Strange problem, because you are trying to find out if the developer did something wrong during runtime.
But anyways - here is one solution for your problem:
handler: function (btn) {
let mainPanel = btn.up('panel'),
item = Ext.create('Test');
// bug testing
if(Ext.isDefined(item) && Ext.isObject(item.layout)) {
mainPanel.add(item);
} else {
console.error(item.id + ' could not be added because of an error I made.')
}
},

Panel Appearance After Clicking On Text

I've just started working with Sencha Touch over the past couple days and I've run into a few questions. The main one is, when working with anything that doesn't regularly have user click interaction (titlebar, html text, etc for some random examples), is it possible to click on things like this and get a panel to appear.
I know that with buttons and other things, you have a tap, itemtap, etc, but I'm not sure about instances like this. Any help would be appreciated with examples.
Yes you can. Check out my blog post here: http://www.senchahackers.com/touch/multiple-tap-listeners-one-xtemplate/ that explains exactly how to do that.
Basically you can listen for a tap event on any element, as long as you add it to the list of 'delegates'
In your view:
listeners: {
tap: {
element: 'element',
delegate: '.app-box, .doc-box, .bubble-holder',
fn: function(e){
var url = e.target.name,
divClassName = e.delegatedTarget.className,
appbox = "app-box",
docbox = "doc-box",
bubble = "bubble-holder";
console.log(divClassName);
switch(divClassName){
case docbox :
//lets say you have an element '.doc-box' that you want to click and show the panel
// show the panel, which is a separate file, shown below
var profileController = YourApp.getController('YourController');
//call the showProfilePanelPopup() method in your controller, passing in this as the element that shows it
profileController.showProfilePanelPopup(this);
break;
case appbox :
alert(appbox);
break;
case bubble :
alert(bubble);
break;
}
}
}
}
Then in your controller:
extend: 'Ext.app.Controller',
config: {
refs: {
profilePanelPopup: {
autoCreate: true,
selector: '#profilePanelPopup',
xtype: 'profilePanelPopup'
}
}
},
showProfilePanelPopup: function(btn, action, values) {
var me = this;
var popup = me.getProfilePanelPopup();
popup.showBy(btn);
popup.on('hide', function () {
popup.destroy();
}, this);
}
Assuming you some Panel in your views directory like this:
Ext.define('App.view.ProfileNowPop', {
extend : 'Ext.Panel',
alias: 'widget.profileNowPop',
xtype: 'profilePanelPopup',
config: {
height: (Ext.os.deviceType != "Desktop") ? "35%" : 253,
cls:'profilePop',
left: '1%',
padding: 0,
top: '1%',
width: (Ext.os.deviceType != "Desktop") ? '40%' : '36%',
hideOnMaskTap: true,
modal: {
cls:'opaquemask'
},
scrollable: false,
store: 'ProfilePopStore',
model: 'App.model.ProfilePopModel',
items:[
{
xtype: 'fieldset',
items: [
{
xtype: 'textfield',
id: 'gradePopField0',
cls: 'gradePopField',
style: 'background: #f7f7f5',
listeners: {
initialize: function(ele, eOpts) {
this.setReadOnly(true);
}
}
}
]
}
]
},
initialize: function() {
this.callParent(arguments);
}
});

Show Row Details as a Popup/ToopTip form on Mouse Hover for each row in KendoUI Grid

I have a grid populated with data and
i want to show only 3 or 2 columns and hide rest of columns cause the grid goes very wide.
when the mouse is hovered over a row i want to show all the columns of that row as as popup /tooltip form.
Please help me with this. I searched a lot and only found out Editable popup and with button click not with hover.
function PopulateGrid() {
$("#recentNews").kendoGrid({
columns: [
{ field: 'Date', title: 'Date', width: 80,
template: '#=kendo.toString(toDate(NewsDate), "yyyy/MMM/dd") #'
},
{ field: 'TradeTime', title: 'Time', width: 60,
template: '#=kendo.toString(toDate(NewsTime), "hh:mm:ss") #'
},
{ field: 'Title', title: 'Description', width: 200 },
{ field: 'Country', title: 'Country', width: 40 },
{ field: 'Economy', title: 'Economoy', width: 40 }
],
dataSource: {
transport: {
read: {
url: 'Home/GetNews',
dataType: "json",
type: "POST"
}
},
schema: {
data: function (data) {
return data.data;
},
total: function (data) {
return data.total;
}
},
pageSize: 100
},
// change: onChange,
// dataBound: onDataBound,
dataBound: HoverOnGrid,
pageable: true,
sortable: true,
scrollable: true,
height: 565,
width: 2000
});
}
There are two separate questions about what you are trying to implement:
Bind hover to the Grid rows (easy).
Generate a popup / tooltip that shows the rest of the columns (easy but requires some amount of coding).
Since it seems that you have already defined a function called HoverOnGrid lets write it as:
function HoverOnGrid() {
$("tr", "#recentNews").on("mouseover", function (ev) {
// Invoke display tooltip / edit row
var rowData = grid.dataItem(this);
if (rowData) {
showTooltip(rowData);
}
});
}
where grid is:
var grid = $("#recentNews").kendoGrid({
...
}).data("kendoGrid";
Now, the tricky question, how to show a tooltip / popup... There is no predefined way of doing it, you should do it by yourself. The closes that you can get is defining HoverOnGrid as:
function HoverOnGrid() {
$("tr", "#recentNews").on("click", function (ev) {
grid.editRow(this);
})
}
and the Grid initialization say:
editable: "popup",
But this opens a popup but with fields on edit mode (something that you can hack defining in the dataSource.schema.model that all fields are not editable:
model: {
fields: {
Date: { editable: false },
TradeTime: { editable: false },
Title: { editable: false },
Country: { editable: false },
Economy: { editable: false }
}
}
But it still shows update and cancel buttons in the popup.
So, my recommendation is writing a piece of code that creates that tooltip.
EDIT: For hiding the tooltip you should first intercept the mouseout event:
$("tr", "#recentNews").on("mouseout", function (ev) {
// Hide Tooltip
hideTooltip();
});
where hideTooltip might be something as simple as:
var tooltipWin = $("#tooltip_window_id").data("kendoWindow");
tooltipWin.close()
assuming that you are always using the same id for the tooltip (in this example, tooltip_window_id).

Extjs 4, Event handling, scope, custom components

I have following problem. I have grid with tbar. Inside tbar I have number of Ext.form.field.Trigger.
When the user click on trigger button I want to filter the store using function that is provided with grid. I want to define functionality of triggerclick inside defined class, so I can reuse this component with different grid.
So, in short I want to find the panel where clicked component is placed and call panel function, or pass reference of panel to triggerclick, or fire an event with some parameter that will calculated based on where the button was clicked, or maybe there is a better method to accomplish this.
The code (FilterField -> extension of trigger):
Ext.define('GSIP.core.components.FilterField', {
extend: 'Ext.form.field.Trigger',
alias: 'widget.filterfield',
initComponent: function() {
this.addEvents('filterclick');
this.callParent(arguments);
},
onTriggerClick: function(e, t) {
//Ext.getCmp('gsip_plan_list').filterList(); - working but dont want this
//this.fireEvent('filterclick'); - controller cant see it,
//this.filterList; - is it possible to pass scope to panel or reference to panel
//e.getSomething() - is it possible to get panel via EventObject? smth like e.getEl().up(panel)
}
});
code of panel:
Ext.define('GSIP.view.plans.PlanReqList', {
extend: 'Ext.grid.Panel',
alias: 'widget.gsip_devplan_list',
id: 'gsip_plan_list',
title: i18n.getMsg('gsip.view.PlanReqList.title'),
layout: 'fit',
initComponent: function() {
this.store = 'DevPlan';
this.tbar = [{
xtype: 'filterfield',
id: 'filter_login',
triggerCls: 'icon-user',
//scope:this - how to pass scope to panel without defining onTriggerClick here
// onTriggerClick: function() {
// this.fireEvent('filterclick'); //working event is fired but controller cant see it
// this.filterList; //this is working but i dont want to put this code in every filterfield
// },
// listeners : {
// filterclick: function(btn, e, eOpts) { //this is working
// }
// },
}];
this.columns = [{
id: 'id',
header: "Id",
dataIndex: "id",
width: 50,
sortable: true,
filterable: true
}, {
header: "Name",
dataIndex: "name",
width: 150,
sortable: true,
filterable: true
}, {
header: "Author",
dataIndex: "author",
sortable: true,
renderer: this.renderLogin,
filterable: true
}];
this.callParent(arguments);
},
filterList: function() {
this.store.clearFilter();
this.store.filter({
property: 'id',
value: this.down("#filter_id").getValue()
}, {
property: 'name',
value: this.down("#filter_name").getValue()
});
},
renderLogin: function(value, metadata, record) {
return value.login;
}
});
part of code of Controller:
init: function() {
this.control({
'attachments': {
filesaved: this.scanSaved,
}
}, {
'scan': {
filesaved: this.attachmentSaved
}
}, {
'#filter_login': {
filterclick: this.filterStore //this is not listened
}
});
},
filterStore: function() {
console.log('filtering store');
this.getPlanListInstance().filter();
},
Controller can listen to anything. Just need to specify exactly what to. But I would fire events on the panel level - add this into your trigger handler:
this.up('panel').fireEvent('triggerclicked');

Categories

Resources