dojo tree event on root nodes - javascript

**I'm building dojo tree using the following code:
The tree is displayed as expected. The problem that I have is that the onClick event is only fired on leaf nodes. When I click on the root level node(I have several root level) it is just open showing child nodes.
How can I add "extra" onClick functionality to the root nodes?

You've got openOnClick set to true for your tree. I think the API docs answer this as well as I possibly could.
http://dojotoolkit.org/api/dijit/Tree/openOnClick
That said, it looks like you'd be able to connect to _onClick instead and do whatever you want (that's the method responsible for calling onClick only when openOnClick is false, anyway). Or, if you wanted to feel a little less guilty about accessing private members, dojo.declare yourself a subclass of dijit.Tree, extending _onClick to also fire another function you define as public.

Related

Is it harmful to nest too many components inside a single one?

I have a multi-selectable table component which contains a table-disaply component. Inside the table-display component there is another component called table-row.
table-selectable
| (contains)
v
table-display
| (contains)
v
table-row
I am doing this because I would like to make each component genereic enough so that it can be used for other purpose, Howere, I realise it is not easy to pass the action up the the parent component. The reason is that I have to carefuly wire all the actions inside sendAction method and the action name inside the hbs file and I feel this probbaly may cause error(s) in the long wrong.
My question is that is it harmful to nest tom nay components inside a single component like the one I did?
Javascript prepares an HTML DOM Tree of Objects in a document loaded. This DOM is then available to you to work around with its elements.
Javascript access to HTML DOM is still slower than executing javascript without accessing HTML DOM.
The level you have mentioned is not too deep nested, so far you are you are easy to access the inner elements.
Events generated by elements always propagate toward Execution Context which Javascript engine has created to run the piece of your code. So, you can work with these events on Global level (which is "window" level most of the time) until you are registering the listener with proper HTML element to listen to the proper event, otherwise this will not work. For example, a button fires a "click" event, e.g.
document.getElementById('mybutton').addEventListener('click', function() {
console.log('my button clicked');
});
So far as you are successful to select this button, and bind the "click" event listener, you are OK. But if your element selector is wrong, or you are trying to listen to the wrong event, this will not work.
So far as the volume of the page is concerned, the more the content, the more page load time. Also consider it as an SEO perspective.

Imitating a click on a dynamically added element with vanilla JavaScript

I have a ReactJS-based website which I wanna navigate programmatically. Basically, the workflow is looped:
Click on Element1.
The web page code is dynamically altered, during which Element2 is added.
Click on Element2.
Etc, until, after clicking on ElementN, the web page returns to the initial state and Element1 is displayed again. Clicking on those elements is what I wanna automate from within the website itself.
I have an access to the JS file that is responsible for the website contents creation and alteration. I can locate the code which describes the elements I'm interested in, and add any extra event listeners if need be.
I'm almost completely new to the client-side development, so my approach to solving this task is purely intuitive. So far my idea was to add an event listener for some sort of "onAdded" event which would fire when the element is added to DOM, and from that listener call the "onclick" listener (or dispatch the "click" event in some other way). However, i can't find any events that would indicate an addition to the DOM tree.
So, strictly speaking, i have two questions:
Is the approach described above viable (and adequate)? If so, then how exactly do i accomplish it?
If i'm doing it all wrong then what would be the right way to accomplish my task?
Edit 1
As per Matthew Herbst's suggestion, I looked into React lifecycle methods like componentDidMount. Turns out, the elements I wanna automate clicking on are not independent React component but some other component's contents added inside the render method with a huge chain of createElement calls.
So now the problem switches from detecting a moment when a particular element is added to the DOM structure to finding a way to interact with it.
The easy (and ugly) way to do it, as I currently see it, is to use the window object from componentDidMount, locate the element I wanna click by its data-reactid attribute (which is a string of dot-separated digits which, from what I can tell, is generated dynamically and reflects the element hierarchy) and then dispatch the required DOM event.
It might work, but if the document structure changes then the values of the data-reactid then it's all broken again. I would prefer to somehow dispatch the React's own onClick event properly, but I don't know how. I tried calling the function that gets passed to the createElement method as a value of the onClick property from componentDidMount, but for some reason it doesn't work.
I have also tried the method of interacting with DOM described in this article, but in my case the ReactDOM object doesn't seem to be defined.
Since I'm not much of a client-side developer, especially not a React guru, I don't really see the whole picture of how the website's client logic is working, and the code I'm working with seems to be minified/obfuscated to make it even harder. So if anyone could provide any specific suggestions without sending me to read all the React documentation, I'd be grateful.
Okay, I'm not sure if a question as profane as mine should be answered at all, but it looks like I got it figured out.
The minified/obfuscated code I had to deal with still had prominent features of a React application, such as objects with series of callbacks like render, componentDidMount or componentDidUpdate. So, just like Matthew Herbst suggested, I looked into the things they do.
The elements clicking on which I needed to automate were created inside the render methods by long chains of createElement calls which looked something like this:
T["default"].createElement("li", null, T["default"].createElement("div", {
className: P["default"].img
}, T["default"].createElement("img", {
src: n(600),
alt: ""
}), T["default"].createElement("b", null , "+3")), T["default"].createElement("h4", null , "«Header text»", T["default"].createElement("b", null , "+3")), T["default"].createElement("p", null , "Description"), T["default"].createElement("div", {
className: P["default"].btn
}, T["default"].createElement(A.Btn, {
mod: "info",
onClick: this._router.bind(this, "/gtr", "gtr")
}, "Play")))
I should have posted that code in the original post, but back then I didn't really understand what's going on here.
It turns out, the object referred to by T["default"] is a React object, meaning that T["default"].createElement calls were actually equivalent to the React.createElement ones.
Then, the article by James K. Nelson helped, which explained that in order to locate a specific child of a component I need to assign a ref attribute to it. I needed to access that "Play" button, so I tried adding a ref property to what looked like its descriptor object, so it would look like
T["default"].createElement(A.Btn, {
mod: "info",
ref: "automatedElement1",
onClick: this._router.bind(this, "/gtr", "gtr")
}, "Play")
, and it worked. Now, inside the componentDidUpdate method I could use the code like
if (this.refs.hasOwnProperty("automatedElement1")) {
var buttonElement = this.refs.automatedElement1;
}
Unfortunately, I didn't quite understand how to get from this object to its DOM reflection, but by simply studying its contents I managed to find a property which corresponds to the value of the data-reactid attribute of an HTML element of that button. So then I found no smarter solution than to acquire the element's DOM node by using the document.querySelector method:
var buttonNode = document.querySelector('button[data-reactid="' + buttonElement._reactInternalInstance._rootNodeID + '"]');
if (buttonNode) {
buttonNode.click();
}
This might be a bad solution, but that's the solution I managed to find in my situation, and it works. Hope it helps anyone who had a rough encounter with a React application and didn't know where to start.

What does dojo.empty() / domConstruct.empty() do exactly

Let's say I register some widgets with some ids(let's say id1, id2) in someNode. Now if I do, domConstruct.empty(someNode), this will remove the widgets from someNode by doing someNode.innerHTML= "". But are the widgets still in memory?
What I mean to say is, after domConstruct.empty(someNode), will I be able to register a widget with id1 or id2?
If not, then how can I achieve the same? I do not want to check for widget with same id during its creation and destroy it if it exists.
P.S: I am assuming that dojo.empty() and domConstruct.empty() work in the same way.
dojo/dom-construct's APIs do not know anything about Dijit widgets, so when you run domConstruct.empty(node) or domConstruct.destroy(node), it does nothing to look for and destroy widgets. (I've explained how to do that in a largely-related question.)
When Dijit widgets are created, they are populated in a hash maintained by the dijit/registry module, which allows them to be accessed by ID (or node) in the future. dijit/registry.findWidgets is also used by dijit/_WidgetBase#getChildren (which is in turn used by container and layout widgets) to retrieve child widgets according to the DOM tree.
Since dojo/dom-construct knows nothing of Dijit, it simply destroys all DOM nodes underneath the given node, and doesn't update Dijit's registry. Thus, you end up with an inconsistent state, where Dijit thinks these widgets still exist, but their DOM has actually been destroyed. As answered in the other question, you should use findWidgets to properly destroy the widgets first, or consider using a layout widget or ContentPane to manage the child widgets for you.

Kendo - can two Observable objects use the "change" event on the same page?

I have a page that uses a Kendo MVVM approach for two different elements, one providing file search results, the other a document upload facility.
The problem I am encountering is to do with the change event that both elements use - it seems that when one control fires a change event it is then picked up by the other control, which then attempts to process the event and passes it on, at which point it is picked up by the second control's change handler which processes it and passes it on to the first control's change handler. As you might expect, after around 1500 repetitions of this cycle, I see a Uncaught RangeError: Maximum call stack size exceeded message as the JavaScript engine runs out of memory.
At first I thought the problem was that the container of the second model was contained within the first, but even if they are completely separate on the page it seems as though the problem still shows up, so now I'm wondering whether the problem is related to the event being global to the page.
It seems that anything I do in my event handler in terms of trying to stopPropagation or stopImmediatePropagation - or even to set the event to null altogether - makes no difference to this behaviour. Tracing the call stack I can see it looping through Kendo's trigger call then through the event binding on my object and jQuery's dispatch loops that lead it back to Kendo, where it triggers the event handler on the other observable object.
Removing my bindings does not affect the problem, the change event is still bounced back and forth between Kendo and jQuery in the same way, it just doesn't run through my code.
The answer here was not a direct consequence of Kendo itself, so it would have been hard to answer from the question as I set it.
Inside the Observable container that was raising this error, I was using Isotope for layout. The step I had missed was that I had a relationship like this:
Parent [Observable]
-> Container
-> Child
-> Child
-> Child
One of the things that Isotope brings to the party is that for each item in the child collection, it adds a reference to its parent object.
When the child is Observable that creates a structure like this:
Parent [Observable]
-> Container <--┐
-> Child ---|
-> Child ---|
-> Child ---┘
This is an ideal situation for events to be propagated from child to parent, but because the properties in question were being automagically added by the libraries in question it was very hard to troubleshoot.
The solution was to remove the Container layer from the Observable model - it didn't need to trigger anything on change and so I wrapped it in a simple getContainer() closure and used that everywhere I was previously using it as a property. This protected it from the Observable object, breaking the circular reference without harming the functionality.
It may also be relevant that as far as I can tell the initiating event was a DOM change event rather than one of Kendo's own events. The problem may have been avoidable by using a custom Kendo namespace but that would have been a significant change in a complex application and guaranteed to cause a lot of side effects.

Lateral communication in Polymer

Here is the problem:
Any two Polymer elements may need to communicate. No assumption is made as to where these elements might be in the DOM (or shadow DOM), this means one event cannot simply bubble up to another element.
The good old way to achieve this would have been to let events bubble up to the root node and then fire broadcast events on the root node for other elements to listen to.
This approach however breaks encapsulation and seems to go against Polymer's overall design. AngularJS for example provides an event broadcaster that keeps controllers from unnecessarily keeping references to the root node.
Can such approach be achieved with Polymer? Otherwise can this be solved with a different approach?
You should be able to do this using polymer-signals
http://www.polymer-project.org/articles/communication.html#using-ltpolymer-signalsgt
Quoting from the doc:
Your element fires polymer-signal and names the signal in its payload:
this.fire('polymer-signal', {name: "foo", data: "Foo!"});
This event bubbles up to document where a handler constructs and dispatches a new event, polymer-signal-foo, to all instances of . Parts of your app or other Polymer elements can declare a element to catch the named signal:
<polymer-signals on-polymer-signal-foo="{{fooSignal}}"></polymer-signals>

Categories

Resources