How to implement the onselect event on htmx? - django

I'm a django developer and I'm new to htmx.
I was wondering if there was an easy way to implement the onselect event in htmx.
I have the following dropdown:
When the role is selected "onselect", I want to send an http request to the back-end using htmx(not jquery or javascript)
How can I do this?
Any help is much appreciated!
Thanks!
Tried searching "onselect" on htmx docs but there's no built in implementation.
Tried searching "onselect htmx" stack overflow but I couldn't find a helpful post.

You should use hx-trigger="changed".
https://htmx.org/docs/#triggers
If you don't specify trigger attr then the request will trigger on selection change anyways. Please check out the following example:
https://htmx.org/examples/value-select/

I found the answer upon re-reading the docs.
I found the solution with [hx-trigger] on the change event hx-trigger
<select
class="custom-select"
id="role"
name="role"
hx-post="{% url 'set_user_role' user.id %}"
hx-trigger="change">
<option value=""></option>
{% for role in roles %}
<option value="{{role.id}}"
{% if role == current_role %}selected{% endif %}
>{{role.name}}</option>
{% endfor %}
</select>

Related

Flask keeping checkboxes after page regresh

I have this piece of code of a flask template
<div class="rows">
<h3>In oven</h3>
{% for checkbox in checkboxes: %}
<li><input type="checkbox"></li>
{% endfor %}
</div>
I tried using java script but after refresh the checkboxes resets even if I checked it before. I want to checked it and after refreshing the page the check to stay. Any ideas how to do it?
You need to store somewhere the value of the checkbox to set it when loading the page again.
Local storage
Flask session
Database
Ajax query
With a form
This value has to be something that can be evaluated as true/false.
After retrieving the value you need to evaluate for add or not the checked property in the input.
In this example, I'm using a variable on the view.
#app.py
#app.route("/")
def sample():
your_variable=True
return render_template('index.html', your_variable=your_variable)
#index.html
<div class="rows">
<h3>In oven</h3>
{% for checkbox in checkboxes: %}
<li><input type="checkbox" {{'checked="checked"' if your_variable else ""}}></li>
{% endfor %}
</div>
Of course, with a more complete question this can be more specific

How to pass a <select> in a View using Django

I was trying to make a cart system in Django and wanted to pass Size and the Quantity of product as <Select>
input in View.
My Template have :
<ul class="list-unstyled">
Select Size:
<select name="sizes">
{% for size in product.sizes.all %}
<li class="list-item list-inline-item"><option value="{{size.nameSize}}">{{size.nameSize}}</option> </li>
{% endfor %}
</select>
</ul>
This is how it looks :
But when i Submit it using the Add to Cart Button i get error:
This is the code in the view:
def add_item(request,pk):
product = get_object_or_404(Product,pk=pk)
size = request.POST['sizes']
selectsize = Size.objects.get(nameSize=size)
user = request.user
usercart = Cart.objects.get(owner=user)
newitem = CartItems.objects.create(cart = usercart,product=product,size=selectsize)
items = usercart.cartitems
return render(request,'cart.html',{'cartitems':items})
I am trying to use the name of the size from the Template and compare the size name i have in the database for that product Using:
selectsize = Size.objects.get(nameSize=size)
I was able to get size with name 36 so i wanted to pass the value 36 from the template to the variable size using post.
But i get the error mentioned which i believe is because name for the <select> is common in all the <option>.
If i can either get an alternate way to do that or solve this error both type of solutions are welcomed.
*I am not using Django Forms because i don't know how to have django form display like i am displaying my products in cart and on the product page.
ANSWER
I was missing a submit button and was rather using a <a href="{% url 'add_item' product.pk %}>Add To Cart</a>" to submit the form which was not working.
Now i replaced it with <button class="btn btn-success" style="margin-top: 10px;" type="submit">Add To Cart New</button>
And the form Action is given the link i was trying to go to.
<form method="post" enctype="multipart/form-data" action="{% url 'add_item' product.pk %}">
A silly mistake on my side.
Thanks for the answers.
Expanding on what #Yevhenii M. said, and talking particularly about the MultiValueDictKeyError:
This error happens when the given key (sizes in this case) is not found in the POST dict. This might be happening (i'm only guessing, since you didn't post the full html code), because you didn't put the corresponding <form> tag surrounding the select.
So, the final code would look something like:
<form action="url-to-send-form-data" method="POST">
{% csrf_token %}
<select name="sizes">
{% for size in product.sizes.all %}
<option value="{{size.nameSize}}">{{size.nameSize}}</option>
{% endfor %}
</select>
</form>
The {% csrf_token %} is needed in order to protect you against Cross Site Request Forgery attacks (more info: https://docs.djangoproject.com/en/2.2/ref/csrf/)
EDIT: Now that I take a closer look, the error message shows that the url is being called with a GET request (maybe because of trying to access to /item_added/1 straight from the browser's url). That is why django can't find the sizes key.
One common way to call the url via post, is as shown in the code snipet above, and adding a submit button to the html:
...
<button type="submit">Submit</button>
</form>
You don't need to use <ul> tag here.
You can write:
Select Size:
<select name="sizes">
{% for size in product.sizes.all %}
<option value="{{size.nameSize}}">{{size.nameSize}}</option>
{% endfor %}
</select>
and result will be the same.
Since you didn't specify that add_item(request, pk) works only by POST, then you can't expect that request.POST always will be presented.
Better write your code as this:
if request.POST:
# do something
And if you don't specify default value for your select in template, then sizeswill not be in your request.POST.
You can write like this just to be sure that you got some value:
request.POST.get('sizes', 'some_default_value')
Just because you get MultiValueDictKeyError you need to see what you get in request. Maybe you get QueryDict, then you need to extract first value. For example, see this SO question. For example, print your request.POST or check type.

Use javascript variable with django template

I have a brain model with different resolutions and I want to let the user to change the resolution of the the model by just choosing his desired resolution from a select tag.
I mean I have the complete models loaded and without sending a POST to the server I want to change the view of the brain model.
The problem is that I can't pass the read value from the select to my django tag to choose the suitable moedl to render.
This is my code:
<body>
<select id="resolution_options" onchange="change_brain_resolution()" name="resolution_options">
{% for brain in brains %}
<option value="{{ brain.resolution }}">
{{ brain.resolution_title }}
</option>
{% endfor %}
</select>
<script>
function change_brain_resolution() {
var selcted_resolution = getElementById('resolution_options').value;
{% for brain in brains %}
// Here is my problem !!
{% if brain.resolution == selcted_resolution %}
// Do drawing
{% endfor %}
}
</script>
</body>
The reson of why I don't want to do a POST is because there are many other things the user have been drawing and doing and he may want to change the resolution of the brain model in order to have a better view or performance but he wants to keep the other objects in the scene
Thank you very much.
Try this:
function change_brain_resolution() {
var selcted_resolution = getElementById('resolution_options').value;
{% for brain in brains %}
if (selcted_resolution == {{ brain.resolution }}) {
// Do drawing
}
{% endfor %}
}
This ends up putting logic for every brain resolution on your client side. If you want to be more efficient, you have to pass the selected resolution to server with AJAX, and render the response.
Remember that templates are rendered before the page, hence they don't have access to value of javascript variables. If you want to pass javascript variables to server, you should do so after page load with an AJAX request.

How to disable intermediate signout page in Django allauth

How to disable the intermediate signout page from django allauth. When the user clicks on the signout link on my site I want him to logout right away, I want to remove this intermediate page
Set ACCOUNT_LOGOUT_ON_GET to True in your settings.
Also see the documentation
Using a GET request is probably a bad idea due to browsers prefetching urls from the URL bar. Chrome (as of right now) is pretty bad for this; it'll send a GET request to pages it think you'll hit enter on when typing in your URL bar.
Plus, people can add a link such as <img src="https://example.com/account/logout/"> and you'll be logged out. That's not a security risk since it's logging you out, but it is certainly annoying for your users.
Instead, you should consider using a POST request using a form with CSRF. Django Allauth already comes with this. Here's the <form> from the intermediate signout page:
<form method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<button class="STYLE_ME" type="submit">Logout</button>
</form>
In my case, I just added this to the site header and made the submit <button> look like every other link using CSS so it feels the same to them, but the form will use a POST request.
But if that's not a solution you can implement for any reason, open your settings.py file (or your main settings file) and set:
ACCOUNT_LOGOUT_ON_GET = True
^ The above setting will do what you need. For further Django Allauth settings, check out their configuration page.
Here's another shortcut for preserving the POST request, if you don't want to mess with styling the form button with something like this:
Hide the form:
<form style='display: none;' method="post" action="{% url 'account_logout' %}">
{% csrf_token %}
<input type="hidden" name="next" value="/redirect_target/"/>
<button id="signOutBtn" type="submit">Logout</button>
</form>
Submit with a click event attached to whatever element you've already styled:
$(document).on('click', '#signOutLink', function() {
$('#signOutBtn').click()
});

Django. Cancel button for form in admin site

Is there any functionality in admin site that allow to implement for every add/change form cancel button, that redirects me to list of that form objects. I mean some general solution for any form.
Add admin/submit_line.html in your project's templates directory. Use the code from the default submit_line.html, and add your cancel button. You can link it to just "../" to make it always just go up one level. Then do any necessary CSS styling to make it look right.
Create a file: yourapp/templates/admin/submit_line.html
I use Bootstrap, but you can change this easily
{% extends "admin/submit_line.html" %}
{% block submit-row %}
{{ block.super }}
Cancel
{% endblock %}
Be sure that your application is above "admin" in INSTALLED_APPS.
Looks like this in German locale:
<input type="button" name="Cancel" value="Cancel">
You can this line anywhere inside admin/submit_line.html