ArrayHandle null trying to enumerate <li/> menu items
To frame the opportunity at hand, I tried the same thing in the Chrome dev tools in browser, and I get the range back that I am expecting.
// AH is null querying for the <li/> from the parent menu.
public async Task<T[]> QuerySelectorAllAsync<T>(string selector)
where T : Element
{
var arrayHandle = await EvaluateFunctionHandleInternalAsync<DomHandle>(
"(element, selector) => element.querySelectorAll(selector)",
selector).ConfigureAwait(false);
// AH is null:
var properties = await arrayHandle.GetArray<T>().ConfigureAwait(false);
// ^^^^^^^^^^^
await arrayHandle.DisposeAsync().ConfigureAwait(false);
return properties.ToArray();
}
In my calling code:
// Selector "#menu", does return a valid element construct, AFAIK from debug inspection:
var ulMenu = await context.QuerySelectorAsync<HtmlUnorderedListElement>(S.Menu);
// Selector "li", null ref exception thrown from within, expecting HtmlListItemElement[].
var liCandidates = await ulMenu.QuerySelectorAllAsync<HtmlListItemElement>(S.Li);
// Will turn around and LINQ filter based on some other criteria, but not getting anywhere near that far.
var liServerItems = liCandidates.Where(ListItemWithImage).ToArray();
// ^^^^^^^^^^^^^^^^^
I'm doing that correctly, yes? I want all the <li/> elements child to the ulMenu.
Everything else being equal, I promise you it "should be" returning valid elements, from the Chrome console:
document.querySelector("#menu").querySelectorAll("li")
// #menu: <ul class="..." id="menu" />
// li: NodeList(20) [li.mm-active, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li, li]
There is obviously more within each of these elements, abbreviated for brevity.
Another data point for you, for giggles I tried the following.
var liContext = await context.QuerySelectorAllAsync<HtmlListItemElement>(S.Li);
And it "works". Sort it, but it will not work for us, I think, because these are "all" of the <li/>, not just the ones subordinate to the ulMenu that we want.
Maybe there is a better way to get those children, I do not know.
Note that the <li/> children are not all flat; it would be considered best for a depth first recursive search. I'm assuming that's how the console does it, but I could be mistaken.
After poking around a bit and exploring the query and child paths available, this one will work, and I rather prefer it actually. Seems to be focused on the direct child elements of the specified type, which is perfect, just what we need. Not that the other one ought not to work, in principle, but this one does as well, FWIW.
var ulMenu = await context.QuerySelectorAsync<HtmlUnorderedListElement>(S.Menu);
var liServerItems = await (await ulMenu.GetChildrenAsync<HtmlListItemElement>()).ToArrayAsync();
// ...and on from there, drilled through a couple other use cases, including another nested <li/>, also successfully.
The only thing I dislike about it, the lack of selector comprehension, in the event we need to provide more discernment there, but for what we are doing, I think it will be sufficient.
I'm doing that correctly, yes?
Your code looks fine, likely it's a bug. querySelectorAll returns a NodeList and there's currently no mapping for that yet.
The other QuerySelectorAllAsync methods do something slightly different. Something like the following should work.
var arrayHandle = await Handle.EvaluateFunctionHandleAsync(
"(element, selector) => element.querySelectorAll(selector)",
selector).ConfigureAwait(false);
var properties = await arrayHandle.GetPropertiesAsync().ConfigureAwait(false);
await arrayHandle.DisposeAsync().ConfigureAwait(false);
return properties.Select(kvp => kvp.Value.ToDomHandle<T>()).ToArray();
And it "works". Sort it, but it will not work for us, I think, because these are "all" of the
<li/>, not just the ones subordinate to theulMenuthat we want.Maybe there is a better way to get those children, I do not know.
You know querySelectorAll supports css selectors? You should be able to make a single querySelectorAll call
Awesome; duly noted, for future reference. Thank you... 🍻
We should fix the current implementation.
Cool. That'd be great, overall in general.
Although, I do have a workaround, which I think is a bit better suited to the target DOM in question.