Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework "find" extended CSS selector #1597

Open
Telroshan opened this issue Jul 17, 2023 · 8 comments
Open

Rework "find" extended CSS selector #1597

Telroshan opened this issue Jul 17, 2023 · 8 comments
Labels
enhancement New feature or request

Comments

@Telroshan
Copy link
Collaborator

I must admit I'm not very satisfied with the current find keyword
closest seems obvious because it's going to retrieve the closeST element, so obviously only one.

But when it comes to find, maybe is it because I'm not a native English speaker, but I "feel" it differently depending on the context

  • For hx-target, I think of it as retrieving a single element (which is correct)
  • But for hx-trigger's from keyword, and hx-include, I would expect it to return all elements matching the selector (which is not correct, current implementation only returns the first matching child)
    Examples for that second point:
<div hx-get="/search" hx-trigger="keyup from:find input[type='search']">
    ...
    <label>Some filter <input type="search"></label>
    <label>Some other filter <input type="search"></label>
</div>

Here, I would instinctively expect the div to listen for keyup on both inputs, or more if there were more of them.
Not only does it only retrieve the first matching child, the only way to accomplish such behaviour as of today would be using a standard CSS selector such as #result input[type='search'], which requires adding an ID / class to be able to select on that parent div specifically.

I find it confusing because the word find itself doesn't indicate if it's going to be one, or many elements

So, would it make sense to add a new keyword to make that clearer ? Which would btw add the feature of listening on multiple elements using from as mentioned above
Examples that come to mind:

  • find-first and find-all
<div hx-trigger="from:find-first input"></div>
<div hx-trigger="from:find-all input"></div
  • find-child and find-children
<div hx-trigger="from:find-child input"></div>
<div hx-trigger="from:find-children input"></div
  • closest-child and children
<div hx-trigger="from:closest-child input"></div>
<div hx-trigger="from:children input"></div

Feel free to suggest other ideas, especially given that my English isn't that great

For retro-compatibility, I would then suggest to keep find being an alias of whatever new keyword that would replace it, but deprecate it / undocument it

Let me know

@Telroshan Telroshan changed the title "Find" extended CSS selector Rework "find" extended CSS selector Jul 17, 2023
@alexpetros alexpetros added the enhancement New feature or request label Jul 17, 2023
@xhaggi
Copy link
Contributor

xhaggi commented Jul 18, 2023

Calling find in querySelectorAllExt seems wrong to me, because the function name querySelectorAllExt suggests something else. For next and previous, querySelectorAll is also used. What if we use findAll as a quick fix here? This way you could use :first-child if you are only interested in the first element e.g. from:find input:first-child.

BTW: renaming find to children sounds reasonable to me.

Edit: I was wrong, next and previous return a single item. I would also expect both to return a list of elements.

@Telroshan
Copy link
Collaborator Author

Telroshan commented Jul 18, 2023

Considering the following situation:

<div hx-trigger="input from:find input">
    <div>Something</div>
    <input type="text">
    <input type="text">
</div>

With the current find keyword, the parent div woud listen for the input event on the first of the two text inputs.

With your PR though:

  • The parent div would now listen on both inputs (that's why I was suggesting a retro compatibility for the find keyword as this would change the behaviour of an existing feature)
  • FYI, :first-child isn't an equivalent here, as the doc says:

The :first-child CSS pseudo-class represents the first element among a group of sibling elements.

<div hx-trigger="input from:find input:first-child">
    <div>Something</div>
    <input type="text">
    <input type="text">
</div>

Using :first-child, the div wouldn't retrieve any input at all since the first input isn't the first child of its sibling elements group, it's actually the second child

So I'm afraid it wouldn't fix the issue here

I agree with you that next and previous should allow the user to retrieve multiple elements if they want to, but here for retro-compatibility purposes as well, I think we'd better add another keyword to differentiate single element retrieval from multiple elements retrieval

@xhaggi
Copy link
Contributor

xhaggi commented Jul 19, 2023

Meh, you're absolutely right. I don't know why I thought it would return the first element. So let's first discuss what approach we want to take here before I adjust the related PR to it.

What if we used a function-like syntax similar to CSS pseudo-classes :has(), :not(), but without the colons? The old syntax will be deprecated and removed in 2.0.

closest(<selector>) (do we need first-closest() and closest() or does it not make sense?)
first-child(<selector>)
children(<selector>)
first-next(<selector>)
next(<selector>)
first-previous(<selector>)
previous(<selector>)

<div hx-trigger="input from:first-child(input[type="submit"])"></div>

@Telroshan
Copy link
Collaborator Author

Telroshan commented Jul 19, 2023

I like those ideas

  • I think closest should return only one element, as it mirrors the standard API
    If we want a multiple retrieval of parent elements, I don't think the "closest" keyword makes any sense anymore since it would return any parent matching the selector, so there wouldn't be any left notion of proximity, and "closest" implies the nearest one imo
    For that, maybe parents(<selector>) following your syntax would do the trick
  • I'm not sure about that function syntax with parentheses instead of the current one that is in the form clause <selector>
    I guess it's a matter of taste here, but if I'd have to pick, I think I would stick to the easiest syntax, in the way that just requiring a space between the clause and the selector will eliminate the "I forgot to close my parentheses" potential issues. But again, probably a matter of taste
  • I'm worried about the potential confusion that users could face between a first-child clause that wouldn't behave like CSS's :first-child, but maybe am I worrying too much here

@xhaggi
Copy link
Contributor

xhaggi commented Jul 19, 2023

I think closest should return only one element

I agree.

I'm not sure about that function syntax with parentheses instead of the current one that is in the form clause

The function syntax feels more natural to me and encloses the selector, as is done in CSS with :has(), etc. But yes, it's a matter of taste. Without we have to rename next() and previous() to something else to be backward compatible.

<div hx-trigger="input from:first-child(input[type="submit"])"></div>

vs.

<div hx-trigger="input from:first-child input[type="submit"]"></div>

I'm worried about the potential confusion that users could face between a first-child clause that wouldn't behave like CSS's :first-child, but maybe am I worrying too much here

Don't worry, the documentation will clarify this 😜

@Telroshan
Copy link
Collaborator Author

Either rename next/previous as you said, but we could also

  • not rename at all, thus we'd have to wait for htmx 2 to introduce breaking changes (I must admit I'm not fond of that option though)
  • introduce new keywords for the multiple retrieval versions instead, like next-siblings or previous-siblings or whatever. Again, I'm not a native English speaker so I don't really know if next / previous "feels" more single or multiple retrieval at the first glance (though as you said, we could rely on the documentation to clarify that)

@andryyy
Copy link

andryyy commented Jul 19, 2023

When using multiple keywords a one-time legacy name info could be helpful, shown in the console.

@yaakovLowenstein
Copy link

I've been looking for a find-all selector. Is there any chance of this happening?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants