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

Allow to execute CableReady operations on StimulusReflex::Element #489

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

marcoroth
Copy link
Member

@marcoroth marcoroth commented Apr 14, 2021

Type of PR

Feature

Description

As of today we just have one StimulusReflex::Element instance which is available as element in your reflex.

This PR enables to call CableReady operations on any instance of the said StimulusReflex::Element class. Like this we enable a very DOM-like and natural API in a reflex action to operate on those elements.

Additionally it adds another element accessor to the reflex class named controller_element. This is the element in the DOM which holds the Stimulus Controller you are operating on.

This enables scenarios like:

class CounterReflex < StimulusReflex::Reflex
  def increment
    @count = element.dataset.count.to_i + element.dataset.step.to_i

    element.inner_html(html: @count)
    element.dispatch_event(name: 'increment', detail: { count: @count })
    element.set_focus

    controller_element.set_dataset_property(name: "counterValue", value: @count)

    morph :nothing
  end
end

This PR is part of a bigger story. The PR #490 proposes the introduction of StimulusReflex targets. With that you can declare any DOM node as a StimulusReflex target (like you do in your Stimulus controller). This enables you to then access and operate on the targets in your Reflexes the same way you can with element and controller_element.

Why should this be added

Makes the API even more awesome and straight-forward, it feels like you are operating on an actual DOM Node via the actual DOM API. It also makes the use of CableReady more transparent.

Checklist

  • My code follows the style guidelines of this project
  • Checks (StandardRB & Prettier-Standard) are passing

@marcoroth marcoroth mentioned this pull request Apr 14, 2021
3 tasks
@leastbad leastbad added enhancement New feature or request proposal ruby Pull requests that update Ruby code labels Apr 30, 2021
@leastbad leastbad added this to the 3.5 milestone Apr 30, 2021
@leastbad leastbad modified the milestones: 3.5, 4.0.0 May 23, 2021
@netlify
Copy link

netlify bot commented Feb 20, 2023

Deploy Preview for stimulusreflex ready!

Name Link
🔨 Latest commit 1f38f9e
🔍 Latest deploy log https://app.netlify.com/sites/stimulusreflex/deploys/63f41f71c0efa500088047dd
😎 Deploy Preview https://deploy-preview-489--stimulusreflex.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@marcoroth marcoroth force-pushed the cable-ready-on-elements branch from 0bc4041 to 3e6caf9 Compare February 20, 2023 22:35
@marcoroth marcoroth marked this pull request as ready for review February 21, 2023 00:37
@Matt-Yorkley
Copy link
Contributor

Wooooah this is wild ❤️

Is element.broadcast getting called implicitly somewhere when the reflex is finished? It's not called explicitly in the example...

element.inner_html(html: @count)
element.dispatch_event(name: 'increment', detail: { count: @count })
element.set_focus

@marcoroth
Copy link
Member Author

@Matt-Yorkley Yeah, StimulusReflex calls cable_ready.broadcast at the end of every reflex execution. This is also already happening today if you use the cable_ready inside a reflex action.

But since calling element.inner_html(...) just enqueues a regular operation using cable_ready under the hood it's also getting flushed at the same time.

@Matt-Yorkley
Copy link
Contributor

Matt-Yorkley commented May 26, 2023

I just gave this a little live-test on top of 3.5.0-rc2 and it almost works perfectly, except the selector attribute on the element is in xpath format and the cable ready operations default to xpath: false.

StimulusReflex::Channel transmitting {"cableReady"=>true, "operations"=>[{"selector"=>"/html/body/section[1]/div[1]/div[2]/button[1]", "xpath"=>false, "text"=>"TEST", "reflexId"=>"b913191f-bf74-49b0-8e07-c15ecae87964", "operation"=>"textContent"}

Looks like it just needs a single slash instead of a double in StimulusReflex::Element#method_missing:

-- xpath = selector ? selector.starts_with?("//") : false
++ xpath = selector ? selector.starts_with?("/") : false

It works!

@marcoroth
Copy link
Member Author

@Matt-Yorkley this is great news, thanks for giving this a shot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request proposal ruby Pull requests that update Ruby code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants