hotwired / stimulus

A modest JavaScript framework for the HTML you already have
https://stimulus.hotwired.dev/
MIT License
12.74k stars 427 forks source link

Clarify how to declare multi-word controller names in docs #62

Closed joeybeninghove closed 6 years ago

joeybeninghove commented 6 years ago

Just something you might want to add to the docs eventually. After some experimenting with trying to get a multi-word controller working. I eventually realized that it has to be separated by a - instead of a _ like the controller file itself needs to be named.

<div data-controller="option-panel">
  <div data-target="option-panel.widget"></div>
  <div data-action="click->option-panel#show"></div>
</div>

... which points to ...

option_panel_controller.js

At first, I was putting _ in the markup data attributes before I realized it was a dash. This might be assumed by some folks, but still might not be a bad idea to mention it in the docs or in an FAQ somewhere.

I'm happy to submit a pull request for this as well but wasn't sure where or how you'd want to include this in the handbook.

Cheers :)

sstephenson commented 6 years ago

Thank you for the feedback! We do have the webpack filename-to-identifier mapping documented, but I agree it’s not at all obvious. I’d like to see if we can work this into the Handbook.

joeybeninghove commented 6 years ago

Oh snap! Sorry about that, I totally missed that. Cool deal! 👍

On Jan 18, 2018, at 7:27 PM, Sam Stephenson notifications@github.com wrote:

Thank you for the feedback! We do have the webpack filename-to-identifier mapping documented, but I agree it’s not at all obvious. I’d like to see if we can work this into the Handbook.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

geoffdavis92 commented 6 years ago

Had the same issue with camelCased data attributes for the Data API after the Stimulus render; of course I forgot my HTML5 training, but it may not be obvious to those who may not understand the semantics of data-* attributes.

ex: data-app-showMessage -> data-app-show-message

javan commented 6 years ago

Closing for now since this is documented in the installation guide and referenced in the handbook:

Learn how automatic controller loading works in the Installation Guide.

christhesoul commented 5 years ago

Hey @javan. As someone who is struggling a little with this right now, I'd love to help clarify it for other newcomers. Your link above 404s, and I'm struggling to find the right "vanilla" way of doing this.

e.g. Using without a Build System states the following:

application.register("hello", class extends Stimulus.Controller {
  static get targets() {
    return [ "name" ]
  }

  // …
})

Should the "hello" be "hello-world" or "helloWorld"? I feel like it should be helloWorld but I can only get it to work with the data-controller if it's hello-world.

Perhaps it might be clearer if examples were two-word controllers to begin with – as it's (arguably) easier to work backwards from two words than forwards from one?

Happy to help if I can. Thanks. 👍

javan commented 5 years ago

@christhesoul, hello-world is correct. See https://stimulusjs.org/handbook/installing#controller-filenames-map-to-identifiers.

axelerator commented 3 years ago

Hey @javan, fyi I believe this is also demonstrated in the wrong way in the screen cast.. They reference

data: {controller: "reset_form", action: "turbo:submit-end->reset_form#reset"}

when it really should be

data: {controller: "reset-form", action: "turbo:submit-end->reset-form#reset"}
sgelbart commented 1 year ago

How about for values from data attributes?

mirandashort commented 2 months ago

@javan sorry to resurrect this once more. Per the docs, my understanding is I should be writing things like the following:

data: { card-image_target: "custom-image-front", action: "change->card-image#preview-back }

However, only this works:

data: { cardimage_target: "customImageFront", action: "change->cardImage#previewBack" }

Additionally, my controller only connects when specified as data-controller="card-image".

Did something change and the docs are no longer up to date? Or am I doing something wrong that's causing the latter of my examples to work. Either way, the docs are still pretty unclear how to name things directly within the HTML, and I second having multiname controllers as all the examples might be more helpful

marcoroth commented 2 months ago

Hey @mirandashort, if you have a controller at app/javascript/controllers/card_image_controller.js and it has targets like:

static targets = ["customImageFront"]

You should be able to do:

data: { card_image_target: "customImageFront", action: "change->card-image#previewBack" }

The Rails helper transforms all underscores to dashes, so something like the above should work too.

Let me know if that helps!

mirandashort commented 2 months ago

@marcoroth I definitely expected that! That's exactly what my targets look like. But the only way I could get my code to work was to have it like

data: { cardimage_target: "customImageFront", action: "mousedown->cardImage#dragElement" }

And it's even rendered in the HTML as data-cardimage-target

image

I did use ./bin/rails stimulus:manifest:update to update my app/javascript/controllers/index.js and I noticed that it imported it as

import CardImageController from "./card_image_controller"
application.register("card-image", CardImageController)

I had to change it to cardImage for the controller to be working at all. When left as is, and referenced as data-controller=card-image, nothing happens.

Let me know if you would like for me to open a new issue for this

mirandashort commented 2 months ago

Well, not sure what difference it made, but it all works as expected when index.js is loaded like this:

// Import and register all your controllers from the importmap under controllers/*

import { application } from "controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)

// Load all the controllers within this directory and all subdirectories. 
// Controller files must be named *_controller.js.