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

Form doesn't reactivate again when receiving itself in Chrome #2525

Open
volysandro opened this issue May 3, 2024 · 3 comments
Open

Form doesn't reactivate again when receiving itself in Chrome #2525

volysandro opened this issue May 3, 2024 · 3 comments

Comments

@volysandro
Copy link

Sorry if this is a duplicate, I rarely post issues, only when I really can't even pinpoint the issue.

TLDR;
tbody contains rows of data, and the last row is a form to add new rows. The form receives a fresh tbody and thus replaces itself as well.
Issue: In firefox, I can re-use the form again as soon as I receive it, but in Chrome I have to do a full page reload, as the form just doesn't become active. No errors or warnings.

I know there's a million better ways of doing this, but it's a quick mockup, and I still want to figure this one out:D

(defn all-targets-tbody
  []
  (html
  (let [target-group (db/get-all-targets)]
    [:tbody#targets
   (for [target target-group]
     (let [tags (str/split (:TARGET/TAGS target) #"\,")]
       [:tr
        [:td (:TARGET/FIRST target)]
        [:td (:TARGET/LAST target)]
        [:td (:TARGET/EMAIL target)]
        [:td
         [:div.tags (for [tag tags]
                      [:div.tag (make-tag-pretty tag)])]]
        [:td (delete-button (:TARGET/ID target))]]))
   (add-target-form)])))
(defn add-target-form
  []
  [:form {:hx-post "/api/targets/add"
          :hx-target "#targets" 
          :hx-swap "outerHTML"}
     [:tr    
       [:td [:div
         [:label "First Name"]
         [:input {:type "text" :name "first" :value "Joe"}]]]
        [:td [:div
         [:label "Last Name"]
         [:input {:type "text" :name "last" :value "Blow"}]]]
        [:td [:div
         [:label "Email Address"]
         [:input {:type "email" :name "email" :value "joe@blow.com"}]]]
        [:td [:div 
         [:label "Tags (commas)"]
         [:input {:type "text" :name "tags" :value (random-tags)}]]]
        [:td [:button.btn.waves-effect.waves-light.black "Submit"]]]])

This is the updated table I get via htmx, the form in the last row reactivates again in Firefox, but not in Chrome.

<tbody id="targets">
    <tr>
        <td>John</td>
        <td>Doe</td>
        <td>john@doe.com</td>
        <td>
            <div class="tags">
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/me"
                        hx-swap="outerHTML" hx-target="#targets">me</button></div>
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/all"
                        hx-swap="outerHTML" hx-target="#targets">all</button></div>
            </div>
        </td>
        <td><button class="btn waves-effect waves-light black" hx-post="/api/targets/delete/1" hx-swap="outerHTML"
                hx-target="#targets" hx-trigger="click">Delete</button></td>
    </tr>
    <tr>
        <td>Max</td>
        <td>Musty</td>
        <td>max@musty.com</td>
        <td>
            <div class="tags">
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/all"
                        hx-swap="outerHTML" hx-target="#targets">all</button></div>
            </div>
        </td>
        <td><button class="btn waves-effect waves-light black" hx-post="/api/targets/delete/2" hx-swap="outerHTML"
                hx-target="#targets" hx-trigger="click">Delete</button></td>
    </tr>
    <tr>
        <td>Joe</td>
        <td>Blow</td>
        <td>joe@blow.com</td>
        <td>
            <div class="tags">
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/me"
                        hx-swap="outerHTML" hx-target="#targets">me</button></div>
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/ all"
                        hx-swap="outerHTML" hx-target="#targets"> all</button></div>
            </div>
        </td>
        <td><button class="btn waves-effect waves-light black" hx-post="/api/targets/delete/39" hx-swap="outerHTML"
                hx-target="#targets" hx-trigger="click">Delete</button></td>
    </tr>
    <tr>
        <td>Joe</td>
        <td>Blow</td>
        <td>joe@blow.com</td>
        <td>
            <div class="tags">
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/testing"
                        hx-swap="outerHTML" hx-target="#targets">testing</button></div>
            </div>
        </td>
        <td><button class="btn waves-effect waves-light black" hx-post="/api/targets/delete/42" hx-swap="outerHTML"
                hx-target="#targets" hx-trigger="click">Delete</button></td>
    </tr>
    <tr>
        <td>Joe</td>
        <td>Blow</td>
        <td>joe@blow.com</td>
        <td>
            <div class="tags">
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/testing"
                        hx-swap="outerHTML" hx-target="#targets">testing</button></div>
                <div class="tag"><button class="btn waves-effect waves-light black" hx-get="/api/targets/tags/ me"
                        hx-swap="outerHTML" hx-target="#targets"> me</button></div>
            </div>
        </td>
        <td><button class="btn waves-effect waves-light black" hx-post="/api/targets/delete/47" hx-swap="outerHTML"
                hx-target="#targets" hx-trigger="click">Delete</button></td>
    </tr>
    <form hx-post="/api/targets/add" hx-swap="outerHTML" hx-target="#targets">
        <tr>
            <td>
                <div><label>First Name</label><input name="first" type="text" value="Joe" /></div>
            </td>
            <td>
                <div><label>Last Name</label><input name="last" type="text" value="Blow" /></div>
            </td>
            <td>
                <div><label>Email Address</label><input name="email" type="email" value="joe@blow.com" /></div>
            </td>
            <td>
                <div><label>Tags (commas)</label><input name="tags" type="text" value="all" /></div>
            </td>
            <td><button class="btn waves-effect waves-light black">Submit</button></td>
        </tr>
    </form>
</tbody>
@Telroshan
Copy link
Collaborator

I understand that you want to figure out the situation here, but there's a first problem even before getting to htmx ; you have an invalid here HTML, as a tbody may only contain tr children, thus not a form.

When you look at the DOM in Chrome's inspector with the HTML you provided, here's how it actually gets parsed:
image
So all your tr/td containing inputs were moved out of the form itself, thus the form feeling "disabled", but the core issue isn't htmx-related here, it's simply invalid HTML.

In your case, you might want to use the form attribute + get your form either inside one of the td for ex, or outside the table, where it'd be legit to reside

@volysandro
Copy link
Author

volysandro commented May 3, 2024

I noticed this! Weirdly, the form is parsed wrong on both page load and htmx-refresh, the form works on a fresh page load.

And I know it's sacrilegious / not conform..
But I figured chances are high someone splattered paint and encountered the same behaviour, so I was still curious about the root cause:P

@Telroshan
Copy link
Collaborator

so I was still curious about the root cause

As said above the very root cause is that it's not valid HTML, thus it's up to your browser to decide how to parse this HTML.
The result here in Chrome is that your form gets disconnected and rendered apart from your <tr> and <td> elements.
Your inputs being no longer inside the form, you have an "input-less" form and "form-less" inputs that have no relationship between each other.
Thus, in your setup, the hx-post is bound to a form that won't ever be triggered anyway as no input/submit button are attached to it.
You can bind these inputs/buttons again to the form using the standard form attribute though.

And I have no idea why the form would work on a fresh page load in the first place given the situation 😆 but don't get me wrong, the anomaly here is the form working sometimes, not the form not working!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants