I'm studying how react currently works and am a bit confused how to access the functions that are hidden in the props with native javascript. I'm aware if I download the react extension I can view them in the google developer console but this is not what I need. I don't have access to the react components directly because I'm making a Google chrome extension.
For example in the Chrome Developer Console, I can type the following:
var elem = document.querySelector('.wrap-XdW9S1Ib');
Lets just say that this element is my element of interest and it has an onClick event within it's props that I would like to access to automate clicks for testing purposes.
Attached is a picture of the progress so far:
I can then type something like...
elem.__reactProps$63clhtkk874
Which shows the below:
Note you can see the onClick event and other functions that react creates.
Now... if you try to do this same thing via code. In particular the for(key in elem){console.log(key);} for some reason __reactFiber and __reactProps do not appear!
Note: Notice that align,title,lang etc... all show up but the __reactProps are not there now.
Note#2: My code is identical to what you see above in the pictures and works just fine printing out to console (as you can also see in the screenshot), except..., I just don't see the react events.
Why do these show up in the developer console and NOT in the same console via my code I write. In otherwords, when I type in the console prompt it not via non prompt (I.E, just regular .js file)
I found the solution to this question, it is indeed because the chrome extension is in isolated memory space compared to the DOM. To get access to that variable I first have to inject my script into the regular DOM and then use chrome messaging api to send a message to my injected script to THEN get the variables I'm looking for. Hopefully this helps someone else out. I can see why my question was initially closed now as a duplicate, but none the less I think this may help some people that get confused by this particular issue when it comes to react.
I'm just guessing over here. But judging from the underscores you are probably accessing elements from React's internal virtual DOM. Which may or may not be the same as the DOM. I've read that React was built for the purpose of abstracting away the imperative DOM manipulation that vanilla javascript uses.
Though sometimes interacting with the DOM cannot be avoided, so whenever I see DOM manipulation in React, I think of the useRef hook. By setting the useRef hook to a variable and linking it to a DOM element, you can console.log variable.current, and see the real DOM element and work with it in a useEffect hook for example. Hope this was at least a little helpful! All the best in your learning endeavors!
Related
In my application I need to know when a user switches to show his screen instead of camera, both the local user and for other users. When I change to showing the user's screen, MesiboGroupcall_OnVideoSourceChanged is not called. The only listeners that are called is MesiboGroupcall_OnVideo and MesiboGroupcall_OnAudio for the local participant, and no listeners for remote participants.
Inspecting the participant through the console shows that the listener have indeed been set to be my desired function,
MesiboGroupcall_OnVideoSourceChanged: (newVideoSource, oldVideoSource) => {
console.log("MesiboGroupcall_onVideoSourceChanged: newVideoSource:", newVideoSource, "- oldVideoSource:", oldVideoSource);
}
but it won't run. Do anyone have any tips on getting this to work?
From what I can decipher reading mesibo.js, MesiboGroupCall_OnVideoSourceChanged is the only listener that is referenced only twice, when it is declared and when it is set in the call method. It seems like it isn't called elsewhere, for instance I would expect it to be called in to methods that change the video source like .setVideoSource(). I also find no reference to MesiboGroupcall_OnVideoSourceChanged in the source code for the live demo web application, which leads me to suspect that it might not be implemented yet or work correctly. If any mesibo devs read this, maybe they can clarify.
It would also be useful to get information back locally when the user allows or disallows the screensharing, are there any way of doing this with mesibo? I see other video conference providers do this through promises, but I have a hard time seeing if anything similar is available for mesibo, without having more documentation on the mesibo interface.
I thought maybe I can listen for it through the DOM, but haven't looked into doing that yet. If anyone has any experience or thoughts on this, that would also be great.
In dealing with JS frameworks like AngularJS, Angular, and React, I've observed that directly interacting with the DOM is discouraged, and can often lead to bugs, if you ignore the warnings. When I say "interacting with the DOM" I mean using document.getElementById('myElement') and similar methods to do some manipulation or read values from the document.
My question is essentially Why?. Is this a virtual DOM problem, where React (for example) isn't tracking the actual DOM, and therefore will be caught off guard if you make a change "on your own" without notifying React and subsequently updating the virtual DOM? Would Angular have the same problem in such a case?
If someone has knowledge of only a specific framework, I would be very interested to read the answer to my question even if it is not generalized. Obviously, I'm going to go google this some more, but I didn't see a similar question here yet, so I figured I'd post for posterity. Thanks in advance for any insights!
#HDJEMAI linked to this article which I'll repeat, as it's good advice: https://www.reddit.com/r/javascript/comments/6btma7/whats_so_wrong_with_direct_dom_manipulation/
I'll expand on some of those reasons below:
Modern frameworks like Angular and React are designed to hide the DOM because they want to abstract the DOM away. By using the DOM directly you break the abstraction and make your code brittle to changes introduced in the framework.
There are many reasons to want to abstract-away the DOM, and the Reddit page linked-to mostly focuses on "state management" because your framework (Angular, React, etc) will likely make assumptions about the DOM's state that will be broken if you manipulate the DOM directly, for example:
function this_is_your_code() {
tell_angular_to_make_my_sidebar_500px_wide();
document.getElementById('mysidebar').style.width = 700px;
var sidebar_width = ask_angular_for_sidebar_width();
console.log( sidebar_width ); // will print "500px"
}
Another reason to abstract away the DOM is to ensure your code works with non-traditional DOMs besides the typical web-browser document/window DOM environment, for example "server-side Angular" is a thing, where some of the Angular code runs on the server to pre-render HTML to send to the client to minimize application startup delay or to allow web-browsers without JavaScript to access your webpages, in these situations the normal W3C DOM is no-longer available, but a "fake" DOM is available but it's provided by Angular - and it only works through Angular's abstractions - it won't work if you manipulate document directly, for example:
function this_is_your_code_that_runs_in_nodejs() {
tell_angular_to_make_my_sidebar_500px_wide(); // this works and Angular's built-in abstraction of the DOM makes the appropriate change to the rendered server-side HTML
document.getElementById('mysidebar').style.width = 500px; // fails because `document` is not available
}
Really good answer from #Dai above, I would like to add on top of that. For most cases, you should not manipulate the dom directly. There are cases where you have to and it's the right thing to do.
For example, React and Vue has a concept of ref. Which can be though like an id and gives you the access to the dom node. Let's say you are building a chat application where you fetch old chats when the user scroll to the top and you need to keep the last visible chat in focus.
This kind of situations are there and we need to access the dom. The good practice is to keep such code encapsulated and use the framework way of accessing something instead of reaching out for the document/dom.
I have a web app which is developed using Polymer and want to implement end-to-end testing using JavaScript. That's why I am trying to programmatically set some value, but I'm unable to access the element's local DOM by either:
document.getElementById('nativeInput');
document.querySelector('#nativeInput');
Someone told me that it is not possible to access shadow-root elements directly and set a value on them. So my basic question is: How can I access an element's shadow DOM and set some value to its children?. Please let me know whether that is possible and if so, please share some solution.
See the screenshot to get a clearer understanding of what I am trying to accomplish, on the HTML element with my JavaScript selector, on #shadow-root (open).
Since it was created in open mode you should be able to access it via node.shadowRoot. That said, shadow dom exists to isolate internal structures of aggregate elements, so you should first check if the iron-input custom element provides a public API which allows you to set the value.
Since you're mentioning end-to-end testing, I want to point out that Polymer provides its own, separate tool kit for that purpose.
Regardless of the technology/testing framework you'll end up with, take a look at the implementation of paper-input's tests, since they solve the exact problem you're facing. Understanding concepts like component lifecycle might be essential here.
If you want to send some value with javascript outside of polymer element, you may add at root level, like you may bind value into polymer. Sometine like :
index.html
<dom-bind>
<template>
<my-app my-prop = "{{myProp}}" ></my-app>
</template>
</dom-bind>
<script>
var bindVal = document.querySelector('dom-bind');
bindVal.myProp = "Test"
</script>
so in <my-app> element, you have a myProp property with "Test" value.
I have a website set up with RequireJS and Angular, but at seemingly random moments, it will decide to either not load part of the Javascript or not databind part of the angular code.
The page in question has several different components on it with their own angular controllers. Everything loads fine about 90% of the time, but sometimes something will happen that prevents databinding (angular brackets visible, ng-hide not working,...). Additionally, the 'network' tab in Chrome devtools shows no files being loaded, though they are listed in 'sources'. I don't know if that is relevant somehow. I get no errors in the console at all.
Digging around in the JS console I've found that one of the broken controllers in question does exist ( = I get an object using angular.element(...).scope() ) but when I try to access one of its properties, they are either undefined OR in case of the init() function I use in all my controllers, it returns the function of the parent controller.
What could cause the controller to be loaded but its scope variables to be undefined at seemingly random times?
EDIT:
The only way I've found to sort of reproduce this issue without errors showing up in the console is to initialise the controller as an empty function. This produces similar scope behavior in the console, but it doesn't cause the angular curly braces to show up. I will accept any clue that leads me to the cause of the issue or a viable workaround.
It appears that RequireJS sometimes loaded everyting fast enough for the angular.bootstrap call to be executed before the DOM was completely loaded. This lead to angular processing what is already loaded and ignoring whatever came next. I therefore added a domReady requirement to the setup so I only bootstrap angular when I know the whole page will be there. Since it is hard to know for sure, I can only hope this was the cause and that we won't be seeing this issue again.
You might have to use AngularAMD. Works great for our angular website.
I was watching a video on making a good javascript application infrastructure. Basically what it said was:
Your application consists of components
Components are parts of the page that can act on their own.
components can be registered into te application.
upon registration, they get their own sandbox.
A sandbox is an component's interface to the application core.
The core is built on top of a javascript library.
Components only have access to their sandbox, not to other components, nore the core or the underlying library.
Now, what I'd like to make is an application where you can easily make new components. Components have their own part on tha page, their own div in which they can work. And here comes the first part of my question: I want to give these components a copy of the jQuery object, but that has an internal restriction applied so that it can only work inside a certain containing element.
The second part is,that even if a component has limited access to the DOM using jquery, it can still access the document. I have tried both setting Window and Document to null, before running my test script, but the browser doesn't allow this. Is there any way that I can truly restrict the possibilities of an object to the methods of 1 object that I pass to it?
You're mis-understanding the point here. The intention isn't "make it 100% imposible for a component to acces anything it shouldn't". The ONLY way to do that is the insanely complicated step that Facebook took which is to parse the JS/HTML code and re-write it to dis-allow certain references, etc. I'm betting it took their dev team 1,000+ hours to do and there are still holes in it.
Basically the intention is to give each component a sandbox to play with and then say "please only use this". The authors then comply with the request.
Your sole other option is iFrames, in which case a component can do whatever it wants and it won't effect anything (assuming you're on a different sub-domain and you provide a parent-window proxy).