How to Get React Element Props from HTML Element with Javascript? - javascript

I can inspect a component's props with the React developer tools. Is it possible to get the component's props from its corresponding HTML element from the console without using the developer tools?
The solution would be something like this:
const someElement = document.querySelector('.some-element')
getElementReactProps(someElement)
I tried to inspect the HTML element's properties __reactFiber$at69yqn7c1k and __reactProps$at69yqn7c1k but couldn't find any of its props that I see in the React developer tools.
I have also found other stack overflow threads but none of them worked. (React - getting a component from a DOM element for debugging, React - get React component from a child DOM element?, How do you inspect a react element's props & state in the console?)
Any ideas?

React does seem to store the correct properties in some parent elements, but not in child elements.
The code below works by walking down the path from the given parent to the target child in the react prop tree, after tracing it from the DOM tree. I've only tested it with a single app but I believe it works with all elements created by React 17+.
function getReactProps(parent: Element, target: Element): any {
const keyof_ReactProps = Object.keys(parent).find(k => k.startsWith("__reactProps$"));
const symof_ReactFragment = Symbol.for("react.fragment");
//Find the path from target to parent
let path = [];
let elem = target;
while (elem !== parent) {
let index = 0;
for (let sibling = elem; sibling != null;) {
if (sibling[keyof_ReactProps]) index++;
sibling = sibling.previousElementSibling;
}
path.push({ child: elem, index });
elem = elem.parentElement;
}
//Walk down the path to find the react state props
let state = elem[keyof_ReactProps];
for (let i = path.length - 1; i >= 0 && state != null; i--) {
//Find the target child state index
let childStateIndex = 0, childElemIndex = 0;
while (childStateIndex < state.children.length) {
let childState = state.children[childStateIndex];
if (childState instanceof Object) {
//Fragment children are inlined in the parent DOM element
let isFragment = childState.type === symof_ReactFragment && childState.props.children.length;
childElemIndex += isFragment ? childState.props.children.length : 1;
if (childElemIndex === path[i].index) break;
}
childStateIndex++;
}
let childState = state.children[childStateIndex] ?? (childStateIndex === 0 ? state.children : null);
state = childState?.props;
elem = path[i].child;
}
return state;
}
Example usage:
let itemRow = document.querySelectorAll("#item-row")[2];
let menuBtn = itemRow.querySelector("#more-button");
let props = getReactProps(itemRow, menuBtn);
//This may also work:
let props = getReactProps(menuBtn.parentElement, menuBtn);

Related

Javascript how to loop child element of children

I want to read an element's children and for each of the children, read their children.
I have done this but do not understand why it does not work:
var myElement = $('.a-container');
var myChildren = myElement.children();
for(var i = 0; i < myChildren.length; i++) {
var myGrandChildren = myChildren[i].children();
}
The error I get is myChildren[i].children() is not a function.
Is this not how to achieve what I'm trying to do?
You need to select the element inside the loop:
myGrandChildren = $(myChildren[i]).children();
Although in this case, jQuery.eq is more suitable:
myGrandChildren = myChildren.eq(i).children();

Javascript: Find the Parent Element Text

How do I find the Parent Attribute for a data-element (data-qa). I have a data attribute id, data-qa=productId1 , productid2, productid3. (for each row in the grid)
For each row number in a grid.
How do I tell if the parent Element has kendogridcell above?
I don't know what kendogridcell is, its not a class.
let dataQaElements = document.querySelectorAll(`[data-qa]`);
for (let i = 0; i < dataQaElements.length; i++) {
let attr = dataQaElements[i].parentElement;
// not sure what next code is
}
Currently team is doing Selenium test automation.
const dataQaElements = document.querySelectorAll(`[data-qa]`);
for (let el of dataQaElements) {
const parent = el.parentElement;
const kendogridcell = parent.getAttribute("kendogridcell"); // if exists "" or null if does not exist
}

How to go to a parent node from a node in a treeview of wijmo flex grid

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);
}
};

How to get child element in ExtJS 4

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()

How to iterate through a DOM tree?

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

Categories