Looking at the documentation for videoJS for the mouseTimedDisplay and trying to understand it better.
How to I use the $ selector?
(Thinking I then can avoid using document.querySelector to get elements/components.)
It's a wrapper around querySelector that will search the component's element by default, unless a different starting element is given as a starting element.
Given the standard controls, player.controlBar.progressControl.seekBar.mouseTimeDisplay.$('div') would return the inner div (with the vjs-time-tooltip class) of the MouseTimeDisplay component.
<div class="vjs-mouse-display">
<div class="vjs-time-tooltip" aria-hidden="true"></div>
</div>
If you wanted the component's element (with vjs-mouse-display), you just use el().
You'd mostly use it when creating/extending custom player components.
Related
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 ShadowRoot.
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
I can use the following to get an element:
document.getElementById('the-container');
Is there a way to get a child (not necessarily an immediate child) of this component.
<div id="the-container">
<div class="whatever">
<form>
.....
I'd like to get the form element, without adding an id/class or targeting it via the form tag (might be other forms on page).
No jquery but happy for HTML5.
querySelector is a property of Element objects and takes a selector as its first argument.
document.getElementById('the-container').querySelector("form");
You could also use it directly on the whole document with a more elaborate selector:
document.querySelector('#the-container form')
EDIT: So it seems to be an issue with selectors? Does jqLite not support selectors or some reduced version of them?
find('input') and find('button') will return results but if I try to filter it with a ":first" or something then it returns no results.
I can't seem to get jqLite's find() to return any child inputs of my div.
I have a $watch on a boolean function that my ng-show uses. So when this div becomes visible I want to apply focus on the div element and then find the first input descendant and focus on that.
example div element that the directive watches:
<div myDirective="function()">
text and stuff
<button>
<another button>
</div>
<div myDirective="function()">
<input>
</div>
this is my helper function in my directive:
function highlightAndFocus(node) {
// focus the div
node.focus();
// get angular's jqlite wrapped element
var task = angular.element(node);
task.addClass('highlight');
// these return empty statements
console.log(task.find('input:first'));
console.log(task.find('button:visible:not("#cancel"):first'));
}
The angular documentation says it finds only by tag name but isn't that what "input" and "button" are?
https://docs.angularjs.org/api/ng/function/angular.element
What's going on here? It seems silly to include jquery just for this one usecase when it seems like it should be supported. I'm printing the var task and I can see the input child elements in the web console.
JQlite is not the same thing as jQuery. If jQuery is available on the page, Angular will use it, but if it isn't, jQlite is used instead.
The docs clearly say that jQlite's .find() only supports lookup by tag names, it doesn't to work with additional selectors (like :first).
You can use the standard DOM APIs instead, namely Element.querySelectorAll(), if you really need it.
For draggable divs in JS on my page, I want to store the last location in local storage so that when a user refreshes, the draggable elements on the page stay put.
My HTML is in general like this:
<div id="some_id" class="draggable">
<p>I am a draggable thing.</p>
</div>
I then use the id of the div as a key in local storage so that having multiple draggable objects on the page doesn't result in them all being given the same position on refresh.
However, templates like this are sometimes used inside a template which handles visibility, so sometimes they'll be like this:
<div class="visibility_container draggable">
<button class="close_button">Close</button>
<div id="some_id">
<p>I am a draggable thing.</p>
</div>
</div>
Note that the draggable class is added programmatically each time.
These templates may vary but will never have ids within them – they'd be pretty terrible templates if they did – so I only need to find the first descendant element which has an id and use the value of that id as my local storage key.
How can I find the nearest element with JS? I'm aware that jQuery has a .closest() method which finds the nearest ancestor – I need to go in the opposite direction. I'm also aware of jQuery's .find() which can find me all descendants matching a selector, but I'm unsure I can guarantee the order in which jQuery returns these children as the API docs were not clear on that point.
I'm also aware of jQuery's .find() which can find me all descendants matching a selector, but I'm unsure I can guarantee the order in which jQuery returns these children as the API docs were not clear on that point.
find lists elements in document order (aka "DOM order") (and you're right, I'm surprised not to see a clear statement of that in the docs). "Document order" is a well-defined DOM term, it means a depth-first search of the descendant elements. Or put it another way: The one whose text is first in the markup.
So for instance:
<div id="container">
<div>
<div>
<div id="one"></div>
</div>
<div id="two"></div>
</div>
...then
console.log($("#container").find("[id]").first().attr("id"));
...will log one, not two.
This document order thing is common across most of the jQuery API and DOM methods like querySelectorAll, getElementsByTagName, and such. I'm not having any luck finding a clear statement of it in the jQuery documentation, though, which seems like an oversight. The closest I've found so far is a bit documenting an exception to that (e.g., saying here that "The second and third...create a jQuery object using one or more DOM elements that were already selected in some other way...unlike most other multi-element jQuery operations, the elements are not sorted in DOM order." [my emphasis].) The multiple selector docs also point out that the results will be in document order (not the order of the selectors).
I want to access a simple button in an unknown nested level of a container.
Using container.children('button') allows me to access buttons in the first level, I.E.:
<div>
<button>test</button>
</div>
Trying to use the same with the following construct:
<div>
<div>
<button>test</button>
</div>
</div>
Fails, because the button is not a direct children. I could use element.children().children('button') but the depth of the button can change and this feels too strange.
I can also write my own function to iterate though all children to find what I need, but I guess jQuery does already have selectors for this.
So the question is:
How can I access children in an unknown depth using jQuery selectors?
How about
container.find('button');
by using .find()