my select2 jquery only work for the first form - javascript

i want to use select2.min.js to auto-complete the choices (ForeignKey values) , but it only work for my first form , i used django formset for duplicate forms
this is my snippet
<tbody class="tbody tb1 " id="form_set">
{% for item in items.forms %}
<tr class="p-0 col-12">
<td class="">
<div class="col-12 p-0 mt-3 inp">
<input class="col-12 0qarz qarz" type="number" name="" placeholder="qarz">
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.price | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.quantity | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.model | add_class:'col-12 0model model' | attr:'id:model'}}
</div>
</td>
</tr>
{% endfor %}
</tbody>
<script type="text/javascript">
$(function(){
$('.tb1 tr:last').formset({
prefix:'{{items.prefix}}',
addText:'add',
deleteText:'remove',
addCssClass:'btn btn-success',
});
})
</script>
<script type="text/javascript">
$(document).ready(function(){
$("#model").select2()
})
</script>
but the select2 only work for my first form then doesnt have any effect on other forms ! and how to set number of forms to add_class it will help to solve maybe?
thanks

First of all I would love to see a little bit more, for example how you actually define your formset. It is not also clear to me what are you trying to do here. Please paste more data.
I would suggest that you think about using django-select2 module that helps a lot with handling select2 stuff in django.
I am also not sure what you mean by "how to set number of forms", maybe you wish to include some incremental counter that can be done with {{ forloop }} inside for/endfor loop?
Please paste more stuff and answer will be better.

The selector you are using to initialize select2 #model is for element ids, which should be unique for each element in the DOM.
In most browsers the effect will be that only the first instance of an element id will be recognized, and the rest ignored as if they don't exist.
In this instance you want to use a class selector: .model. This will ensure select2 is initialized for all elements that have the class "model". So the code to initialize select2 would be:
<script type="text/javascript">
$(document).ready(function(){
$(".model").select2()
})
</script>

You have to reinitialize(like this way: $("#model").select2();) the select2 for other pages when they appear.

You should need separately initialize with different ids.
for example:
<script type="text/javascript">
$(document).ready(function(){
$("#id_1").select2();
$("#id_2").select2();
})
</script>

the way I found is sending the number of forms through context then apply for loop in the template.
views.py
get_context_data()
context.update({
"accessoryNum": len(StoreRequestAccessory.objects.filter(storeRequestId=self.object.pk)),
"oneDimensionalItemNum":len(StoreRequestOneDimensionalItem.objects.filter(storeRequestId=self.object.pk)),
"twoDimensionalItemNum":len(StoreRequestTwoDimensionalItem.objects.filter(storeRequestId=self.object.pk)),
})
template.html
{% block javascripts %}
<script>
{% comment %} get accessoryNum from context {% endcomment %}
var accessoryNum = {{accessoryNum}};
$(document).ready(function(){
for(let i = 0; i <=accessoryNum; i++){
$(`#id_storereq_accessory_form-${i}-accessoryId`).select2({
placeholder: "Select a Item",
allowClear: true
});
}
});
</script>
{% endblock javascripts %}

Related

How to dynamically submit form input values with OnChange event using JQuery in django

I'm currently developing a simple true odd finder calculator using python, django and jquery. I need to have form input submit actions executed by jQuery as the user types in the input values. The goal is to get rid of submit buttons in the frontend html. As of nowadays calculator based web applications don't require submit buttons. The functionality behavior should look like here. I did a research and found out that i need to use JQuery. After implementing the functionality in my app, am able to type the first form input element, however upon clicking the second form input so as to start typing, my application crashes with server error 500, if i go back then type the second form input, it updates output.
How can i implement form input onChange using jquery to match the referenced functionality above.
My template and JQuery code
{% extends "base.html" %}
{% block title %}Two Way True Odd Finder{% endblock %}
{% block content %}
<script type="text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('.form-control').change(function () {
$('#myform').submit();
});
});
</script>
<div class="container m-5">
Dashboard Home
3 Way True Odds Finder Calculator
</div>
<div class="container m-5 text-justify">
<div class="row">
<div class="col-4">
<form action="" method="post" id="myform">
{% csrf_token %}
<div class="mb-3">
<label for="Odd1" class="form-label">Odd 1</label>
<input type="number" class="form-control" name="odd1" id="Odd1" min=" " value=" " step=".001" required='required'>
</div>
<div class="mb-3">
<label for="Odd2" class="form-label">Odd 2</label>
<input type="number" class="form-control" name="odd2" id="Odd2" min=" " value=" " step=".001" required='required'>
</div>
<!--<button type="submit" class="btn btn-primary">Submit</button>-->
</form>
</div>
<div class="col-8">
<div class="row">
<div class="col-sm-6">
<div class="card shadow-sm p-3 mb-5 bg-white rounded">
<div class="card-body">
<h5 class="card-title">Results</h5>
<table class="table table-bordered">
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Odd1</th>
<th scope="col">Odd2</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Initial Odds With Juice</th>
<td>{{HomeOdd}}</td>
<td>{{AwayOdd}}</td>
</tr>
<tr>
<th scope="row">Implied Probability Win %</th>
<td>{{Home_implied_probability}}</td>
<td>{{Away_implied_probability}}</td>
</tr>
<tr>
<th scope="row">True Odds Without Juice</th>
<td class="text-success">{{Home_True_Odd}}</td>
<td class="text-success">{{Away_True_Odd}}</td>
</tr>
</tbody>
</table>
<div class="container text-justify">
<p>Total Implied probability is {{TotalImpliedProbability}}%</p>
<p>Inverted probability is {{Inverted_Probability}}%</p>
<p>Bookie juice is {{Juice}}%</p>
<p>True probability is {{True_Probability}}</p>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="card shadow-sm p-3 mb-5 bg-white rounded">
<div class="card-body">
<h5 class="card-title">Enjoyed the calculator?</h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container bg-light p-5">
<h3>HOW IT WORKS</h3>
</div>
</div>
{% endblock %}
django view
def two_way_calc(request):
if request.method == 'POST':
odd1 = float(request.POST.get('odd1'))
odd2 = float(request.POST.get('odd2'))
func_def = odd_finder_true_2(odd1, odd2)
context = {
'Juice': func_def['Juice'],
'TotalImpliedProbability': func_def['TotalImpliedProbability'],
'HomeOdd': func_def['HomeOdd'],
'AwayOdd': func_def['AwayOdd'],
'Home_True_Odd': func_def['Home_True_Odd'],
'Away_True_Odd': func_def['Away_True_Odd'],
'True_Probability': func_def['True_Probability'],
'Home_implied_probability': func_def['Home_implied_probability'],
'Away_implied_probability': func_def['Away_implied_probability'],
'Inverted_Probability': func_def['Inverted_Probability'],
}
return render(request, 'three_way_temp.html', context)
else:
return render(request, 'three_way_temp.html', {})
urls.py
from django.urls import path
from .views import *
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('two_way_calc/', views.two_way_calc, name='two_way_calc'),
]
Python function behind the calculation
def odd_finder_true_2(first_odd, second_odd):
home_implied_probability = round((100/first_odd), 2)
away_implied_probability = round((100/second_odd), 2)
total_implied_probability = home_implied_probability + away_implied_probability
inverted = (100/total_implied_probability) * 100
juice = total_implied_probability - inverted
hundred_odd_home = total_implied_probability/home_implied_probability
hundred_odd_away = total_implied_probability/away_implied_probability
prob_true = 1/(round(hundred_odd_home, 2)) + 1/(round(hundred_odd_away, 2))
my_dict_two = {
'Juice': round(juice, 2),
'TotalImpliedProbability': round(total_implied_probability, 2),
'HomeOdd': first_odd,
'AwayOdd': second_odd,
'Home_True_Odd': round(hundred_odd_home, 2),
'Away_True_Odd': round(hundred_odd_away, 2),
'True_Probability': round(prob_true, 1),
'Home_implied_probability': home_implied_probability,
'Away_implied_probability': away_implied_probability,
'Inverted_Probability': round(inverted, 2)
}
return my_dict_two
so there are a few things that i should say before your answer
First of all it's better approach to use AJAX instead of submit your form because AJAX prevents the page from being reloaded and by using it you do not need to send a whole complete http request and receive a complete response
It will only send needed information to server and get exact answer and js helps you to inject that data in your page
Second you don't actually and necessarily need jQuery, you can do what you want in pure js using fetch API however jQuery is an option too
Now the answer
5xx Errors are server side errors and thank to you for sending your complete code i can show you error
So the problem is when you trigger submit event, you are changing one input and this causes your form to be submitted,
BUT, WHAT ABOUT SECOND INPUT?
it has no value and thus your server can't do the calculations right
How to fix this?
It's up to your algorithm, if you can find a default value to be set on the second input, it can solve the probe
Or
You can check it in you jQuery code
$(".form-control").on("change",function(){
if($("Odd2").value !== "")
$('#myform').submit()
}) ;
Also The jQuery code you've write is correct but it can be better
You are using change event which fires after the value is changed AND when user left the input (blur event)
You will get a better and more live result using input event
$(".form-control").on("input",...)
===============
Updated, based on your last comments, my guess was right and you want the answer to be shown to the user immediately after he entered the number
So you need to use another event called input here's the result (you can add a simple alert before that if to see how input event fires
$(".form-control").on("input",function(){
if($("Odd2").value !== "")
$('#myform').submit()
}) ;
Let me know if your code is changed a lot and provide me your new jQuery code if this didn't solve your problem
============
Updated
Again my guess was right and you need to prevent page from being reloaded (or redirected) this can be done by AJAX
you have multiple choices in AJAX
you can use pure JS (xmlHttpRequest object)
you can use Fetch API in js
you can use Axios.js which is a great library designed to handle Ajax requests and responses
Or finally you can use jQuery
Because in your project you are already using jQuery, I'll do it using jQuery but i don't approve it, Fetch is best option in my opinion, anyway :
$(".form-control").on("input",function(){
if($("Odd2").value !== "")
var fData = new FormData($('#myform'));
var jqxhr = $.ajax({
url: 'AddressToYourBackendFile',
method : 'POST',
data : fData
});
jqxhr.done( res => {
console.log('your response is ready :\n' + res);
});
}) ;

How can I re-run a Django For Loop inside a HTML Div using Javascript on Click Event

I have a HTML div like this,
<div class="coment-area ">
<ul class="we-comet">
{% for j in comment %}
<div id="delete_comment{{j.id}}" class="mt-3">
{% if j.post_id.id == i.id %}
<li >
<div class="comet-avatar">
{% if j.user_id.User_Image %}
<img class="card-img-top" style=" vertical-align: middle;width: 50px;height: 50px;border-radius: 50%;" src= {{ j.user_id.User_Image.url }} alt="">
{% else %}
<img class="card-img-top" style=" vertical-align: middle;width: 60px;height: 60px;border-radius: 50%;" src="static\images\resources\no-profile.jpg">
{% endif %}
</div>
Inside of it is a For Loop that is executed when the page is first loaded.
Below this For Loop is a Comments Button
<div >
<button type="submit" onclick="comment_save(event,{{i.id}})" class= "my-2 ml-2 px-2 py-1 btn-info active hover:bg-gray-400 rounded ">Comment</button>
</div>
</div>
</li>
</ul>
</div>
Whenever this button of Comments is clicked, a function in Javascript is called which is defined below,
function comment_save(event,post_id)
{
var comment_value=$("#comment_value"+post_id).val();
var user_id=$("#comment_user_id"+post_id).val()
postdata={
"comment_value":comment_value,
"user_id":user_id,
"post_id":post_id
}
SendDataToServer("readmore",postdata,function()
{
alert()
})
$("#comment_value"+post_id).val(" ")
<! --- document.location.reload().. Something here that refresh that for loop --->
}
What I want is this that whenever the button is clicked, it re-executes that for Loop inside my main div without having to refresh the page. I have been trying to do this for two days but could not find any solution to this. Can anyone help me in doing this?
The Django Templating Language is executed server-side. That means the client (browser, running Javascript) has no access to it whatsoever.
Some of your options are:
Do everything back-end: Re-render the template (which you said don't want to do).
Do everything front-end: You could have your view function return the data used in your template loop and re-implement it in your front-end (but that makes the original template loop kind of pointless).
Hybrid: Return the data for only the new comment in your response and add it to the list with Javascript.

how to change id per form in select2 django formset

i need to increment id field forms per form
default id which django provides is id_formsetname_set-0-fieldName and 0 increment one by one
in my case named id_items_set-0-model and for second form will be id_items_set-1-model it display in inspect element source code from browser , i used this for loo script
for (var i = 0; i < 10; i++){
$("#id_items_set-"+i+"-model").select2();
}
but only worked for the first form , i dont want to use django-select2
my template looks like this
this is my snippet
<tbody class="tbody tb1 " id="form_set">
{% for item in items.forms %}
<tr class="p-0 col-12">
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.price | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.quantity | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.model | add_class:'col-12 0model model' | attr:'id:id_items_set-0-model'}}
</div>
</td>
</tr>
{% endfor %}
</tbody>
<script type="text/javascript">
$(function(){
$('.tb1 tr:last').formset({
prefix:'{{items.prefix}}',
addText:'add',
deleteText:'remove',
addCssClass:'btn btn-success',
});
})
</script>
<script type="text/javascript">
$(document).ready(function(){
for (var i = 0; i < 10; i++){
$("#id_items_set-"+i+"-model").select2();
}
})
</script>
only work for my first form then doesnt have any effect on other forms ? is there something i did wrongly in the script part please?
jquery.formset has added attribute we can call a function every time when a row created
<script type="text/javascript">
$(function(){
$('.tb1 tr:last').formset({
prefix:'{{items.prefix}}',
addText:'add',
deleteText:'remove',
addCssClass:'btn btn-success',
added:function($row){
$('.model').select2()
}
});
})
</script>
I have never worked on django .
Could you try this please .
and if you could share with us a link for real example in case this doesn't work
$(()=>{
let ids = document.querySelectorAll("[id=*'id_items_set']");
ids.forEach((element)=>{
$(element).select2();
});
});

Get attribute from a specific element of a class

Basically I have to develop a Tic-Tac-Toe game, here is the HTML file which I can't rewrite only reformat a bit, but the idea should stay the same.
{% block content %}
<nav class="navbar fixed-top navbar-light">
<button id="retry-button" class="btn btn-success">Try again?</button>
Reset settings
</nav>
<div id="game-board" class="mb-3" data-row-num="{{ row_num }}" data-col-num="{{ col_num }}" data-win-size="{{ win_size }}">
{% for row in range(row_num) %}
<div>
{% for col in range(col_num) %}
<div class="game-cell"
data-coordinate-x="{{ col }}"
data-coordinate-y="{{ row }}"></div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endblock %}
As you can see i have a game-cell class which contains by default 9 elements. I would like to return the data-coordinate-x and data-coordinate-y when I click one of the game-cells. I had a previous try but if I clicked it returned all of the blocks not just the one i clicked on. I have to write it in Js. If you can point me in the right direction that's more than enough for me.
Thanks!
If I understood correctly, you need to access data attributes of your game-cell element. In order to do this, you need to select the element by some ID or class. I have modified your code a little to make it run inside stackoverflow`s platform. I have added an ID which i called "unique" and I also set some values into your coordinate-x and y data attributes. Please review the code bellow and see how I managed to get those data attributes. It's important to notice that this is not the only way to access them.
var gamecell = document.getElementById('unique');
console.log(gamecell.dataset.coordinateX);
console.log(gamecell.dataset.coordinateY);
<nav class="navbar fixed-top navbar-light">
<button id="retry-button" class="btn btn-success">Try again?</button>
Reset settings
</nav>
<div id="game-board" class="mb-3" data-row-num="{{ row_num }}" data-col-num="{{ col_num }}" data-win-size="{{ win_size }}">
<div>
<div class="game-cell" id="unique"
data-coordinate-x="172"
data-coordinate-y="273"></div>
</div>
</div>
Its also possible to get these values using the getAttribute method.
var elem = document.getElementById('unique');
var coordX = elem.getAttribute('data-coordinateX');
var coordY = elem.getAttribute('data-coordinateY');
Please, take a look at this page, it explains some aspects of data attributes:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
Simply access your clicked game-cell by: (it will find the clicked coordinateX and coordinateY)
document.querySelectorAll('.game-cell').forEach((game) => {
game.addEventListener('click',function(event){
console.log(game.dataset.coordinateX);
console.log(game.dataset.coordinateY);
});
});
you must to get your element by class name or id(add an id)
than you can get its attributes like this
let gameCell = document.getElementById('game-cell-id');// id for example
gameCell.getAttribute('data-coordinate-x')

Semantic Form Dropdown get value

I am using a Semantic Dropdown in one of my forms. I am adding the options using jinja2 as shown below.
<div class="ui selection dropdown">
<input type="hidden" name="set">
<i class="dropdown icon"></i>
<div class="default text">Class</div>
<div class="menu">
{% for set in sets %}
<div class="item" data-value="{{ set.id }}">{{ set.name }}</div>
{% endfor %}
</div>
</div>
I am trying to get the data-value with javascript, and this is what I am currently using:
var setID = $('.ui.dropdown').dropdown('get value');
However when I use console.log(setID) nothing is printed.
Any help would be appreciated
I found the problem: I had an if statement further down with 1 = instead of two so it overwrote setID's value.

Categories

Resources