FancyTree load all nested children on select - javascript

Here's my issue. I'm using checkboxes and lazy load via ajax. However, if you were to check a parent item without expanding it, none of the child nodes have been loaded so they don't get checked. How can I load all child and nested child nodes under a parent, and check them all, when they check the parent? Thanks, and this is what I have so far
$(function () {
// Create the tree inside the <div id="tree"> element.
$("#tree").fancytree({
source: { url: "/Home/GetData", cache: true }
, checkbox: true
, icons: false
, cache: true
, lazyLoad: function (event, data) {
var node = data.node;
data.result = {
url: "/Home/GetTreeViewData/" + node.key
, data: { mode: "children", parent: node.key }
, cache: true
};
}
, selectMode: 3
, select: function (event, data) { //here's where I need to load the children and any sub children for that node, if it has them, so they can be set to checked
}
, strings: {
loading: "Grabbing places and events…",
loadError: "Load error!"
},
})
});
Update
The reason I need to pull these client side is because this is a treeview that will be loading google map markers. So if I have a structure like
Parent1
->child1-1
->->child1-1-1
->child1-2
all of those child nodes load lazy. however, if they were to check the parent node 1, then I'd need to load the markers for all of those child nodes. That's why I'm looking for a way to recursively get all the children. Because it would be really hard to keep track of what markers have/haven't been added, if I don't just load the treeview items and check the boxes. Make sense?

I think you could use select event:
select: function(event, data) {
var node = data.node;
if (node.isSelected()) {
if (node.isUndefined()) {
// Load and select all child nodes
node.load().done(function() {
node.visit(function(childNode) {
childNode.setSelected(true);
});
});
} else {
// Select all child nodes
node.visit(function(childNode) {
childNode.setSelected(true);
});
}
}
}
That way if the child nodes haven't been loaded they will be loaded and selected after that.

First: maybe you don't even need to load all child nodes.
In selectMode: 3 a selected parent means 'all children are selected too', so if you post the top-most selected parent nodes to your server, the backend could handle it accordingly. The stopOnParent argument of the tree.getSelectedNodes method supports this as well.
Another option would be to fix the the selection state of child nodes
after a lazy parent was loaded:
$("#tree").fancytree({
checkbox: true,
selectMode: 3,
source: { url: "/getTreeData", cache: false },
lazyLoad: function(event, data) {
data.result = {
url: "/getTreeData",
data: {mode: "children", parent: node.key},
cache: false
};
},
loadChildren: function(event, data) {
// Apply parent's state to new child nodes:
data.node.fixSelection3AfterClick();
},
Update
If you really need to load the lazy child nodes when the parent is selected, you could try in addition to the above code
(untested)
$("#tree").fancytree({
...
select: function(event, data) {
if( data.node.isUndefined() ) {
data.node.load(); // triggers lazyLoad to load children
// alternative: node.expand()
}
},

Adding the unselect option, the Andrew's code would be:
if (node.isSelected()) {
if (node.isUndefined()) {
// Load and select all child nodes
node.load().done(function() {
node.visit(function(childNode) {
childNode.setSelected(true);
});
});
} else {
// Select all child nodes
node.visit(function(childNode) {
childNode.setSelected(true);
});
}
}
else{
if (node.isUndefined()) {
// Load and unselect all child nodes
node.load().done(function() {
node.visit(function(childNode) {
childNode.setSelected(false);
});
});
} else {
// Select all child nodes
node.visit(function(childNode) {
childNode.setSelected(false);
});
}
}

Related

ExtJs 4.1.2 ComboBox Update or Reload Based on another ComboBox

I'd like to know a way of how to update the list values of a ExtJs ComboBox. For instance, I have two comboboxs.
One Combobox determine what values the another ComboBox should have. So, after selecting some of those,
I click the drowndown list (combobox) to see the values. But i dont get reflected.
change: function (combofirst, record) {
Ext.Ajax.request({
-- -- --
-- -- --
success: function (response) {
var combosecond = Ext.getCmp('defaultPackageType');
//I am unable to update the combosecond from below snippet.
combosecond.store = Ext.create('Ext.data.Store', {
fields: ['value', 'display'],
data: [
["N", "No"],
["A", "All accounts"]
] //json response
});
},
failure: function (record, action) {}
});
});
In short, how can I change the values of a ComboBox already has with ajax only.
Hope someone can help me
Thanks
I would also agree to the comment, that creating every time a new store and bind it to the combobox is not the optimal solution. I don't know really the reason why this should be done, but nevertheless here is a working example by using bindStore:
https://fiddle.sencha.com/#view/editor&fiddle/3ci0
Ext.create('Ext.form.field.ComboBox', {
// ...
listeners: {
change: {
fn: function (cb) {
Ext.Ajax.request({
url: 'https://jsonplaceholder.typicode.com/albums',
method: 'GET',
timeout: 60000,
success: function (response) {
var jsonResp = response.responseText;
let jsonObj = Ext.JSON.decode(jsonResp, true)
var combo2 = Ext.getCmp('myCombo2');
combo2.bindStore(Ext.create('Ext.data.Store', {
fields: ['id', 'title'],
data: jsonObj
}));
}
});
}
}
}
});
For selection of value 1 the data is loaded from a different url.
But I would think about whether a new proxy call is necessary and whether you can achieve your requirements by using filters or something else.

JSTree Exclude different nodes from selection

In my project I have 3 company root nodes and test children.With Checkboxes.
- []Company1
-- []Test1
-- []Test2
- []Company2
-- []Test1
-- []Test2
-- []Test 3
- []Company3
-- []Test1
The tree is much more complex, but for question I reduced the levels. However, I want to manage, that it is forbidden to select two Companies. As sample, if Test1 from Company2 is selected and the user select Test1 from Company1, then all selections from Company1 and Company3 get unchecked.
My code for the jstree is:
$(function () {
$('#html1').on('select_node.jstree', function(e, data){
var countSelected = data.selected.length;
if (countSelected>1) {
data.instance.deselect_node( [ data.selected[0] ] );
}
});
$.ajax({
type: "get",
url: "/jstreecontent",
dataType: "json",
success: function(data) {
$('#html1').jstree({
'core' : {
'data' : data
},
"checkbox" : {
"keep_selected_style" : false
},
"plugins" : [ "checkbox", "contextmenu"],
"checkbox": {
three_state : true, // to avoid that fact that checking a node also check others
whole_node : false, // to avoid checking the box just clicking the node
tie_selection : false // for checking without selecting and selecting without checking
},
"contextmenu": {
"items": function ($node) {
var tree = $("#html1").jstree(true);
if($node.a_attr.type === 'test')
return getTestContextMenu($node, tree);
}
}
});
},
complete: function() {
// This function will be triggered always, when ajax request is completed, even it fails/returns other status code
console.log("complete");
},
error: function() {
// This will be triggered when ajax request fail.
console.log("Error");
}
});
});
If I remove the part:
"checkbox": {
three_state : true, // to avoid that fact that checking a node also check others
whole_node : false, // to avoid checking the box just clicking the node
tie_selection : false // for checking without selecting and selecting without checking
},
The selection with the root nodes works perfect, just one root node is allowed, but I cannot select a whole root, just its nodes. So I think the
$('#html1').on('select_node.jstree', function(e, data){
var countSelected = data.selected.length;
if (countSelected>1) {
data.instance.deselect_node( [ data.selected[0] ] );
}
});
Is working on all nodes, not only on the top one. Maybe this is wrong.
But it seems, I fail with it, it is the wrong way. I hope someone else had the same problem in the past and give me a hint for this.

How do I select the root node in jstree?

I am trying to embed some functionality in my jstree based on whether it is a root node or if it is one of the child nodes.
From the jstree documentation and other Stack Overflow posts that I have gone through, I am now able to populate the items correctly, but I am at a roadblock on how to select the root node of the jstree in an "select_node" condition like the following snippet. Is this correct appending the word "root" to select_node? Please advise. (My root item is called "root", if I have to call get_parent() and check how would I pass my root as paramter). Any pointers to proceed would be appreciated.
$(".myjstree").on("select_node.jstree.root", function (e, data){
// do stuff if this is my root node
});
Listening to select_node.jstree.root does not work as intended, as all it does is create an additional namespace for select_node.jstree (see the Event names and namespaces section from http://api.jquery.com/on/ for more information). select_node.jstree.root events are still triggered for all select_node.jstree events.
Instead, you can check whether the root node is selected via the data.selected property in select_node.jstree. You can also interact with it via $('#jstree').jstree(true).get_node('root') like so:
$('#jstree').jstree({
core: {
data: [
{
id: 'root',
text: 'Root',
state: { opened: true },
children: [
{ id: 'child-node-1', text: 'Child 1' },
{ id: 'child-node-2', text: 'Child 2' }
]
}
]
}
});
$('#jstree').on("changed.jstree", function (e, data) {
if (data.selected.length === 1 && data.selected[0] === 'root') {
let root_node = $('#jstree').jstree(true).get_node('root');
console.log(root_node);
}
});
#import "https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css";
<div id="jstree"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>

Passing object to Query plugin which includes data from the element applied to

I need to pass an object to some jQuery plugin. The plugin is applied to multiple elements. The data passed is obtained from the element the plugin is applied to.
How can I pass such an object to a Query plugin which includes data from the element applied to (i.e. $(this).parent().parent().data('id'))?
EDIT. without iterating over the results and applying the plugin each time.
$('#main').find('tr a.upload').fileupload({
formData: {id:$(this).parent().parent().data('id'),foo:'bar'}, //id is not included
start: function() {
//Doesn't work
$(this).fileupload({
formData: {example: 'test'}
});
},
done: function(e, data) {
console.log(this); //Am able to access element
},
});
Try this:
$('#main').find('tr a.upload').fileupload({
formData: function(form) {
return {
id: form.parent().parent().data('id'),
foo:'bar'
};
},
done: function(e, data) {
console.log(this); //Am able to access element
},
});
The function is received the form as a parameter, not as the this context.

Extjs: Tree, Selecting node after creating the tree

I have a simple TreePanel. I would like to select a particular node upon loading it. The nodes are from a remote file (json).
The tree is loading as expected. However, the node is not being selected. Firebug shows node as undefined. This perhaps because of the async property. But, I an unable to configure this other wise, or specify the node be selected.
Any suggestions welcomed, and thank you.
LeftMenuTree = new Ext.tree.TreePanel({
renderTo: 'TreeMenu',
collapsible: false,
height: 450,
border: false,
userArrows: true,
animate: true,
autoScroll: true,
id: 'testtest',
dataUrl: fileName,
root: {
nodeType: 'async',
iconCls:'home-icon',
expanded:true,
text: rootText
},
listeners: {
"click": {
fn: onPoseClick,
scope: this
}
},
"afterrender": {
fn: setNode,
scope: this
}
});
function setNode(){
alert (SelectedNode);
if (SelectedNode == "Orders"){
var treepanel = Ext.getCmp('testtest');
var node = treepanel.getNodeById("PendingItems");
node.select();
}
}
I use this code in the TreeGrid to select a node
_I.treeGrid.getSelectionModel().select(_I.treeGrid.getRootNode());
I haven't tried this in a TreePanel but since the TreeGrid is based on it I'll just assume this works. I used the load event of the loader to plugin similar code after the XHR request was done, so try to write your setNode function like this:
var loader = LeftMenuTree.getLoader();
loader.on("load", setNode);
function setNode(){
alert (SelectedNode);
if (SelectedNode == "Orders"){
var treepanel = Ext.getCmp('testtest');
treepanel.getSelectionModel().select(treepanel.getNodeById("PendingItems"));
}
}
this work for me...
var loader = Ext.getCmp('testtest').getLoader();
loader.on("load", function(a,b,c){
b.findChild("id",1, true).select(); // can find by any parameter in the json
});
I have documented a way to accomplish something very similar here:
http://www.sourcepole.ch/2010/9/28/understanding-what-s-going-on-in-extjs
what you'll need to make sure is that the node that you are selecting is visible. You can accomplish that by traversing the tree and node.expand()ing all the nodes parents (from the root down).
This is because the node isn't really selectable until the tree has been rendered. Try adding your node selection to an event listener listening for the render event.
If you're using a recent enough version of ExtJS then I find using ViewModels and the Selection config far easier for this kind of thing.
Something like:
LeftMenuTree = new Ext.tree.TreePanel({
renderTo: 'TreeMenu',
collapsible: false,
height: 450,
border: false,
userArrows: true,
animate: true,
autoScroll: true,
id: 'testtest',
dataUrl: fileName,
bind: {
Selection: '{SelectedNode}'
},
root: {
nodeType: 'async',
iconCls:'home-icon',
expanded:true,
text: rootText
},
listeners: {
"click": {
fn: onPoseClick,
scope: this
}
"afterrender": {
fn: setNode,
scope: this
}
});
(You'll need to either have a ViewModel set up in the TreePanel or the owning view)
Then assuming you're using a ViewController and setNode is a member:
setNode: function(){
var nodeToSelect = // code to find the node object here
this.getViewModel().set('Selection', nodeToSelect);
}
The nice thing about the ViewModel approach is that it seems to just handle all of the rendering / data loading issues automatically.

Categories

Resources