How to get all the child elements or id of a Panel in ExtJS 4?
I wrote that function for you. I think it will help you.
function getAllChildren (panel) {
/*Get children of passed panel or an empty array if it doesn't have thems.*/
var children = panel.items ? panel.items.items : [];
/*For each child get their children and concatenate to result.*/
Ext.each(children, function (child) {
children = children.concat(getAllChildren(child));
})
return children;
}
It takes panel (container) as a parameter and returns all children and subchildren recursively.
EDIT
This will return ids of children. USES PREVIOUS FUNCTION - getAllChilden
function getAllChildenIds(panel) {
//*Get all child items. \*/
var children = getAllChilden(panel);
//*Replace items with their ids.\*/
for (var i=0, l=children.length; i < l; i++) {
children[i] = children[i].getId();
}
return children;
}
Just call query() on your panel which will return an array of all child elements which match an optional selector.
i.e. panel.query()
Related
I am using wijmo flex grid to create a tree view for my data, I am able to find whether a specific node has children or not and what is the level of the node but I am unable to go to the parent node from a given node. The index for each row is also being retrieved.
Any insights on the topic would be highly helpful.
$scope.selectionChanged = function(sender,args){
var index = sender.selection.row;
var temp;
console.log(index);
temp = sender._rows[index]._data;
console.log(temp.reports);
};
FlexGrid rows come in two flavors: regular rows (Row objects) and nodes (GroupRow objects). Regular rows have no "level", but GroupRow objects do have a "level" property that you can use to get the node's level.
To get a row's parent node, you should scan the grid's rows collection up until you find a node that has a "level" smaller than the one you started with.
Here's a fiddle the demonstrates:
http://jsfiddle.net/Wijmo5/8n2yde6f/
Check out the implementation of the "getParentNode" method, that should be what you're looking for:
// gets the parent row for a given FlexGrid row.
// returns the parent row or null if original row doesn't have a parent.
function getParentNode(row) {
// get row level
var startLevel = row instanceof(wijmo.grid.GroupRow) ? row.level : -1;
var startIndex = row.index;
// travel up to find parent node
for (var i = startIndex - 1; i >= 0; i--) {
var thisRow = row.grid.rows[i],
thisLevel = thisRow instanceof(wijmo.grid.GroupRow) ? thisRow.level : -1;
if (thisLevel > -1) {
if (startLevel == -1 || (startLevel > -1 && thisLevel < startLevel)) {
return thisRow;
}
}
}
// not found
return null;
};
Hope this is useful.
What you want to do is access the dataItem of the selected row and see if it contains children, using the FlexGrid's childItemPath that you set.
Here is a working sample: http://jsfiddle.net/banzor/700e6bn2/1/
And here is the code for my selectionChanged event.
$scope.selectionChanged = function(sender, args){
var index = args.row;
var row = args.panel.rows[index].dataItem;
var childPath = sender.childItemsPath;
var children = row[childPath];
if (children && wijmo.isArray(children)) {
console.log("Has items: " + children.length);
}
};
Am using http://www.jstree.com
i used var nodes=$('#jstree').jstree("get_json"); this code and i got follow object as result
. I just want only get children as like this.
how to get that
You can use the get_json function, just pass in the optional ID (the node from which to begin):
var nodes=$('#jstree').jstree("get_json","NODE-ID-HERE").children;
Keep in mind this approach will give you the children of the children too, but you can simply ignore those. If that does now work for you - loop through the result and remove the children property.
var instance = $('#jstree').jstree(true),
children = instance.get_json("NODE-ID-HERE").children,
i, j;
for(i = 0, j = children.length; i < j; i++) {
delete children[i].children;
delete children[i].children_d;
}
// children is now an array of all the node's children, but without their children
I'm working on a website which uses a tree structure made the following way : a list is created and if an element of this list is itself a list then it is append to the first list using appendChild. The big list is put in a div named 'tree'.
I would like to access the content of the div 'tree' and go through the nodes to display them.
I've tried to code it several ways but it doesn't work, does someone has any idea how to do it ?
Edit (my code was too long)
This function iterates through a DOM tree. You can pass it a callback that takes the parent and child element too:
_SU3.treeIterate = function(parent, callback) {
var children = _SU3.getChildren(parent);
for (var i = 0; i < children.length; i++) {
var child = children[i];
callback(parent, child);
_SU3.treeIterate(child, callback);
}
};
_SU3.getChildren = function(parent) {
var children = new Array();
var childNodes = parent.childNodes;
if (childNodes == null)
return children;
for (var i = 0; i < childNodes.length; i++) {
var child = childNodes[i];
if (child.tagName == "li" || child.tagName == "LI") {
children.push(child);
}
}
return children;
};
Note: in this example the getChildren() function only finds "li" items. Amend as necessary.
If you think you will need several other functions on the tree, I suggest you to have a look on jsTree
I've a function that takes an object as a parameter, and uses the structure of the object to create nested DOM nodes, but I receive the following error:
http://new.app/:75NOT_FOUND_ERR: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
What I would like my function to do, is, when supplied with a suitable object as a parameter, example:
var nodes = {
tweet: {
children: {
screen_name: {
tag: "h2"
},
text: {
tag: "p"
}
},
tag: "article"
}
};
It would create the following DOM nodes:
<article>
<h2></h2>
<p></p>
</article>
Here is my attempt so far:
function create(obj) {
for(i in obj){
var tmp = document.createElement(obj[i].tag);
if(obj[i].children) {
tmp.appendChild(create(obj[i].children)); /* error */
};
document.getElementById("tweets").appendChild(tmp);
};
};
I'm already struggling!
Ideally I'd like to eventually add more child key's to each object, not just tag, but also id, innerHTML, class etc.
Any hel would be much appreciated, though please: I'm sure a framework or library could do this for me in just a few lines of code, or something similar, but I'd prefer not to use one for this particular project.
If you could briefly explain your answers too it'd really help me learn how this all works, and where I went wrong!
Thank you!
NB: I've changed and marked the line in my function that the error message is talking about.
I changed it from:
mp.appendChild(obj[i].children);
to:
mp.appendChild(create(obj[i].children));
This is because I want any nested keys in the children object to also be created, so screen_name had a children key, they too would be created. Sorry, I hope you can understand this!
I'm looking at http://jsperf.com/create-nested-dom-structure for some pointers, this may help you too!
Your "create" function is going to have to be written recursively.
To create a node from your data (in general), you need to:
Find the "tag" property and create a new element
Give the element the "id" value of the element (taken from the data)
For each element in "children", make a node and append it
Thus:
function create(elementDescription) {
var nodes = [];
for (var n in elementDescription) {
if (!elementDescription.hasOwnProperty(n)) continue;
var elem = elementDescription[n];
var node = document.createElement(elem.tag);
node.id = n; // optional step
var cnodes = create(elem.children);
for (var c = 0; c < cnodes.length; ++c)
node.appendChild(cnodes[c]);
nodes.push(node);
}
return nodes;
}
That will return an array of document elements created from the original "specification" object. Thus from your example, you'd call:
var createdNodes = create(nodes);
and "createdNodes" would be an array of one element, an <article> tag with id "tweets". That element would have two children, an <h2> tag with id "screen_name" and a <p> tag with id "text". (Now that I think of it, you might want to skip the "id" assignment unless the node description has an explicit "id" entry, or something.)
Thus if you have a <div> in your page called "tweets" (to use your example, though if so you'd definitely want to cut out the "id" setting part of my function), you'd add the results like this:
var createdNodes = create(nodes), tweets = document.getElementById('tweets');
for (var eindex = 0; eindex < createdNodes.length; ++eindex)
tweets.appendChild(createdNodes[eindex]);
I added a function appendList that accepts a list of elements, and the container to append to. I removed the append to "tweets" part out of the create function to more effectively separate your code.
function create(obj) {
var els = [];
for(i in obj){
var tmp = document.createElement(obj[i].tag);
var children;
if(children = obj[i].children) {
var childEls = create(children);
appendList(childEls, tmp);
}
els.push(tmp);
};
return els;
};
function appendList(list, container){
for(var i = 0, el; el = list[i]; i++){
container.appendChild(el);
}
};
// gets an array of root elements populated with children
var els = create(nodes);
// appends the array to "tweets"
appendList(els, document.getElementById("tweets"));
Building on the previous answer:
I think you still need to create the element you're trying to append:
tmp.appendChild(children[prop].tag);
should be
tmp.appendChild(document.createElement(children[prop].tag));
function create(obj) {
for(i in obj){
var tmp = document.createElement(obj[i].tag);
var children;
if(children = obj[i].children) {
for(var prop in children)
tmp.appendChild(document.createElement(children[prop].tag));
}
document.getElementById("tweets").appendChild(tmp);
};
};
I have a element which contains 3 child. let says
<div class="parent">
<div class="firstChild">firstChild</div>
SecondChild
<ul><li>thrid child</li></ul>
</div>
In the example I need to select first 2 childs and not the UL. how to do through jquery.
You can use the :lt selector. http://api.jquery.com/lt-selector/ and the * selector.
$('div.parent > *:lt(2)')
This selector should do it.
$(".parent *").not("ul")
Try this:
$(".parent").children();
If you want the text node included, .clone() it and remove what you don't want like this:
var children = $(".parent").clone();
children.find("ul").remove(); //or: children.find(":gt(1)").remove();
//children now contains everything by the <ul>
I commented some in the original post about what nodes there really are in the poster's example markup.
Here is a little something to print out the "real" structure if anyone is interested. I just added an id to the parent element to get ahold of it a little easier when about to start walking the DOM:
<body>
<div id="parent" class="parent">
<div class="firstChild">firstChild</div>
SecondChild
<ul><li>thrid child</li></ul>
</div>
<script type="text/javascript">
(function (startNode) {
// Recursively walking the structure from the supplied node
function walk(node, indent) {
indent = (typeof indent==='undefined') ? '' : indent;
var children = node.childNodes;
var child, info;
// For each child of node...
for (var idx=0, len=children.length; idx<len; ++idx) {
child = children.item(idx);
// ..print it.
printNodeInfo(child, indent);
// If it was an element (tag) we try to display any children it might have
if (child.nodeType===1) {
arguments.callee(child, indentAdd+indent);
}
}
}
function printNodeInfo(node, indent) {
indent = (typeof indent==='undefined') ? '' : indent;
console.log(indent+getNodePrintString(node));
}
function getNodePrintString(node) {
var info = '';
// Check type and extract what info to display
if (node.nodeType===1) {info = node.nodeName;} // element nodes, show name
else if (node.nodeType===3) {info = trim(node.nodeValue);} // text nodes, show value
// If it was an empty textnode, return special string
if (!info) {return '[empty '+nodeTypes[node.nodeType]+' node]';}
else {return nodeTypes[node.nodeType]+': '+info+(node.id?'#'+node.id:'');}
}
// Just a utility function to trim values of textnodes
function trim(str) {
return str.replace(/^\s+/, '').replace(/\s+$/, '');
}
// Amount of indentation to add each level
var indentAdd = ' ';
// Mappings for nodeType => name of nodetype
var nodeTypes = {
1: '#Element'
, 2: '#Attribute' // not used right now
, 3: '#Text'
};
// Print info in start node
printNodeInfo(startNode);
// Start walking
walk(startNode, indentAdd);
})(document.getElementById('parent')); // Supply a start node
</script>
</body>
And here's the output:
#Element: DIV#parent
[empty #Text node]
#Element: DIV
#Text: firstChild
#Text: SecondChild
#Element: UL
#Element: LI
#Text: thrid child
[empty #Text node]
Here's how you can grab childnodes of an element, including "pure" text nodes (text not inside tags).
// Returns child nodes (including text nodes, if not empty) of 'node',
// but no more than 'limit' nodes.
// If limit given is not a number >= 0, it harvests as many as it can find.
function npupNodes(node, limit) {
// not a number or < 0 means 'no limit'
limit = (typeof limit!=='number' || limit<0) ? -1 : limit;
var result = [];
var children = node.childNodes;
var child, nodeType, captureCount=0;
// Loop over children...
for (var idx=0, len=children.length; idx<len && (limit<0 || captureCount<limit); ++idx) {
child = children.item(idx);
nodeType = child.nodeType;
// If it is an element or a textnode...
if (nodeType===1 || nodeType===3) {
if (nodeType===3 && !child.nodeValue.replace(/^\s+/, '').replace(/\s+$/, '')) {
// ..if it is a textnode that is logically empty, ignore it
continue;
}
// ..otherwise add it to the harvest, and increase counter
result.push(child);
captureCount += 1;
}
}
return result;
}
As you can see in the code, logically blank (all whitespace) textnodes are not returned.
Calling it like this with the markup in the poster's question, it does the job asked for (except for not using jQuery - sue me :)
var someChildren = npupNodes(document.getElementsByClassName('parent')[0], 2);