ExtJS5: TreePanel select event firing twice - extjs

I made a Fiddle test case to reproduce my problem: the select event is fired twice. Even the selectionchange does so. But the cellclick is fired only once.
I use ExtJS5.1.1 GPL.
NB: the Load button (on the left) has to be clicked first.

This looks like a bug...
An ugly workaround can be using buffer. You can set the listener like this:
select: {
buffer: 1,
fn: function(treepanel, record, index) {
console.log('select', index);
}
}

The listener is added to the events twice, this is a bug in Sencha Framework that relates to the locked/normal treegrid and is fixed in 5.1.2. It seems as if the listener is added once to the listener object of the locked grid and once to the listener object of the normal grid, and because both grids use the very same object, that object will contain the listener twice.
A quick fix seems to be to remove the select listener from the listener config and add it to one of the grids only:
Ext.ComponentQuery.query('viewport treepanel[isLocked=true]')[0].on('select', function(treepanel, record, index) {
console.log('select', index);
});

Related

How to Get keypress event in extjs charts

This is related to ExtJs 4.2 Charts.
I am stuck where i need to make selection of multiple columns in a column chart only when a user press ctrl key + column selection with mouse click. So, i couldn't find how to capture control key press event in itemclick event of chart.
Please send in your suggestions...
This is a shot at a direction you might take and not a definitive answer.
You might look at adding a couple listeners to the Panel or Viewport you are working with, add a keydown event and the keyup event, not sure if that will work, you might go so far as to add it to the DOM models window too. You see the problem I am seeing here is that you have to have focus first on something, and you will probably at least have the focus of the window, where if you, put this listener on the actual chart you have to focus there by clicking on the chart first and then selecting the key and then clicking again, kind of a lot of actions I would think and not intuitive.
Then set a global variable to true on the key press down and back to false on the key press up.
Then in the itemmousedown event that you also create on the charts Series so you can read the variable and use it as you intend.
here is what the listener should look like
series: [{
type: 'column',
...
listeners: {
itemmousedown: function(item, eOpts) {
.... // get your global variable here.
console.log(item);
console.log(eOpts);
}
},
I found a solution it is working fine but its a kind of workaround.
Here is the code snippet...
var bIsControlkeyPressed=false;
function setCtrlKey(event){
if (event.ctrlKey) {
bIsControlkeyPressed=true;
}else{
bIsControlkeyPressed=false;
}
alert(bIsControlkeyPressed)
}
<body onmousedown = "setCtrlKey(event)">hello</body>
When you click anywhere on page (body part i.e. 'hello' in this case), this code will set the global flag to true if ctrl key is also pressed else false is set. I know there are other ways this can be done but this approach works with IE8 also :)

Backbone delegateEvents not bubbling / propagating

Weird problem with event propagation in Backbone. Most people ask how to stop event propagation, but I'm struggling with getting my events to propagate!!
Here I have two View objects. The MainView which contains Item views and listens to click events to call run():
var MainView = Backbone.View.extend({
...
events: {
"click .item": "run" // works only if no click event in Item
},
render: {
// Item View object children
},
run: function() {
//run :)
}
});
Item view objects also listen to click events on themselves to toggle on/off behaviour:
var Item = Backbone.View.extend({
...
events: {
"click" : "toggle" // MainView click event works when this is removed
},
toggle: function() {
this.model.toggle();
}
});
The problem being that MainView.run() is not fired when the Item is clicked, while it has a click event for Item.toggle().
However, MainView.run() DOES fire if I remove the Item.toggle() click event. Leading me to the conclusion that the event is somehow forced to stop propagating, outside of my control.
How can I solve this problem? Am I missing something obvious, or is this unavoidable?
Thank you for any and all suggestions and answers :).
It appears that the click event in your item view isn't bound to a specific DOM object. It's possible that listening for a generic click event is overriding Backbone from listening for your specific .item click event. Try adding an ID or class name to your item view click event to remove any ambiguity.
var Item = Backbone.View.extend({
...
events: {
"click .some-class" : "toggle" // This should fix your problem
},
...
Jay B. Martin answered the question.
The problem is that the View calls this.model.toggle();
The toggle() function sets some variables which the MainView is listening for, causing a render() event to fire.
When MainView calls render(), the Item views are in turn removed, rendered and added to the DOM. This loses the bound event to the DOM element using events: {}.
Instead _.bind() or _.bindAll() should have been used to permanently bind the events, regardless of the context / state of the element bound to in the DOM.
Original comment answer:
#Dan0, sorry I'm a little confused about how toggle could be the root of your issue. I think it's a symptom of the context ambiguity created by binding to an implicit DOM element in a nested view. Once toggle is called, the click event loses the context to which it was initially bound (i.e., this.el). The idiomatic way of solving this is to either a) pass an explicit element so that it can rebind on subsequent events, or b) use _.bind or _.bindAll, so that the click event is permanently bound to the itemview as the context changes. – Jay B. Martin Aug 10 at 23:46

How to programmatically fire the check change event of a ExtJS 4.1 checkbox tree panel

I have a ExtJs 4.1 check box tree panel. When I check or uncheck any node, check change event for the tree is fired. How can I programmatically fire this event.
One way I can think of is to use following code. But this code is not firing every time :-(
this.fireEvent('checkchange', node, true, opts);
Thank you
try with this event
checkchange(node, checked, eOpts)

How to remove a listener before an event takes place?

My question is similar to this one: How to prevent itemclick event on check change in Ext Js Tree.
However, it does not provide a solution for my problem. So, my question is: how can I remove a listener before an event takes place? The problem is that I have three listeners in my tree, and on checkchange I want to prevent the itemclick event. But everything executes in an unexpected order. The code is:
checkchange:function(node,check){
alert("1");
},
itemclick:function(view,rec,item,index,eventObj){
alert("2");
},
render:function(){
Ext.getCmp('mytree').on('checkchange',function(node,check){
alert("0");
Ext.getCmp('mytree').removeListener('itemclick',this);
});
}
When I check a node in my tree, I first see alert(2), then alert(1) and only then alert(0). So, the code which should remove the listener happens at the very end and I want the opposite.
Edit:
I do not want to completely remove the itemclick event. The more appropriate word is to "stop" an event, to prevent it from happening.
Edit:
The solution is to do e.getTarget() check inside the itemclick event. So, my code inside the itemclick event now looks like this:
itemclick:function(view, record, item, index, e, eOpts){
if(e.getTarget('span',1,true)){
// all other code which should take place in case
// itemclick event does not come from checkbox element
}
}
Firstly, it's important to understand the order events are fired:
render
itemclick
checkchange
Secondly, it's important to understand what's happening within the function you've defined for the render event.
What the code is doing is adding additional code to that which you've already defined for the checkchange function, so checkchange when it runs will alert 1 then 0 (what you are seeing). In addition, it will then remove the itemclick listener. This will mean that the second time you click a node, it should behave differently.
If you want to suppress the itemclick event immediately upon render, you should un-nest the removeListener call, thus:
render:function(){
this.removeListener('itemclick',this).on('checkchange',function(node,check){
alert("0");
});
}
Alternatively, you can simply remove the itemclick event listener itself.
If you want to change the way the itemclick event is handled, you can also intercept the event itself, using one of these methods:
itemclick:function(view,rec,item,index,eventObj){
eventObj.preventDefault(); //or
eventObj.stopPropagation(); //or
eventObj.stop();
},
It's not clear what you're trying to accomplish, however.

event Ext.view.ViewView after Refresh

I need an event which will be fired when items in DataView are ready as DOM elements, when refresh() is fireing the items are still not ready
Thanks
viewready may not be used becouse it fires only onse, I need handle event after each refresh
I think viewready is what you are after. If this doesn't work, afterrender should.
If you need an event that fires AFTER refresh has completed then you can add one. Within the view component of your choice, or within a dataview override that would apply to all dataviews, override the refresh function, call its parent and fire a custom event when it's complete:
refresh : function () {
this.callParent(arguments);
this.fireEvent('afterrefresh')
}
You can listen for that event like any other e.g.
me.on({
afterrefresh : me.doSomethingAfterRefresh,
scope : me
});

Resources