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

Add scoped JS selector support #2493

Closed
wants to merge 1 commit into from

Conversation

rktjmp
Copy link
Contributor

@rktjmp rktjmp commented Mar 1, 2023

Extends LiveView.JS's :to option to accept a two element tuple, where the first element is the traditional target selector (or nil) and the second element is a "scope selector".

The scope selector is applied to the emitting element via Element.closest(), finding the nearest matching parent, then the target selector is applied from the scope element, selecting all matching children.

Additionally nil may be given as the target selector to select the scope element itself, turning this into a "parent selector" interface too.

It can be useful to limit the selector search space for JS commands, without having to give every instance a unique dom ID, meaning components can "self restrict" their internal commands to their own peer nodes.

AlpineJS does this by defining a x-data attribute, which defines a context, but this option (defining a phx-js-root "scope attribute" and always looking up to see if we're inside one) isn't really practical for LV as we don't have the same ability to "break out" of the scope like alpine, so nested components could find themselves "locked in" by unknown parent components.

This means we need a two part selector, one do find the scope root -- which is always a parent of the emitting element -- and a second for the targets. It felt more natural to combine this under the to option rather than adding an additional scope/parent/inside option. I went with a tuple {target, scope}, because a list may imply "apply to all these selectors", and a tuple is less syntax and more defined than a map. Since we can't JSON encode tuples, they are converted to two element lists in the ops field for processing on the javascript side (they may be better described by a map however).

The tuple could be extended to support {target, scope: "scope", opt: x}, where {string, string} is an alias for {string, scope: string}.

Additionally, since the "target selector" always looks "inside" the scope element, it's impossible to target the scope element itself, which is useful to set component-wide attributes. In this case nil can be used as the target selector to target the scope element (sort of synonymous to the current to: nil behaviour).

Extends LiveView.JS's `:to` option to accept a two element tuple, where
the first element is the traditional target selector (or nil) and the
second element is a "scope selector".

The scope selector is applied to the emitting element via
`Element.closest()`, finding the nearest matching parent, then the
target selector is applied from the scope element, selecting all
matching children.

Additionally `nil` may be given as the target selector to select the
scope element itself, turning this into a "parent selector" interface
too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant