stimulus_reflex icon indicating copy to clipboard operation
stimulus_reflex copied to clipboard

Allow to execute CableReady operations on `StimulusReflex::Element`

Open marcoroth opened this issue 4 years ago • 5 comments

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

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

marcoroth avatar Apr 14 '21 21:04 marcoroth

Deploy Preview for stimulusreflex ready!

Name Link
Latest commit 1f38f9e534a52cbc9fd8238f74950738e4e56cf8
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.

netlify[bot] avatar Feb 20 '23 22:02 netlify[bot]

Wooooah this is wild :heart:

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

Matt-Yorkley avatar May 26 '23 15:05 Matt-Yorkley

@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.

marcoroth avatar May 26 '23 15:05 marcoroth

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!

Matt-Yorkley avatar May 26 '23 18:05 Matt-Yorkley

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

marcoroth avatar May 30 '23 18:05 marcoroth