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

hx-params is ignored if included inside a form element #3199

Open
Araoo opened this issue Feb 19, 2025 · 8 comments
Open

hx-params is ignored if included inside a form element #3199

Araoo opened this issue Feb 19, 2025 · 8 comments

Comments

@Araoo
Copy link

Araoo commented Feb 19, 2025

By the default, if the HTMX request is sent from a form element, all fields are sent and hx-params is ignored.

Maybe the documentation should be updated to mention this behaviour or change the behaviour to allow filtering parameters even if the request is sent from a form element.

<form hx-post="/" hx-params="field1">
<input type=text name="field1">
<input type=text name="field2">
<input type=text name="field3">
</form>

In the previous example, all the fields will be sent ignoring hx-params. I would have thought that only 'field1' would be sent.

@geoffrey-eisenbarth
Copy link
Contributor

Based on the testing suite (hx-params: named includes works), this shouldn't be happening. Can you post your actual code, perhaps we can find the issue somewhere else?

@Daddelhai
Copy link

Daddelhai commented Feb 20, 2025

I have the same issue. It doesn't even have to be an field in the form. Forms in general seems to ignore the hx-params attribute.

Call "localhost/?some_fancy_param=1"

<form hx-get="/" hx-params="*" hx-trigger="submit, change delay:1s" hx-replace-url="true">
<input type=text name="field1">
<input type=text name="field2">
<input type=text name="field3">
</form>

Submit the form and you will get "localhost/?field1=&field2=&field3=", but some_fancy_param is gone for ever. It's working fine on e.g. selects

EDIT: After some further testing I also had problems on "a"-tags

@Daddelhai
Copy link

Daddelhai commented Feb 20, 2025

A possible workaround (works only for GET requests and does not take data from any fields):
(Not sure if it actually covers all cases... it was written just within some minutes)

document.addEventListener('htmx:configRequest', function (event) {
    if (event.detail.elt.hasAttribute('hx-params')) {
        console.debug("Please check https://github.com/bigskysoftware/htmx/issues/3199 if it's fixed, and remove this workaround.");

        const hx_parmas_raw = event.detail.elt.getAttribute('hx-params');
        let hx_only = []
        let hx_except = []

        if (hx_parmas_raw === "*") {}
        else if (hx_parmas_raw === "none") {
            return;
        }
        else if (hx_parmas_raw.startsWith("not ")) {
            hx_except = hx_parmas_raw.slice(4).split(',').map(x => x.trim());
        }
        else {
            hx_only = hx_parmas_raw.split(',').map(x => x.trim());
        }

        const hx_include_raw = event.detail.elt.getAttribute('hx-include');
        if (hx_include_raw) {
            const fields = document.querySelectorAll(hx_include_raw);
            fields.forEach((field) => {
                if (field.name) hx_except.push(field.name);
            });
        }

        if (event.detail.elt.tagName === 'FORM') {
            const form_fields = event.detail.elt.querySelectorAll('input, select, textarea');
            form_fields.forEach((field) => {
                if (field.name) hx_except.push(field.name);
            });
        }

        const htmx_url = new URL(event.detail.path, window.location.origin);
        const htmx_params = new URLSearchParams(htmx_url.search);

        const window_url = new URL(window.location.href);
        const window_params = new URLSearchParams(window_url.search);

        // for each param in the window url that is not in the htmx url, add it
        window_params.forEach((value, key) => {
            if (!htmx_params.has(key)) {
                if (hx_only.length > 0 && !hx_only.includes(key)) {
                    return;
                }
                if (hx_except.length > 0 && hx_except.includes(key)) {
                    return;
                }

                event.detail.parameters[key] = value;
            }
        });

    }
});

Maybe you can reuse some of the code to fix the issue...

@Araoo
Copy link
Author

Araoo commented Feb 20, 2025

Based on the testing suite (hx-params: named includes works), this shouldn't be happening. Can you post your actual code, perhaps we can find the issue somewhere else?

<form id="product_form" action="{% url 'core:index' %}" method="post"
            hx-post="{% url 'core:index' %}"
            hx-trigger="get-price from:body, load"
            hx-params="coverage_area, travelers, travel_period, oldest_insured_age, ascendant, car"
            hx-target="#total_quote_div"
            hx-swap="outerHTML"
>
(Fields included here)
</form>

hx-params is ignored.

My workaround was to enclose all fields inside a div and make the hx-post from the div. That way hx-params worked like intented.

@MichaelWest22
Copy link
Contributor

Tested your pasted form code and it works as expected in this example codepen:

https://codepen.io/MichaelWest22/pen/yyLewZx

Image

Your form only includes the specified input field names but excludes the last one I added with a different name.

I tested with multiple old versions of htmx as well and they all seemed to work for me as expected

@MichaelWest22
Copy link
Contributor

I have the same issue. It doesn't even have to be an field in the form. Forms in general seems to ignore the hx-params attribute.

Call "localhost/?some_fancy_param=1"

<form hx-get="/" hx-params="*" hx-trigger="submit, change delay:1s" hx-replace-url="true">
<input type=text name="field1">
<input type=text name="field2">
<input type=text name="field3">
</form>

Submit the form and you will get "localhost/?field1=&field2=&field3=", but some_fancy_param is gone for ever. It's working fine on e.g. selects

EDIT: After some further testing I also had problems on "a"-tags

I think this is expected behavior. The current query parameters of a site are never designed to be submitted with every future form request inside the page as this would be a major security issue if this was possible. Someone sending you to a link to the page could inject malicious parameter data into your next form submission to get you to do all sorts of dangerous things! Use this link to pay me $1 please: https://yourbank.com/make-payment?payment-amount=1000 :)

There are much better more secure patterns I think to handle this situation if you did happen to need a url query parameter to be reused by some of the forms on the page. For example when loading a page with such a parameter that you know is safe and needed for the next form submission you could create a hidden input in the form with the previous url value on page load. or in htmx if you were doing a partial page update and pushing a url with a parameter you could retain an input on the page with the value so it will be submitted next time. Also you can use the configRequest event like you have in your example above but you should only need 3 lines as you can leave htmx to generate the parameters list as normal which it does before it calls configRequest and then your event listener code can just optionally add one extra parameter into event.details.parameters if it is missing or required from the expected and knows to be safe current url query parameter.

@Daddelhai
Copy link

Daddelhai commented Feb 20, 2025

I have the same issue. It doesn't even have to be an field in the form. Forms in general seems to ignore the hx-params attribute.
Call "localhost/?some_fancy_param=1"

<form hx-get="/" hx-params="*" hx-trigger="submit, change delay:1s" hx-replace-url="true">
<input type=text name="field1">
<input type=text name="field2">
<input type=text name="field3">
</form>

Submit the form and you will get "localhost/?field1=&field2=&field3=", but some_fancy_param is gone for ever. It's working fine on e.g. selects
EDIT: After some further testing I also had problems on "a"-tags

I think this is expected behavior. The current query parameters of a site are never designed to be submitted with every future form request inside the page as this would be a major security issue if this was possible. Someone sending you to a link to the page could inject malicious parameter data into your next form submission to get you to do all sorts of dangerous things! Use this link to pay me $1 please: https://yourbank.com/make-payment?payment-amount=1000 :)

There are much better more secure patterns I think to handle this situation if you did happen to need a url query parameter to be reused by some of the forms on the page. For example when loading a page with such a parameter that you know is safe and needed for the next form submission you could create a hidden input in the form with the previous url value on page load. or in htmx if you were doing a partial page update and pushing a url with a parameter you could retain an input on the page with the value so it will be submitted next time. Also you can use the configRequest event like you have in your example above but you should only need 3 lines as you can leave htmx to generate the parameters list as normal which it does before it calls configRequest and then your event listener code can just optionally add one extra parameter into event.details.parameters if it is missing or required from the expected and knows to be safe current url query parameter.

Valid point, still I think this should be secured another way... In my case I just use it for some sorting and filtering. A option to disable this protection would be great. The goal should not be that dev are searching them selfs workarounds.
I think it should at least be clearly pointed out in the documentation, as this information is completly missing there (Including warnings for possible vulnerabilities). At the moment the behaviour feels very random... (as it is working on some elements)

@geoffrey-eisenbarth
Copy link
Contributor

I have the same issue. It doesn't even have to be an field in the form. Forms in general seems to ignore the hx-params attribute.

Call "localhost/?some_fancy_param=1"

<form hx-get="/" hx-params="*" hx-trigger="submit, change delay:1s" hx-replace-url="true">
<input type=text name="field1">
<input type=text name="field2">
<input type=text name="field3">
</form>

Submit the form and you will get "localhost/?field1=&field2=&field3=", but some_fancy_param is gone for ever. It's working fine on e.g. selects

EDIT: After some further testing I also had problems on "a"-tags

I agree with @MichaelWest22, but I think you can get your desired behavior by setting hx-get="" (slightly more context here).

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

4 participants