Find selected nodes/edges in cytoscape.js "on('unselect')" event - cytoscape.js

Background
When I tap a node, one event fires; the 'tap' event. When I then tap a different node, two events fire; the 'tap' event, then the 'unselect' event.
At first I thought it was a problem with on('tap') and on('unselect') event order, just because a human might think, "first I'm clearing my selection, and then I'm selecting a new node", but I can see why this is functioning as it should. A different node is tapped, so the 'tap' event fires; and then because the previous node is no longer selected, the 'unselect' event fires.
So, I think that it is working as it should, but its does mean that I need to code around this behaviour.
Details
What I want to do is to call some code in on('unselect') that will only run when no node/edge is selected. That would usually be when I click the background of the graph.
The problem is that cy.$('node:selected').length is always returning 0. And the same for edge:selected. See the below code.
So I'd just like to know if there are any workarounds for this? How can I query a graph's selected items in on('unselect')?
Context
I'm using the graph selection to filter the rows of a table, but when no node/edge is selected, I want the table to show all the data. Currently, each node/edge must be clicked twice for the on('tap') to not be overwritten by the on('unselect') unfilter code.
Steps to reproduce
var cy = cytoscape({
container: document.getElementById('cy'),
elements: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'ab', source: 'a', target: 'b' } }
]
});
cy.on('tap', 'node', function(evt){
console.log('event: tap node');
});
cy.on('tap', 'edge', function(evt){
console.log('event: tap edge');
});
cy.on('unselect', function(evt){
console.log('event: unselect');
console.log('node: ' + cy.$('node:selected').length);
console.log('edge: ' + cy.$('edge:selected').length);
});
When I tap a node, console logs the tap.
When I tap a different node, console logs the tap, then logs the unselect.
So when I click a node, then an edge, then a node, then the background, the console log is:
event: tap node
event: tap edge
event: unselect
node: 0
edge: 0
event: tap node
event: unselect
node: 0
edge: 0
event: unselect
node: 0
edge: 0
As you can see, cy.$('node:selected').length is always 0.
Environment info
Cytoscape.js version: 3.15.0

Same principle as How to listen to drag event of CytoscapeJS node (including only the one directly under the cursor/finger)
Add a class of your choice, like .selected to the target(s) on tap and use that class when listening for unselect events or when querying for selected targets. Remove the class within your unselect handler logic, so no .selected targets stick around.

Related

Use existing buttons in datatables

I am trying to trigger an onClick event when click on next or previous buttons in data tables. I checked the IDs of the buttons and they are auto generated. couldn't use those IDs. Is this possible ?
You have a page.dt event, fired each time the paging is updated :
table.on('page.dt', function() {
var info = table.page.info();
console.log('Showing page: '+info.page+' of '+info.pages);
});
If you want to target click on the previous / next buttons you can easily do that. To my experience dataTables seems to "eat" the click event simply by updating the view immediately - but you can stay upfront in the chain by listening on the mousedown event instead :
$('.dataTables_wrapper').on('mousedown', '.previous', function() {
console.log('previous clicked')
})
$('.dataTables_wrapper').on('mousedown', '.next', function() {
console.log('next clicked')
})
You need to use a delegated event handler because the dataTable controls is recreated each time the dataTable is redrawn. .dataTables_wrapper, .next and .previous is common for all dataTables.
demo -> http://jsfiddle.net/6jpbyvd4/

CreateJS click event on sprite not working

I'm having trouble with a click event on a sprite in CreateJS. The event isn't firing as expected. I've tried:
button.addEventListener("click", function() { alert('test'); });
and
button.on("click", function() { alert('test'); });
Neither of them fire on click event. Any ideas?
I found my problem. I forgot to enable the mouse on the stage.
e.g.
var stage = new createjs.Stage("canvasId");
//Children of container can dispatch mouse events
stage.mouseChildren = true;
//EaselJS checks 10 times per second what's under mouse pointer
stage.enableMouseOver(10);
CreateJS mouse events tutorial

Show & Hide events for a Sencha Touch navigation view

I'd like to be able to hide and show certain buttons in a navigation view bar when a view is push and popped onto the view stack. Shame I can't control that from the view config itself (but I'll save that moan for another time).
I wanted to know which events I should be using when a view is push/popped on a navigation view. The docs sometimes lie and I've been told many times not too trust it, so I'm not! Come on Sencha, Microsoft wouldn't get away with this!
So Any ideas? When I try to print out all the events for a view I get very unreliable behaviour:
What I've found:
When I push a view I get:
initialize
hide
show
When I pop a view I get:
hide
show
What the flip is going on?!?
The code to show events happening:
control: {
myViewRef: {
initialize: function() { console.log("initialize") },
activated: function() { console.log("activated") },
deactivated: function() { console.log("deactivated") },
painted: function() { console.log("painted") },
show: function() { console.log("show") },
hide: function() { console.log("hide") }
},
}
The code to actually push/pop a view:
onInBoxListViewItemTap: function(scope, index, item, record) {
console.log("onInBoxListViewItemTap");
var detailsView = this.getEnquiryDetailsViewRef();
// push view
var navview = this.getMyInboxViewRef();
navview.push(detailsView);
}
Does this stuff actually work properly i.e. Are there concrete events which are guaranteed to fire when a view is pushed and popped?
First of all - you have a typo in your code. You need to reference activate and deactivate not activate_d and deactivate_d.
Second, I would try to subscribe to push and pop events of navigation view and see if it would get you what you want.
I have the same problem.I use painted handler to solve it.
You can't handle 'painted' event in controller
the painted event description

Sencha Touch - setactiveitem to top level on nested list

I have a tabpanel with items of nestedlists. Each nested list goes several levels deep. If I drill down one of the nested list, then i click on a different item in the tabpanel, then click back to it, the nested list is still drilled down, instead of refreshing to the top level of the nested list.
How do I get the nestedlist to display the top level instead of the drilled down level everytime I return to it?
Additional Info
OK, I'm part way there. Here's the code I have now:
var tabBar = new Ext.TabPanel({
fullscreen: true,
id : 'footer',
cardSwitchAnimation:false,
listeners: {
cardswitch: {
fn: function() {
Ext.getCmp('footer').getActiveItem().setActiveItem(0);
}
}
},
tabBar: {
dock: 'bottom'
},
items: [/* some nestedlist components */]
});
So the final problem is that everytime I cardswitch, I see the "drillup/slideback" animation of the nested list sliding back or drilling back to the top level item. How do I get it to just show the top level item without this drill up/slide back animation? I want to preserve the slide forward and drill down animation when the user drills down the nestedlist.
You can try to set the cardSwitchAnimation parameter to false in the setActiveItem method
[UPDATE] Deselect item
Add an event listener for the item tap event on the nested list
nestedList.on("itemtap", function(nestedlist, index, item, e){setTimeout(function(){nestedlist(index);},500);}, this);
[UPDATE] From John
For some reason your code didn't do anything for me. But this one worked:
var nestedList = new Ext.NestedList({
store: store,
listeners: {
itemtap: function(dv, ix, item, e) {
// Clear the selection soon
setTimeout(function(){dv.deselect(ix);},500);
}
}
});
In March 2014, with version 2.3.1, I had the above problem with the Ext.dataview.NestedList object. The suggested approach of using the "deselect" method did not work for me - probably because of the two years that have gone by since the original question.
To resolve problem, I used the following:
nestedList.goToNode( nestedList.getStore().getRoot() );

Back button on first level of nestedlist

I have a nestedList with a few levels that appears when the user presses a button on the screen. When the nestedList appears, there is no back button (because we're at the top of the tree, so understandably there is nowhere to go back to), whereas tapping on items in the list takes you to screens with a back button.
I'd like to add a back button to the first screen. I have managed to do this, but not without adding the same back button to every sublist in the nestedList - this has the effect of 1 back button at the top level, and 2 back buttons (one to take you out of the nestledList completely, and one to take you up a level) at every subsequent level.
Can anyone help me figure out how to have 1 back button on each screen, including the top level to close the list?
Many thanks
PS a nasty workaround that I'm using at the moment is to have a "close" button in the top right of every screen instead.
I don't know how comfortable you are with the inner workings of Sencha Touch so how you go about doing this is up to you--
The back button is there, hidden, when the nested list is shown (created in the initComponent function with hidden: true), and then onBackTap, onItemTap and setActivePath will all call syncToolbar near the end of their functions which is where the back button is hidden when you are at a depth of 0.
So there are 2 places you need to do something about, first is initComponent which is easy-- just implement initComponent in your nestedList, call the superclass' initComponent and then set the backButton visible
var myNestedList = new Ext.NestedList({
...,
initComponent: function() {
myNestedList.superclass.initComponent.call(this);
this.backButton.setVisible(true);
},
...
});
That takes care of showing it intially.. how you care to deal with fixing syncToolbar is up to you. You can use Ext.override, you can straight up copy and paste the whole syncToolbar function into your nestedList object which would also override it or you could do what you're told never to do and just edit the sencha-touch.js file directly. However you decide to do it, what you're looking to change is
syncToolbar: function(card) {
...
backToggleMth = (depth !== 0) ? 'show' : 'hide';
if (backBtn) {
backBtn[backToggleMth]();
if (parentNode) {
backBtn.setText(backBtnText);
}
}
... };
You can either change backToggleMth to = 'show' or just delete the if (backBtn {...} all together.
In the Sencha Touch 2.2 I had to use a different code:
Ext.create('Ext.NestedList', {
...,
listeners: {
initialize: function(obj) {
obj.getBackButton().show();
},
back: function(obj, node, lastActiveList, detailCardActive) {
switch(node.getDepth()) {
case 1:
obj.getBackButton().show();
break;
case 0:
alert("wohooooooo!");
break;
}
}
}
}