prevent jsTree from expanding the nodes after you select them programmatically - jstree

Is there a way to select a node without expanding nodes? Every time I call the method to select a node, it will call the changed.jstree event and expand the nodes. I want to select a node without expanding the nodes.
$('#jstree').jstree(true).select_node('info');
$('#jstree').on("changed.jstree", function (e, data) {
});
UPDATE:
I also tried the below method to select a node and it still expanded the nodes:
$('#jstree').jstree().select_node('info', false,true)

I figured it out. You call the below method to check the default options and the boolean below to true to set the prevent_open.
$('#jstree').on('ready.jstree', function (e, data) {
data.instance.select_node(['info'], false, true);
});
//$('#jstree').jstree().select_node('info', false,true)

Related

ag-grid - how to get parent node from child grid via context menu?

As an example, I have a Master\Detail grid.
Master\Detail defined as key-relation model and on getDetailRowData method parent node data exists in params
but how to get parent node data from child view?
Tried via context-menu:
On right click - getContextMenuItems got executed which has an input params
On this sample, child-grid doesn't have any row and node in context-params is null, it's ok,
but anyway it should be possible to retrieve the parent details at least via grid API, isn't it ?
Then I've tried to get parent via node:
but instead of detail_173 as you can see its ROOT_NODE_ID, and here is a confusion for me.
So question is that how to get parent node data (RecordID 173 just in case) through child-view context menu or any other possible way (without storing temp value, cuz multiple children's could be opened at the same time)
Yes, I've read this part Accessing Detail Grid API, and still unclear how to get parent-node via child-grid.
For React Hook users without access to lifecycle methods, use Ag-Grid Context to pass the parent node (or parent data) to the detail grid via detailGridOptions. No need to traverse the DOM or use a detailCellRenderer unless you want to :)
https://www.ag-grid.com/javascript-grid-context/
detailCellRendererParams: (masterGridParams) => ({
detailGridOptions: {
...
context: {
masterGrid: {
node: masterGridParams.node.parent,
data: masterGridParams.data
}
},
onCellClicked: detailGridParams => {
console.log(detailGridParams.context.masterGrid.node);
console.log(detailGridParams.context.masterGrid.data);
}
}
})
Able to achieve it. Have a look at the plunk I've created: Get master record from child record - Editing Cells with Master / Detail
Right click on any child grid's cell, and check the console log. You'll be able to see parent record in the log for the child record on which you've click.
The implementation is somewhat tricky. We need to traverse the DOM inside our component code. Luckily ag-grid has provided us the access of it.
Get the child grid's wrapper HTML node from the params - Here in the code, I get it as the 6th element of the gridOptionsWrapper.layoutElements array.
Get it's 3rd level parent element - which is the actual row of the parent. Get it's row-id.
Use it to get the row of the parent grid using parent grid's gridApi.
getContextMenuItems: (params): void => {
var masterId = params.node.gridOptionsWrapper.layoutElements[6]
.parentElement.parentElement.parentElement.getAttribute('row-id');
// get the parent's id
var id = masterId.replace( /^\D+/g, '');
console.log(id);
var masterRecord = this.gridApi.getRowNode(id).data;
console.log(masterRecord);
},
defaultColDef: { editable: true },
onFirstDataRendered(params) {
params.api.sizeColumnsToFit();
}
Note: Master grid's rowIds are defined with [getRowNodeId]="getRowNodeId" assuming that account is the primary key of the parent grid.
A very reliable solution is to create your own detailCellRenderer.
on the init method:
this.masterNode = params.node.parent;
when creating the detail grid:
detailGridOptions = {
...
onCellClicked: params => console.log(this.masterNode.data)
}
Here is a plunker demonstrating this:
https://next.plnkr.co/edit/8EIHpxQnlxsqe7EO
I struggled a lot in finding a solution to this problem without creating custom details renderer but I could not find any viable solution. So the real good solution is already answered. I am just trying to share another way to avoid creating custom renderer.
So What I did is that I changed the details data on the fly and added the field I required from the parent.
getDetailRowData: function (params: any) {
params?.data?.children?.forEach((child:any) => {
//You can assign any other parameter.
child.parentId= params?.data?.id;
});
params.successCallback(params?.data?.children);
}
When you expand the row to render details the method getDetailRowData gets called, so it takes in params as the current row for which we are expanding the details and the details table is set by invoking params.successCallback. So before setting the row data I am iterating and updating the parentId.

how to respond to user expanding a node?

I guess the answer is expand - but the expand-event does not seem to fire.
But let me start at the beginning: I have a nice tree and I'd like to use jBox to display information about certain nodes. I noticed that this worked only for nodes that were visible when the tree was created, but it did not work for nodes under collapsed nodes. So I thought I could use expandand assign an event-handler that would call jBoxto create the tooltips. But it did not work. I added a console.log to the `expand-handler and noticed that it never logged.
Am I specifying it incorrectly?
Fiddle here. The "SD"-Node has some items in it which should have a tooltip attached to the (i)-icon.
It doesn't fire because you are passing in a string:
"expand": "function(event, data) {...}"
You need to remove the double quotes, so that it is a function:
"expand": function(event, data) {...}
See updated fiddle: http://jsfiddle.net/pgh52m4w/3/
The same counts for the event "dblclick". Remove the double quotes there too.
Also, it is encouraged to use the .attach() method when attaching jBox. The attach method will check if this jBox was already attached to the element and only attaches it if it wasn't.
See the updated fiddle. I created a variable for the tooltip and reattach it in the expand event:
$(function() {
var treei = $("#tree").fancytree({
expand: function () {
myTooltip && myTooltip.attach(); // Reattaching Tooltip
}
// ...
});
var myTooltip = new jBox("Tooltip", { // get tooltips showing
attach: '[data-jbox-content]',
getTitle: "data-jbox-title",
getContent: "data-jbox-content"
});
});

Make node fixed in echarts force graph

There is a way to set the initial position of nodes in a force graph in echarts. But is there a way to have this node stay at this position?
Of course,there is an attribute named fixed decide a node fix or not.So you can set an event listener on echarts.For example,I set a click event listener like:
myChart.on('click', function (params) {
fixNode(params.data);
});
The params.data is the object that you click on echarts.Then you should write a fixNode method like:
function fixNode(currentNode){
_nodes.forEach(function (node) {
if(node.name==currentNode.name) node.fixed = true;
});
refresh();
}
This method is to traverse the node array named _nodes and find the same node as currentNode in _nodes.when we find it,we can set its attribute fixed true.Finally, we have to rebind data to echarts,so we write a method to refresh echarts:
function refresh(){
option={
series:[
{
data:_nodes
}
]
};
mycharts.setOption(option);
}
Now,the node that you click will fixed in a position.

Dragula Copy and removeOnSpill

I'm trying to use the Dragula Drag & Drop library to Clone elements into a target container AND allow the user to remove cloned elements from the Target Container by drag & dropping them outside of the target container (spilling).
Using the examples provided I have this:
dragula([$('left-copy-1tomany'), $('right-copy-1tomany')], {
copy: function (el, source) {
return source === $('left-copy-1tomany');
},
accepts: function (el, target) {
return target !== $('left-copy-1tomany');
}
});
dragula([$('right-copy-1tomany')], { removeOnSpill: true });
Which does not work - it seems that 'removeOnSpill' simply doesn't work if the container accepts a copy.
Does anybody know what I am not doing, doing wrong or if there is a work-around?
TIA!
I came here after looking for a while for a solution to a similar issue using the ng2-dragula for angular2.
dragulaService.setOptions('wallet-bag', {
removeOnSpill: (el: Element, source: Element): boolean => {
return source.id === 'wallet';
},
copySortSource: false,
copy: (el: Element, source: Element): boolean => {
return source.id !== 'wallet';
},
accepts: (el: Element, target: Element, source: Element, sibling: Element): boolean => {
return !el.contains(target) && target.id === 'wallet';
}
});
I've got 4 divs that can all drag into one which has the id of wallet
They are all part of the wallet-bag
using this code, they can all copy into the wallet, not copy between each other, and you can remove them from the wallet using the spill but not from the others.
I'm posting my solution as it may also help someone.
Ok, so the general answer I came trough is that:
you can have 'removeOnSpill' working - even with 'copy' option set to true - , only if you set the 'copy' option applying ONLY when the 'source' container IS NOT the one you are trying to remove elements from.
In my case I had 3 containers from which I can drag in another one called 'to_drop_to'.
Those container have all id starting with 'drag'.
So I set:
var containers = [document.querySelector('#drag1'),
document.querySelector('#drag2'),
document.querySelector('#drag3'),
document.querySelector('#to_drop_to')];
dragula(containers, {
accepts: function (el, target, source, sibling) {
return $(target).attr('id')=="gadget_drop"; // elements can be dropped only in 'to_drop_to' container
},
copy: function(el,source){
return $(source).attr('id').match('drag'); //elements are copied only if they are not already copied ones. That enables the 'removeOnSpill' to work
},
removeOnSpill: true
}
and this worked for me.
Hope it helps.
From the dragula documentation
options.removeOnSpill
By default, spilling an element outside of any containers will move
the element back to the drop position previewed by the feedback
shadow. Setting removeOnSpill to true will ensure elements dropped
outside of any approved containers are removed from the DOM. Note that
remove events won't fire if copy is set to true.

Select Child nodes when parent is also selected in JSTREE

I am having difficulties by selecting child nodes when parent is also selected , also would like to open subfolders and select all childs (not sure if im making it clear) so I have know how to get all the child nodes by:
selected_nodes = $("#demo").jstree("get_selected", null, true);
var tree = jQuery.jstree._reference('#demo');
var children = tree._get_children(selected_nodes);
but doest really select or open child folder and nodes
This might not be what OP wanted but on JSTree 3.3. I used this to open all nodes under a selected parent.
$(treeContainer).bind("select_node.jstree", function (e, data) {
return data.instance.open_all(data.node);
});
I gave up on this Idea.. now im just doing ajax requests to load the childs and receive a json object, and from there i can see if its a file or directory, if its a directory again another request and like this i have the whole structure
You have to turn on two_state checkboxes to allow parent and child nodes to be selected indepentently. Below I've configured the "two_state" parameter for the checkbox plugin:
$("#docTree").jstree({
"themes": {
"theme": "classic",
"url": "jstree/themes/classic/style.css"
},
"plugins": ["themes", "ui", "checkbox", "json_data"],
"checkbox": { "two_state" : true }
})
Check documentation here: http://www.jstree.com/documentation/checkbox
If I understand this correctly you want to select all of the lowest descendants in a jsTree (the files) when one of their parents (the folders) have been selected.
Unfortunately I haven't found a more direct approach than the one below. I'm using jsTree 3.1.1 and managed to solve this problem using the following:
var $demo = $("#demo");
var nodes = $demo.jstree("get_top_selected", true);
//Selects all of the children of each selected node including folders
if(nodes.length > 0){
nodes.forEach(function(node, i){
$demo.jstree("select_node", node.children_d, true, false);
});
}
var fileNodes = $demo.jstree("get_bottom_selected", false);
//We now need to deselect everything and only select the file nodes
$demo.jstree("deselect_all", true);
$demo.jstree("select_node", fileNodes, true, false);
The above code allows the user to "select" multiple folders and have those files selected.
The parameter with the value true for the "get_top_selected" function returns the full node instead of just ID's. This lets you get access to the node's children.
Function "select_node" takes three parameters. The first is the nodes to select (in this case the descendants of the current parent node). If the second parameter is set to true it prevents the changed.jstree event from firing for each selected node. The third parameter is set to false as setting to true prevents the children folders from opening.
The function "get_bottom_selected" only returns a node if it has both been selected and it itself does not have any children. As we are now only interested in the node ID's we can pass the parameter false (or omit it completely).
Passing a parameter of true to the function "deselect_all" again prevents the changed.jstree event from firing.
If you want to check out the jsTree API docs you can find them here. That list is filtered to only include the select functions and events. A full list of the API can be found here.
I hope this helps but let me know if you require further clarification on any of the code ^_^
select all child nodes when parent selected ,
$(data.rslt.obj).find("li").each( function( idx, listItem ) {
var child = $(listItem); // child object
$.jstree._reference("#associateRightHandTree").check_node(child);
});
unselect all child nodes when parent unselected ,
$(data.rslt.obj).find("li").each( function( idx, listItem ) {
var child = $(listItem); // child object
$.jstree._reference("#associateRightHandTree").uncheck_node(child);
});