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>
Related
I have my list mode
ListModel {
id: nestedModel
}
and I can append the list model using the code
nestedModel.append({
locationName: qsTr("Location5"),
collapsed: true,
folders: [{
folderName: qsTr("Cam11")
}, {
folderName: qsTr("Cam22")
}, {
folderName: qsTr("Cam33")
}, {
folderName: qsTr("Cam44")
}]
})
Which works fine.
But I need to append the inner list only using the same append model, like I have already Cam11,Cam22,Cam33,Cam44 in my list model, and I have to append Cam55,Cam66 dynamically.
How it’s possible?
Any help will be appreciated…
Thanks
Haris
Finally I found the answer here
We can append new data to child list using,
nestedModel.get(index).folders.append({"folderName": "Cam55"})
nestedModel.get(index).folders.append({"folderName": "Cam66"})
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);
});
}
}
I'm trying to get a handle on using $resource in angularjs and I keep referencing this answer AngularJS $resource RESTful example for good examples. Fetching a record and creating a record work fine, but now i'm trying to add a "section" to an existing mongo record but can't figure it out.
documents collection
{
_id: 'theid',
name: 'My name",
sections: [
{
title: 'First title'
},
{
title: 'Second title'
}
]
}
angular controller snippet
var document = documentService.get({_id: 'theid'});
// TRYING TO ADD $scope.section TO THE SECTIONS ARRAY IN THE VARIABLE document.
//document.sections.push($scope.section); <-- This does NOT work
//document.new_section($scope.section); <-- could do this and then parse it out and insert it in my backend code, but this solution seems hacky and terrible to me.
document.$save(function(section) {
//$scope.document.push(section);
});
documentService
return $resource(SETTINGS.base + '/documents/:id', { id: '#id' },
{
update: { method: 'PUT' }
});
From the link i posted above, If I was just updating the name field, I could just do something like this:
var document = documentService.get({_id: 'theid'});
document.name = "My new name";
document.$save(function(section) {
//$scope.document.push(section);
});
I'm just trying to add an object to a nested array of objects.
Try this:
documentService.get({_id: 'theid'}, function(document) {
document.sections.push($scope.section);
document.$save();
});
I'm trying to implement the FuelUX tree plugin and I've followed the example so far but I need a nested structure. I'm assuming the tree plugin is capable of handling nested children? is this correct?
var treeDataSource = new TreeDataSource({
data: [
{ name: 'Test Folder 1', type: 'folder', additionalParameters: { id: 'F1' },
data: [
{ name: 'Test Sub Folder 1', type: 'folder', additionalParameters: { id: 'FF1' } },
{ name: 'Test Sub Folder 2', type: 'folder', additionalParameters: { id: 'FF2' } },
{ name: 'Test Item 2 in Folder 1', type: 'item', additionalParameters: { id: 'FI2' } }
]
},
{ name: 'Test Folder 2', type: 'folder', additionalParameters: { id: 'F2' } },
{ name: 'Test Item 1', type: 'item', additionalParameters: { id: 'I1' } },
{ name: 'Test Item 2', type: 'item', additionalParameters: { id: 'I2' } }
],
delay: 400
});
So far it seems to load the top level items into the opened folders rather than the nested data items. This is what the demo on their site also does but this doesn't seem as if its the desired interaction. Can anyone confirm if this is expected behaviour?
Can anyone point me to code where they've created a nested data tree using this plugin? Is there something really obvious I am missing?
I am actually in the process of writing a blog post on this very issue.
The solution I have developed is not for the faint-of-heart. The problem is that the folder objects do not support instantiation with child data. Also, adding children is no trivial task. I spun up a quick fiddle that you can pick through to get an idea of how to accomplish your goal. I am using this same solution only that my addChildren function calls out to an MVC route via AJAX and gets back a JSON object to populate the children dynamically.
You can literally, copy and paste the code from my fiddle and start using the addChildren function out-of-the-box.
I'm sorry for the lack of documentation about this - it needs to be improved for sure.
The idea is that you provide a dataSource when instantiating the tree control, and that data source should have a data function with the signature (options, callback). That data function will be called on control init to populate the root level data, and will be called again any time a folder is clicked.
The job of the data function is to look at the options parameter which is populated from the jQuery.data() on the clicked folder and respond with the data for that folder. The special case is the initial root folder data, where the options are populated from any jQuery.data() on the control's root div, which may or may not exist.
The jQuery.data() on folders is populated from the array of objects you provide in your data function's callback. You can see in this example https://github.com/ExactTarget/fuelux/blob/master/index.html#L184-L189 there is a property called additionalParameters but really you can provide any additional properties beyond the required name and type for you to use later (the next time your data function is called) to determine which folder was clicked and return the data for that folder.
Our current example returns the same static data for every folder, which is not the best example, so I do hope to improve this situation by either creating a tutorial myself or linking to one if someone beats me to it.
Following up on Adam's answer, here is an example that seems to accomplish what you want..
The data function for the DataSource can check to see if there is "sub" data passed via options:
DataSource.prototype = {
columns: function () {
return this._columns;
},
data: function (options, callback) {
var self = this;
if (options.search) {
callback({ data: self._data, start: start, end: end, count: count, pages: pages, page: page });
} else if (options.data) {
callback({ data: options.data, start: 0, end: 0, count: 0, pages: 0, page: 0 });
} else {
callback({ data: self._data, start: 0, end: 0, count: 0, pages: 0, page: 0 });
}
}
};
Demo on Bootply: http://www.bootply.com/60761
I am building a YUI3 module for my workplace. I construct it like so:
var testMenu1 = new Y.ContextMenu({
id: 'testmenu1',
menuItems: {
opsdb: {
title: 'empty',
type: 'opsdb',
separator: false,
action: function(e, host) {
iframe_panel_opsdb(host);
}
}
}
});
I'd like to come in later and change the title based on the hostname I right click on. How can I do that given that testMenu1 does now exist. I can do something like testMenu1.set('id', 'newId') but menuItems.opsdb.title, I cannot figure out how to change that one.
You can access nested attributes with dot notation.
Then the following should do what you want, if menuitems is an attributes. (I do not know the details of ContextMenu).
testMenu1.set('menuitems.opsdb.title', 'myNewTitle');
More details there: http://yuilibrary.com/yui/docs/attribute/#subattrs