How to access light DOM info from Javascript in Polymer - javascript

Question:
In Web Components specification, when you want to read elements within a Light-DOM from the template the <content select></content> element can be used. But, how can this information be retrieved from the javascript code of the component?
Example:
<wc-timer>
<wc-timer-title>I want to read this from JS</wc-timer-title>
</wc-timer>
Thanks in advance, Javier.

Remember that this inside of your prototype methods refers to the element itself. IOW, just like you could do element.innerHTML or element.firstChild you can write this.innerHTML or this.firstChild.
Simple mode:
domReady: function() {
console.log(this.textContent);
}
http://jsbin.com/bociz/2/edit
This gets more complicated if you are using <content> to project nodes through multiple levels of Shadow DOM. In this case, you will need to use getDistributedNodes api of the <content> node itself.
Before getting into that, I suggest you start with the simple version, and ask a follow up question if you get into trouble.

Use this, for accessing lightDOM and
use this.shadowRoot to access shadowDOM

I have no idea what the template renders out as to the dom, but maybe you can try this:
//jQuery
$('wc-timer-title').text();
//Plain
document.getElementsByTagName("wc-timer-title")[0].innerHTML;

You should be able to use /deep/, it is being deprecated but there is no date as to when that will happen.

Related

GetElementById from within Shadow DOM

I have a custom-element with shadow DOM, which listens to attribute target change.
target is supposed to be the ID of the element which my component is supposed to be attached to.
I've tried using querySelector and getElementById to get the element of the outer DOM, but it always returns null.
console.log(document.getElementById(target));
console.log(document.querySelector('#' + target));
Both of the above return null.
Is there a way to get a reference to the element in the parent document from within shadow DOM?
You just have to call Shadow​Root.
this.shadowRoot.getElementById('target') should work.
Here's an example, the get syntax will bind an object property to a function.
get target() {
return this.shadowRoot.getElementById('target');
}
There are two use cases of shadow DOM as far as I can see:
You control the the shadow DOM solely through your hosting custom element (like in the answer of #Penny Liu). If you want make sure no other script should call and alter the nodes than this is your choice. Pretty sure some banking websites use this method. You give up on flexibility though.
You just want to scope some parts of your code for styling reasons but you like to control it via document.getElementById than you can use <slot>. After all, many libraries rely on the document object and will not work in shadow DOM.
Back to the problem, what you probably did was something like this:
shadowRoot.innerHTML = `...<script>document.getElementById('target')</script>`
// or shadowRoot.appendChild
This is NOT working! And this is not how shadow DOM was anticipated to work either.
Recalling method 2, you SHOULD fill your shadow DOM solely by <slot> tags. Most minimal example:
<!-- Custom Element -->
<scoped-playground>
<style>some scoped styling</style>
<div id="target"></div>
<script>const ☝☝☝☝ = document.getElementById('target')</script>
</scoped-playground>
<!-- Scoped playground has a shadowRoot with a default <slot> -->
...
this.shadowRoot.innerHTML = "<slot>Everything is rendered here</slot>";
...
More advanced <slot> examples can be found at:
https://developers.google.com/web/fundamentals/web-components/shadowdom#composition_slot

How to Create a Custom Element with a Shadow Root Already Attached

Having a simple custom element
document.registerElement('x-foo', {
prototype: HTMLElement.prototype;
});
I can create an HTML node
<x-foo></x-foo>
then select it in JavaScript, and attach a shadow root.
var xFoo = document.querySelector('x-foo')[0];
var root = xFoo.createShadowRoot();
root.textContent = 'I am a shadow root';
However, I would like the objects to be created with a predefined
shadow root, without any JavaScript manipulations afterwards, as it is with
<input> and other user-agent defined nodes.
How would I define a constructor or something for my element in order to achieve this?
Question is a bit old, but putting this answer here in case you haven't figured it out yet.
There are 4 lifecycle callback methods associated with custom elements. Copying from this nice tutorial on html5rocks.
So to answer you question, you can put your code to attach a shadow-root to custom element inside createdCallback and it will be executed every time your x-code element is initialized.
This is a sort of constructor for your custom element.
Hope it helps.

How do I use jQuery on an HTML document instead of the DOM?

I'm trying to modify an HTML document, but its not the same as the DOM. However, I found that the syntax that I used with the DOM itself doesn't work with the other document. For example, I could find the title using $("title") with the DOM. However, with the document I have to use doc.find("title"). There are other, more involved changes and I'm stuck on how to proceed with this. Is there a reference I can look at? I know about the jQuery documentation, but that assumes that you're manipulating the DOM itself.
From what I've gathered the $ function assumes it's default scope for selectors is the active document. if you create jQuery objects that are not in the body of the document, the $(object).find(selector) is your best way to select within that object. The rest of the functions should work fine, at least the ones dealing with selecting, transversing and manipulation.
I should add that if the object is a jQuery object, there is no need to use the $. All the jQuery functions will be available to that object. So if you create:
var obj = $('<div>some text</div>');
you can use obj.addClass('cool) to get a jQuery object containing
<div class="cool">some text</div>
You can use jQuery on your doc by using the following
$("title", doc)
You pass the string "doc" to jQuery and it will use that instead of the DOM

What if I don't declare an ID in <div>?

How can I access any <div> if I don't declare the id attribute. Does DOM create ID itself?
e.g.
<div class="common_class" onmouseover="know_your_div(this)">
</div>
<script type="text/script">
function know_your_div(obj){
/*
Here i want to access the div object not by class because of it's common
for all div
*/
}
</script>
Well, the answer to your question is right there in your code.
The obj parameter that your know_your_div function takes is supplied as this in the onmouseover attribute. Thus, that is your div.
There's not an easy way to get to it in all browsers. Your best bet is to just create an ID on it. Is there a reason you can't?
Short of that, you have to navigate to it using DOM traversal methods, which are horribly unstable if your DOM structure changes at all. Code like:
document.body.childNodes[3].childNodes[2].childNodes[4];
or
document.getElementsByTagName('DIV')[22]; // 23rd DIV in the page
etc...
The answer is in your Question, let me try to help you
<div class="common_class" onmouseover="know_your_div(this)"> </div>
var oldObject = "";
function know_your_div(obj) {
// write ur condition if/ese/while/..
obj.parentNode.do_Something(); OR obj.parentNode.ID/Class/value
oldObject = obj;
}
then I guess you need to specify the ID explicitly alongside the class name..DOM won't create the ID itself...
Then it's time to use the DOM. Maybe you could use things like firstChild, lastChild, nextSibling.. http://de.selfhtml.org/javascript/objekte/node.htm
If you're using a JS library, like MooTools or jQuery, which I reccomend, you'll have a lot of powerful selector magic at your hands (example http://mootools.net/demos/?demo=Slick.Finder).
Why not use JQuery and selectors?
http://api.jquery.com/id-selector/
No, the DOM does not create an ID. You need to add an ID. You can use jQuery to access a div by it's class.

browsing through nodes

this is what an html structure of the webpage looks like:
<body>
<form>
<input type='file'/>
</form>
<div id='list'>
<div>value here<input id='delete' type='button'/></div>
</div>
</body>
i have found javascript code that triggers on 'delete' button click and removes input 'file' element. it uses this piece of code where element is input 'file' mentioned above:
deleteButton.onclick=function(){this.parentNode.element.parentNode.removeChild(
this.parentNode.element );}
i am trying to understand logic(rules) behind 'this.parentNode.element' ? why not accessing element directly 'element.parentNode.remove...'
many thanks
i am trying to understand logic(rules) behind 'this.parentNode.element' ?
There's no element property on the Node, Element, HTMLElement, or HTMLDivElement interfaces. So my guess would be that elsewhere in that code, you'll find something that's explicitly adding that property to the element instance of the div containing the button. You can do that, add arbitrary properties to element instances. These are frequently called "expando" properties and should be done very, very, very carefully.
Not the answer to the question, just opinion. It's better avoid constructions like
this.parentNode.element.parentNode
Because in case when you change your DOM structure, you will need rewrite you JS. So I think it's better to give id attributes to tags, and use next construction to get DOM element:
document.getElementById('element_id')
or if you will use some js framework (like jQuery) you can use even easier construction to get DOM element
$("#ement_id")
Ok, "removeChild" is a strange method, and quite probably, ill-conceived. It should look like:
<div>value here<input id='deleteMe' type='button'/></div>
var node = document.getElementById('deleteMe');
node.remove(); // <--- does not exist, but sure would be nice!!!
No, instead we have to do these shenanigans:
var node = document.getElementById('deleteMe');
node.parentNode.removeChild(node); // verbose! Convoluted!
We have to get the node's parent, call the method, then refer to the node again. This doesn't look like any other DOM methods as far as I recall. The good news is you can make it happen all in one line, chained, like a jQuery method.
You are best served to start over or copy somebody else's code. The use of "this" means it was within an object (or class), referring to other methods or properties within that object. You should stick to non-object variables and functions for now.
Hope that helps.

Categories