Hotwire Discussion

Why does values work only on the controller?

Hello, I tried:

<div data-controller='comments'>
  <div data-comments-source-value="some3"></div>
</div>

And then it hit me, that it is only for the controller:

<div data-controller='comments' data-comments-source-value="some3">
</div>

Why is that? Why is that limitation?
I am using rails and I would like to render

<div data-comments-source-value="some3"></div>

In a partial down below? Is there a discussion or is it just a matter of fact it is not implemented?

Hi,

A controller is an object, values are default properties attach to this object. That is it.

If you explain a little bit more what you want to achieve I may can help you. Maybe there is is another way to do what you want.

Cordialement,

So this is my use case:

What I currently have:

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = ["name"];
  connect() {
    this.setResourceNameFromFilename();
  }

  /**
   * Setting the value of the field for the reource name if it is present.
   * @private
   * @param {Object} data The upload file data that is generated
   */
  setResourceNameFromFilename(fileName) {
    if (!this.hasNameTarget) {
      return;
    }
    this.nameTarget.value = fileName;

    let shouldStripExtensionFromFileName = false;

    if (this.nameTarget.dataset.shouldStripExtensionFromFileName == "true") {
      shouldStripExtensionFromFileName = true;
    }

    if (shouldStripExtensionFromFileName) {
      this.nameTarget.value = stripFileNameExtension(fileName);
    }
  }
}

<div data-controller="controller">
  <input type="text" data-should-strip-extension-from-file-name="true" data-controller-target="name">
</div>

And I want to write this with the new Values from 2.0.0

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = ["name"];
  static values = { shouldStripExtensionFromFileName: Boolean }
  connect() {
    this.setResourceNameFromFilename();
  }

  /**
   * Setting the value of the field for the reource name if it is present.
   * @private
   * @param {Object} data The upload file data that is generated
   */
  setResourceNameFromFilename(fileName) {
    if (!this.hasNameTarget) {
      return;
    }
    this.nameTarget.value = fileName;

    if (this.shouldStripExtensionFromFileNameValue) {
      this.nameTarget.value = stripFileNameExtension(fileName);
    }
  }
}

<div data-controller="some"
     data-some-should-strip-extension-from-file-name-value="true">
  <input type="text" data-some-target="name">
</div>

And my main concern is that in this case the value and the target go together.
It would not be maningfull to have the value without the target
In my opinion this is more meaningfull when the target and the value are supposed to work together.

<div data-controller="some">
  <input type="text" data-some-target="name" data-some-should-strip-extension-from-file-name-value="true">
</div>

If you are using a controller in many places as an abstract controller for lets say
Apples and Oranges and only the apples and oranges know their “nameValue”.

Then the apple partial would add the nameValue = apple.
And the oranges partial would add the nameValue = orange.

We would not need to use yield in the controller to get the yeilded name.
And nobody would do that and just use dataset instead. But using dataset is outside of the
controller stimulus scope and that is why I thought that it should encapsulate everythign.

Hi,

It’s a quick reply.

You have a file input. Sometime, this file input need a special operation.
What I will do is create a small controller for those special input for that special operation.

So, using your code:

<div data-controller="some">
  <input type="text" data-some-target="name">
  <input type="text" data-some-target="name" data-controller="strip-extension" data-action="input->strip-extension#update">
</div>

And 2 controllers:

import { Controller } from "stimulus";

export default class extends Controller {
  static targets = [
    "name"
  ]

  connect() {
    this.setResourceNameFromFilename(fileName)
  }

  setResourceNameFromFilename(fileName) {
    if (!this.hasNameTarget) return
    this.nameTarget.value = fileName
  }
}

And

import { Controller } from "stimulus";

export default class extends Controller {
  update() {
    this.element.value = stripFileNameExtension(this.element.value)
  }
}

If you give me a little bit more complete use case … You can attach the main controller on the input it self and have a value as stimulus 2.0 define it.
It depend on your real use case.

Thank you for the fast reply, sorry I could not get to you quicker.
I will give you more context:

I am using uppy.io to upload files.

<%= form.hidden_field :title, data: { uppy_dashboard_target: "name", should_strip_extension_from_file_name: something_other } if something %>

My idea is that because this field is progressively added it should not bloat the controller. And thus it would be easier to go to the defined values from Stimulus, and not the values in the dataset. I do not like going to the dataset, because there is not structure there and I would need to provide that structure.

I thought that values would give me that freedom and I did not think that they would be attached only to the controller main element.

In our project we do not want to attach two controllers:
1 for the uppy upload
1 for the automatic adding of the name to the field if it exists after success on uppy upload.

This means that we would have to have an api and two controllers that need to work in sync, when we can do it in one.
I am doing it in one currently. Using dataset. But I do not want to use dataset, because Values is way more convenient.