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 changing the submitter text during form submission #869

Merged
merged 2 commits into from
Feb 23, 2023

Conversation

afcapel
Copy link
Collaborator

@afcapel afcapel commented Feb 10, 2023

This change introduces a new optional data-turbo-submitting-text attribute that can be set on submit elements (inputs or buttons) in Turbo forms.

<form action="/" method="post">
  <input type="submit" value="Save" data-turbo-submitting-text="Saving...">
</form>

When the form is in a submmiting state Turbo will change the submitter content -the input value for inputs, and the innerHTML for buttons- with the data-turbo-submitting-text, and restore the original value when the submission ends.

This is a common requirement in many apps, to style the form submitting state and give feedback to the user that a click is already being processed.

This change introduces a new optional data-turbo-submitting text
attribute that can be set on submit elements (inputs or buttons) in
Turbo forms.

      <form action="/" method="post">
        <input type="submit" value="Save" data-turbo-submitting-text="Saving...">
      </form>

When the form is in a submmiting state Turbo will change the submitter
content -the input value for inputs, and the innerHTML for buttons- with
the data-turbo-submitting-text, and restore the original value when the
submission ends.

This is a common requirement in many apps, to style the form submitting
state and give feedback to the user that a click is already being
processed.
@seanpdoyle
Copy link
Contributor

Is this inspired by its rails/ujs predecessor? That attribute's name was [data-disable-with]. Is there a reason that this attribute name diverges from the others ([data-method] to [data-turbo-method], [data-confirm] to [data-turbo-confirm], etc.)?

Copy link
Collaborator

@kevinmcconnell kevinmcconnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Just 2 minor questions.

input.value = this.originalSubmitText
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor thing, but setSubmittingText and resetSubmittingText are quite similar. I wonder if it would simplify things to use single method, like replaceSubmitterText that sets the new content and returns the previous content.

Then setSubmittingText becomes:

this.originalSubmitText = this.replaceSubmitterText(this.submittingText);

and resetSubmittingText becomes:

this.replaceSubmitterText(this.originalSubmitText)

The guard clause would mean it's still conditional on there being some submit text configured.

Could have setSubmittingText and resetSubmittingText be little wrappers that call the common method, or just inline them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gave that try, the whole change becomes:

  setSubmittingText() {
    this.originalSubmitText = this.replaceSubmitterText(this.submittingText)
  }

  resetSubmittingText() {
    this.replaceSubmitterText(this.originalSubmitText)
    this.originalSubmitText = undefined
  }

  replaceSubmitterText(replacement: string | undefined | null) {
    if (!this.submitter || !replacement) return

    let originalValue

    if (this.submitter.matches("button")) {
      originalValue = this.submitter.innerHTML
      this.submitter.innerHTML = replacement
    } else if (this.submitter.matches("input")) {
      const input = this.submitter as HTMLInputElement
      originalValue = input.value
      input.value = replacement
    }

    return originalValue
  }

That works and removes a bit of duplication, but in practice it feels that the new replaceSubmitterText is harder to grasp, and a tiny bit longer, than the two original methods:

  setSubmittingText() {
    if (!this.submitter || !this.submittingText) return

    if (this.submitter.matches("button")) {
      this.originalSubmitText = this.submitter.innerHTML
      this.submitter.innerHTML = this.submittingText
    } else if (this.submitter.matches("input")) {
      const input = this.submitter as HTMLInputElement
      this.originalSubmitText = input.value
      input.value = this.submittingText
    }
  }

  resetSubmittingText() {
    if (!this.submitter || !this.originalSubmitText) return

    if (this.submitter.matches("button")) {
      this.submitter.innerHTML = this.originalSubmitText
    } else if (this.submitter.matches("input")) {
      const input = this.submitter as HTMLInputElement
      input.value = this.originalSubmitText
    }
  }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I like the one that removes the duplication :) I don't have very strong feelings about it though.

Comment on lines +197 to +198
await nextEventNamed(page, "turbo:submit-start")
assert.equal(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a race condition here, or is the assert.equal guaranteed to happen before the next event?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some delay to the submit response so the test picks up the changing test.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could check the values in the event handler, so that we don't have to think about the timing of it.

@afcapel
Copy link
Collaborator Author

afcapel commented Feb 10, 2023

Is this inspired by its rails/ujs predecessor? That attribute's name was [data-disable-with]. Is there a reason that this attribute name diverges from the others ([data-method] to [data-turbo-method], [data-confirm] to [data-turbo-confirm], etc.)?

@seanpdoyle it's inspired [data-disable-with], but both are slightly different. [data-disable-with] not only works with submitter buttons, but also with full forms and remote links. Its main point is to disable the annotated element during an XHR request.

But in Turbo we're already disabling the submitter on every form submission, regardless of any data attributes. I feel that if the attribute name was data-turbo-disable-with, it would give the impression that it's a drop-in replacement for [data-disable-with], even when they're functionally different, and that you need the attribute to disable a button on form submission, which is not the case.

@marcoroth
Copy link
Member

I kinda agree that a data-*-with attribute would be more "familiar" given how they were previously used. What if we used something like data-turbo-submits-with?

@dhh
Copy link
Member

dhh commented Feb 15, 2023

Great to see this come to Turbo. Agree with @marcoroth on familiar naming using data-turbo-submits-with to both differentiate from the fact that there's no extra disabling, but connects with what we had, and reads a little nicer.

@kevinmcconnell kevinmcconnell merged commit 455ffe0 into main Feb 23, 2023
@kevinmcconnell kevinmcconnell deleted the submitting-text branch February 23, 2023 12:01
another-rex referenced this pull request in google/osv.dev Mar 6, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [@hotwired/turbo](https://turbo.hotwired.dev)
([source](https://github.com/hotwired/turbo)) | [`7.2.5` ->
`7.3.0`](https://renovatebot.com/diffs/npm/@hotwired%2fturbo/7.2.5/7.3.0)
|
[![age](https://badges.renovateapi.com/packages/npm/@hotwired%2fturbo/7.3.0/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/npm/@hotwired%2fturbo/7.3.0/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/npm/@hotwired%2fturbo/7.3.0/compatibility-slim/7.2.5)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/npm/@hotwired%2fturbo/7.3.0/confidence-slim/7.2.5)](https://docs.renovatebot.com/merge-confidence/)
|
| [sass](https://github.com/sass/dart-sass) | [`1.58.0` ->
`1.58.3`](https://renovatebot.com/diffs/npm/sass/1.58.0/1.58.3) |
[![age](https://badges.renovateapi.com/packages/npm/sass/1.58.3/age-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://badges.renovateapi.com/packages/npm/sass/1.58.3/adoption-slim)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://badges.renovateapi.com/packages/npm/sass/1.58.3/compatibility-slim/1.58.0)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://badges.renovateapi.com/packages/npm/sass/1.58.3/confidence-slim/1.58.0)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>hotwired/turbo</summary>

### [`v7.3.0`](https://github.com/hotwired/turbo/releases/tag/v7.3.0)

[Compare
Source](https://github.com/hotwired/turbo/compare/v7.2.5...v7.3.0)

#### What's Changed

- Don't break out of frames when frame missing by
[@&#8203;kevinmcconnell](https://github.com/kevinmcconnell) in
[https://github.com/hotwired/turbo/pull/863](https://github.com/hotwired/turbo/pull/863)
- Respect `turbo-visit-control` for frame requests by
[@&#8203;kevinmcconnell](https://github.com/kevinmcconnell) in
[https://github.com/hotwired/turbo/pull/867](https://github.com/hotwired/turbo/pull/867)
- Allow changing the submitter text during form submission by
[@&#8203;afcapel](https://github.com/afcapel) in
[https://github.com/hotwired/turbo/pull/869](https://github.com/hotwired/turbo/pull/869)
- Form submissions from frames should clear cache by
[@&#8203;kevinmcconnell](https://github.com/kevinmcconnell) in
[https://github.com/hotwired/turbo/pull/882](https://github.com/hotwired/turbo/pull/882)
- Deprecate `[data-turbo-cache=false]` in favor of
`[data-turbo-temporary]` by
[@&#8203;packagethief](https://github.com/packagethief) in
[https://github.com/hotwired/turbo/pull/871](https://github.com/hotwired/turbo/pull/871)
- `resume()` does not require `value` by
[@&#8203;dahlbyk](https://github.com/dahlbyk) in
[https://github.com/hotwired/turbo/pull/854](https://github.com/hotwired/turbo/pull/854)
- Rename `isIdempotent` to `isSafe` by
[@&#8203;kevinmcconnell](https://github.com/kevinmcconnell) in
[https://github.com/hotwired/turbo/pull/883](https://github.com/hotwired/turbo/pull/883)

**Full Changelog**:
hotwired/turbo@v7.2.5...v7.3.0

</details>

<details>
<summary>sass/dart-sass</summary>

###
[`v1.58.3`](https://github.com/sass/dart-sass/blob/HEAD/CHANGELOG.md#&#8203;1583)

[Compare
Source](https://github.com/sass/dart-sass/compare/1.58.2...1.58.3)

-   No user-visible changes.

###
[`v1.58.2`](https://github.com/sass/dart-sass/blob/HEAD/CHANGELOG.md#&#8203;1582)

[Compare
Source](https://github.com/sass/dart-sass/compare/1.58.1...1.58.2)

##### Command Line Interface

-   Add a timestamp to messages printed in `--watch` mode.

- Print better `calc()`-based suggestions for `/`-as-division expression
that
    contain calculation-incompatible constructs like unary minus.

###
[`v1.58.1`](https://github.com/sass/dart-sass/blob/HEAD/CHANGELOG.md#&#8203;1581)

[Compare
Source](https://github.com/sass/dart-sass/compare/1.58.0...1.58.1)

- Emit a unitless hue when serializing `hsl()` colors. The `deg` unit is
    incompatible with IE, and while that officially falls outside our
compatibility policy, it's better to lean towards greater compatibility.

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "before 6am on wednesday" in timezone
Australia/Sydney, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://app.renovatebot.com/dashboard#github/google/osv.dev).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4xMjUuMSIsInVwZGF0ZWRJblZlciI6IjM0LjE0Ni4yIn0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants