I have a big list of items / divs that I need to create programmatically, and I need to implement scrollIntoView buttons for each them. I know how to do it with refs.
Whether there is an alternative to refs that might be more performant?
I believe something like this will work:
onScrollClick(ev) {
ev.target.scrollIntoView();
}
render() {
return (
... <button onClick={this.onScrollClick}>Scroll This Element Into View</button>
)
}
That assumes you want to scroll the button itself into view. If that's not what you want, you'll have to be specific.
[edit] if it's not the element itself, but one of the elements parents, you can also find a parent with javascript apis, element.parentElement -- you can use that as many times as you need to find the relevant element.
Related
On an HTML page which repeats a nested structure like
<div>
<div class="ugga">
<button class="theButton">
</div>
</div>
several times, with one ".theButton" also having class "active", I would like to use jquery to find the button after the active button.
$(".theButton .active").parents(".ugga").parent().next().find(".theButton")
would roughly do the trick. However, this is still under development, so that I am not sure that the nesting level div/div/button as well as the parent element with ".ugga" will be stable. So whenever there is a structure change on the HTML side, I would have to change the above jquery-magic accordingly.
What is stable is that there will be a list of ".theButton" elements at some nesting level and all on the same nesting level.
Is there a simple way in Jquery to find the next button after the active one even if the structure is changed to just div/button or to form/div/div/button and the ".ugga" I rely on currently disappears? Something like
$(".theButton active").nextOnSameLevel(".theButton")
There's no short and simple solution I know of, which would let you to do that.
The most convenient way would be to have the HTML ready before setting up javascript for DOM manipulation. Even thinking of project updates I would personally spent that little while to change a small part of js.
However, if that's needed for some reason, then I would probably loop through the elements, to find the one I need, eg.:
var found = false;
$(".theButton").each(function(){
if(found){
// do something with $(this) ...
return false;
}
if($(this).hasClass('active')){
found = true;
}
});
JSFiddle
And yet another, oneliner solution:
$(".theButton").eq(($.inArray($(".theButton.active")[0], $(".theButton").toArray()))+1);
JSFiddle
This is for looking at all the other elements having the same parent as your element of interest.
$(".theButton active").siblings(".theButton");
This will return all the elements having theButton before and after your active button elements but if you're looking specifically for the element after active, use next() with a selector like this
$(".theButton active").next(".theButton");
<div>
<a href='...'>LINK</a>
<img class='image' />
</div>
<div>
...
</div>
I want to get a protractor element for the img tag with image class. I already know the link text 'LINK'. In other words, "How do I locate a sibling of a given element?".
The first line of the code could look like this:
browser.findElement(by.linkText('LINK'))
Any ideas?
Thanks & Cheers
Thanks for the inspiration. Here's my solution, not the one I was hoping for, but it works:
element(by.css('???')).element(by.xpath('..')).element(by.css('???')).click();
The chaining and the by.xpath, which allows to get back to the parent are the keys of the solution.
This is what I actually implement on a Page Object:
this.widgets['select-status'] = this.ids['select-status']
.element(by.xpath('following-sibling::div[1]'));
this.widgets['select-status.dropdown'] = element(by.css('.btn-group.bootstrap-select.open'));
The page is based on Bootstrap along with Bootstrap Select. Anyways, we traverse the DOM along the following-sibling axis. Refer to XPATH specification for yourself.
Using Xpath selectors is not a better choice as it slows down the element finding mechanism.
I have designed a plugin to address this specific issues: protractor-css-booster
The plugin provides some handly locators to find out siblings in a better way and most importantly with CSS selector.
using this plugin, you can directly use:
var elem = await element(by.cssContainingText('a','link text')).nextSibling();
elem.click(); //proceed with your work
or, use this as by-locator
var elem = element(by.cssContainingText('a','link text')).element(by.followingSibling('img'));
You can always checkout the other handy methods available here...
Now, you can find web elements such as:
Finding Grand Parent Element
Finding Parent Element
Finding Next Sibling
Finding Previous Sibling
Finding any Following Sibling
Finding First Child Element
Finding Last Child Element
And, guess what, everything you can find using 💥 CSS Selectors 💥
Hope, it will help you...
I am kinda stuck with something and I need your help.
I am trying to show context-menus only when a user right-clicks on a certain elements in the page.
I thought I solve this problem by using getElementByClassName(...) and adding an onClick listener to each one of the elements, and when the user clicks on any of them I will then create the context-menus. And then remove the content menu later when everything is done.
Problem is that I don't have the full class names of those elements, all I know that they start with "story".
I am not sure how to go about doing this. Is there a way to use regex and getting all elements with a class name of story? Or is that not possible.
Thanks in advance,
There's this library that allows for regex selectors.
<div class="story-blabla"></div>
$("div:regex(class, story.*)")
However, you may not want to implement a full library. There's another solution:
$('div').filter(function() {
return this.class.match(/story.*/);
})
This will return the objects you want.
You can do this using attribute starts with selector
document.querySelectorAll("[class^=story]")
I've got an image gallery where each item in the gallery has a unique ID I'm using to tie it to my backend so that I can run DB actions etc. I'm using the data attribute to hold the 'imageid' on the parent div of each image for example: data-imageid="168"
The image gallery items have alot of nested divs so on rollover/click I find myself doing alot of the below in order to run actions:
$(this).parent().parent().attr('data-imageid');
It doesn't feel like a clean solution or the best performance wise. How are other people handling this? What's the best solution? Whatever the solution, this must be a problem solved everyday.
Edit: I realize my subject line is vague but it further explains where my heads at with this problem.
You can specify a criterion to go "up to", so if you want to go up to the nearest div or li or whatever, either use jQuery's .closest() or a simple upTo() function:
function upTo(el, tagName) {
tagName = tagName.toLowerCase();
var el;
do {
el = el.parentNode;
if (el && el.tagName && el.tagName.toLowerCase() == tagName) {
return el;
}
} while (el)
}
This sounds suspiciously like you have a case of divitis. In any case you can use .parents([selector]) with a filter to make your code a bit less verbose. e.g.
$(this).parents(".classOfDivContainingData").attr('data-imageid');
or you could loop through the parent divs on initial load, and copy the data attribute to the "this" in your example. Is there a reason why you can't set the attribute here in the first place?
You can try this
$(this).parents("[data-imageid]:first");
I would recommend you to use additional attributes to the elements:
<div data-imageid="367">
<div>
<div data-parent-imageid="367">
</div>
</div>
</div>
So you can make action knowing only the element which fired the event. Using this solution you don't care about structure of the elements, move them in the DOM tree freely and performance will be improved too.
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()