Call a modal (Bootstrap 5) from Jinja2 templating - flask

I'm likely the nth person to have asked this question but am having trouble parsing the relevant documentation; I want to add a modal dialogue to a button declared with a function in Jinja2.
The code for the form where I want the modal to be called is below - the modal should be called when the shutdown button (last line) is pressed, to confirm this action.
<form class="form form-horizontal" method="post" role="form"
style="text-align: center;">
{{ power_form.hidden_tag() }}
{% if power_status == "None" %}
{{ power_form.power_on(class_="btn btn-default") }}
{{ power_form.power_cycle(class_="btn btn-default") }}
{{ power_form.power_off(class_="btn btn-default") }}
The modal dialogue is called 'Shutdown Confirmation' and has been declared later. I am unsure how to call it as online examples show the button declaration is used instead of the {{. Here is the bootstrap documentation for this:
<button type="button" class="btn btn-primary" data-bs-
toggle="modal" data-bs-target="#exampleModal">
Launch demo modal
</button>

With Bootstrap 5 you can activate the modal panel by data attributes or JS API. I assume you want to use the data-attribute method.
With WTForms you can pass any attribute to the rendered element, just replace any dash with underscore (because Python syntax), and WTForms will change them back to dashes:
{{ power_form.power_off(type="button", class_="btn btn-default", data_bs_toggle="modal" data_bs_target="#exampleModal") }}
Change the #exampleModal to the corresponding selector of your modal element. We also change the type of the button from the default submit to simple button, so it wont submit the form, just open the modal window.

Related

HTMX not triggering correct query on pickadate.js selection

I use django-forms-dynamic package and htmx to dynamically load available options on a MultipleChoiceField. The options are based on a date field, for which I use pickadate.js by Amsul.
The initial query gets the correct choices from the database. However, if the date is changed, the query is lagging one step behind. So, let's asume 1.11.2022 is initially selected. If changed to 4.11.2022, the query is made for the 1.11.2022. If 28.11.2022 is selected, 1.11.2022 is queried, etc.
reservation_form.html
<div class="col-lg-6">
<div class="form-floating">
{% render_field reservation_form.date class="datepicker form-control mb-3"
hx-get="/reservation/filter-seats"
hx-include="#id_dinner"
hx-trigger="click change"
hx-target="#id_seat_reservation"
%}
<label for="id_date">Dinner Date</label>
</div>
<div class="form-floating">
{% render_field reservation_form.amount_guests class+="form-control" placeholder="" %}
<label for="id_amount_guests">Guests</label>
</div>
<div class="visually-hidden">
{% render_field reservation_form.dinner %}
</div>
<div class="form-check">
{% render_field reservation_form.seat_reservation class+="form-select" %}
<label for="id_seat_reservation">Select Seats</label>
</div>
</div>
pickadate script
<script>
var $input = $('.datepicker').pickadate({
format: 'yyyy-mm-dd',
formatSubmit: 'yyyy-mm-dd',
min: 0,
max: 90,
disable: {{ blocked_dates }},
firstDay: 1,
})
var picker = $input.pickadate('picker')
</script>
What am I missing?
You have set the triggers as hx-trigger="click change". First, this is incorrect, you have to separate events with a comma, right now HTMX tries to evaluate change as a trigger modifier without success. Therefore you only have the click trigger event, HTMX submits the form when you click on the input element. At the same time pickadate.js also listens to the click event and opens the datepicker widget. After selecting a date the form dispatches the change event, but you have disabled that for HTMX so it will not submit the form again. Next time you click on the input element HTMX submits the form with the previously selected value.
To fix the issue just remove the hx-trigger attribute. For input fields the default trigger is already the change event, therefore HTMX will submit the form when pickadate.js enters the selected date into the input field.

Can we load Livewire Component on clicking some button?

I have a Livewire component with a button, and I want to append a form (i.e another livewire component) by clicking that button. Like we do that by using ajax, requesting to the backend to load HTML and append with jQuery. So question is, can we do the same with Livewire?
<div>
<button wire:click="loadFormComponent">Add a Link</button>
<div>
here I want to append the result of `loadFormComponent`
</div>
</div>
bellow is Form Component
<div>
<form wire:submit.prevent="addLink">
<div>
<input type="URL" wire:model="URL" placeholder="https://example.com">
<button type="submit">Save Link</button>
</div>
</form>
</div>
Yes, you can display parts of your blade -including other Livewire components- under conditions. You don't need AJAX for this. You make the section of your Blade file conditional:
<div>
<button wire:click="$set('showFormComponent', true)">Add a Link</button>
#if ($showFormComponent)
<div>
here I want to append the result of `loadFormComponent`
</div>
#endif
</div>
and in your livewire component you need to add:
public $showFormComponent;
On click, the variable $showFormComponent will be set to true and view will be re-rendered including the component.

creating an if statement to look for specific button press

first time poster! I'm still fairly new to coding and Django...
I'm looking to create a django if statement to see if a certain button is pressed. I have a toast set up to show an error warning if a search returns no results, but it also pops up if the user clears the search.
Here's the button(s)
<div class="input-group-append">
<button class="form-control rounded-circle btn form-button ml-2" type="submit">
<span>
<i class="fas fa-search"></i>
</span>
</button>
<button class="form-control rounded-circle btn form-button ml-2 closebutton" type="clear" name="clear">
<span>
<i class="fas fa-times"></i>
</span>
</button>
</div>
I'd like it to spot if the button with the name/type "clear" is clicked, then it won't run the toast. Toast is below:
{% if button == 'clear' %}
<div class="toast custom-toast rounded-0 border-top-0" data-autohide="false">
<div class="arrow-up arrow-danger"></div>
<div class="w-100 toast-capper bg-danger"></div>
<div class="toast-header bg-white text-dark">
<strong class="mr-auto">Error!</strong>
<button type="button" class="ml-2 mb-1 close text-dark" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="toast-body bg-white">
{{ message }}
</div>
</div>
{% endif %}
I'd like it to spot if the button with the name/type "clear" is clicked, then it won't run the toast.
This if statement is only run on the server when it renders the HTML for the web page. It is checking if a variable named button has the string value "clear". This has nothing to do with any HTML elements in the page, let alone the name of a particular <button>. Instead, the value of the variable button comes from the "context" when your Python calls one of the render functions.
I'm looking to create a django if statement to see if a certain button is pressed.
There are two different ways to handle button clicks:
Submit a form to the server which then returns a response with a new page. This can be the same Django template rendered with different values in the context in order to get the behavior that you want.
Add an onclick handler to the button. This should be a JavaScript function that peforms the action you want. It can manipulate the elements in the page to add a toast or anything else.
The first option is very slow because it will require a new network request. The second option is probably preferred here since it will be very responsive to the user's actions.

How to call a django url after clicking on a bootstrap tab and show results on the tab content?

I have created two bootstrap tabs whose data is comming from django functions. I can easily post essential data of all tabs while the tabs are loaded but I want to load data of each tab once the tab is clicked instead of loading all data together.
Bootstrap uses href or data-target to load a tab content. So, when I set django url in href attribute and activate the tab by JavaScript, the django function is invoked but bootstrap does not open the tab. It always opens the first tab.
<ul id="myTab" class="nav nav-tabs bar_tabs" role="tablist">
<li role="presentation" class="active">Profile
</li>
<li role="presentation" class="">Monitor
</li>
</ul>
<div id="myTabContent" class="tab-content">
<div role="tabpanel" class="tab-pane fade active in" id="tab_content1" aria-labelledby="home-tab">
</div>
<div role="tabpanel" class="tab-pane fade" id="tab_content3" name="tab_content3" aria-labelledby="profile-tab">
{% include "setting/monitor.html" %}
</div>
</div>
My JavaScript code is:
<script>
$(document).ready(function(){
switch("{{section}}"){
case 'monitor':
$('#myTabContent #tab_content3').tab('show');
break;
case 'profile':
$('#myTab a[href="#tab_content1"]').click();
break;
}
})
</script>
I have also used the below javascript to activate second tab, but it does not wok.
$("#myTab").tabs("select", 2);
I appreciate your help.
Bootstrap will show the tab which you marked as "active". So when returning the HTML for 2nd tab make that tab as active by adding class="active" attribute to it.
May be you need to pass that information from view in the context and add that class to appropriate tab in the template.

how to add css class to radio button in django template

I am trying to do the following with django widget tweaks:
{{ form.gender.0.tag|attr:"class:radio_1" }}
I get the error:
'SafeText' object has no attribute 'as_widget'
What am I doing wrong?
Initialize your RadioButton like this:
CHOICES=[('option1','option1'),
('option2','option2')]
radio = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect(attrs={'class': 'radio_1'}))
and the generated HTML-Code will look like this:
<input type="radio" class="radio_1" ... />
You may have figured out already how to apply CSS to radio buttons in Django template but in case someone is in the same situation, here's a code straight from the docs:
<fieldset>
<legend>{{ myform.beatles.label }}</legend>
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
</fieldset>
This code assumes you have a form myform with a field beatles that uses a RadioSelect as its widget.
As you can see, looping through the field beatles can allow you to add necessary classes (here class="myradio") for each radio button; hence, make your CSS styling possible and easier.
In your case, you might want to also loop through your gender field and then apply the appropriate classes.