how can i resolve the issue in displaying the ajax search results in django? - javascript

Problem
The results are being retrieved by the ajax search function but when I display the data retrieved in the selector using $(selector).htm(data) it loads whole the page with a page with correct search results.
The code is attached below with the screenshot of what I'm getting from this code for a better understanding.
JS
$('#searchsubmit').on('click', function(e){
e.preventDefault();
q = $('#search').val();
console.log(q);
updateContentBySearch(q);
});
function updateContentBySearch(q) {
var data = {};
data['search_by'] = q
// data["csrfmiddlewaretoken"] = $('#searchform [name="csrfmiddlewaretoken"]').val();
$.ajax({
method: 'POST',
url: "{% url 'main:Search' %}",
data: {
'search_by': q,
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()
},
success: function (data) {
searchSuccess(data)
}
});
}
function searchSuccess(data, textStatus,jqXHR)
{
$('#search-results').html(data);
}
HTML
<div class="row">
<div class="row justify-content-center" style="text-align:center">
<form class="d-flex col-md-6" id="searchform" method="POST">
{% csrf_token %}
<div class="input-group mb-3" style="text-align:center">
<input name="q" type="text" class="form-control" placeholder="Search" id="search">
<button class="btn btn-primary shadow px-5 py-2" type="submit" id="searchsubmit">Search</button>
</div>
</form>
</div>
<hr style="border-top: 1px solid #ccc; background: transparent;">
<div class="row" id="search-results">
{% regroup transaction by productID as ProductList %}
{% for productID in ProductList %}
///some code
</div>
{% endfor %}
</div>
VIEWS
#csrf_exempt
def search(request):
q = request.POST.get('search_by')
print(q)
product = Products.objects.all()
cart_product_form = CartAddProductForm()
transaction = transactions.objects.filter(productID__name__icontains=q,status='Enable').order_by('productID')
print(transaction)
context={
'products':product,
'transaction': transaction,
'cart_product_form':cart_product_form
}
html = render_to_string('main/home.html',context)
return JsonResponse(html,safe=False , content_type="application/json")
SCREENSHOT
Now in this screenshot u can see it showing me two banners and search bars and after the second the products from the search results are displayed. It's like it loads the whole page again within the page from the selector i have passed data too.
DOES ANYONE KNOWS HOW TO RESOLE THIS ISSUE OR WHERE I HAVE DONE WRONG.

because you render 'main/home.html' agin ! you just need send a json response with your context data and add it to web page with JS or create a new html template and render that with your context data and send that as response!

Related

JavaScript is not executed in tracking form

I'm doing an e-commerce website for school and got the task to implement an order tracking system to display the status history of the order. I used a template for this, and half of the code is working. In the views.py file I fetch the information form the database and put it in json format.
However in my html file there is a js script that is supposed to display the iformation from the database and that is not working.
I unfortunately do not have any previous experience with web development, so I'm lost as to why it doesn't work because in the video that used the template it worked.
If someone could help me that would be fantastic as we have to hand the project in in two days.
PS.:
When I put in the ref code and email, it just gives back the HttpResponse with the json. I'm not sure what to do with the HttpResponse though. How does it interact with the script in the html file?
I put
jQuery.noConflict();
at the start of the script as I thought maybe the bootstrap js was overshadowing my script. It didn't do anything though.
Here is my views.py function:
def tracking(request):
if request.method == "POST":
ref_code = request.POST.get('ref_code', '')
email = request.POST.get('email', '')
try:
order = Order.objects.filter(ref_code=ref_code, email=email)
if len(order) > 0:
update = OrderUpdate.objects.filter(ref_code=ref_code)
updates = []
for item in update:
updates.append(
{'text': item.update_desc, 'time': item.timestamp})
response = json.dumps(updates, default=str)
return HttpResponse(response)
else:
return HttpResponse('Please enter a valid ref code and email address.')
finally:
print()
return render(request, 'order_tracking.html')
Here is the script from the order_tracking html file:
<script>
jQuery.noConflict();
$('#trackingForm').submit(function(event) {
$('#items').empty();
var formData = {
'ref_code': $('input[name=ref_code]').val(),
'email': $('input[name=email]').val(),
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val()
};
print(ref_code)
$.ajax({
type: 'POST',
url: '/order-tracking/',
data: formData,
encode: true
})
.done(function(data) {
console.log(data)
updates = JSON.parse(data);
if (updates.length > 0 & updates != {}) {
for (i = 0; i < updates.length; i++) {
let text = updates[i]['text'];
let time = updates[i]['time'];
mystr = `
<li class="list-group-item d-flex justify-content-between align-items-center">
${text}
<span class="badge badge-primary badge-pill">${time}</span>
</li>`
$('#items').append(mystr);
}
} else {
mystr = `<li class="list-group-item d-flex justify-content-between align-items-center">
Sorry, We are not able to fetch this ref code and email. Make sure to type correct ref code and email</li>`
$('#items').append(mystr);
}
});
event.preventDefault();
});
</script>
And this is the rest of the html file, I'm not sure if it's relevant:
{% block content %}
<div class="container tracking">
<div class="col my-4">
<h2> Enter Your Order ID and Email address to track your order </h2>
<form method="post" action="#" id="trackingForm">{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
<label for="inputname">Ref Code</label>
<input type="text" class="form-control" id="ref_code" name="ref_code" placeholder="Ref Code">
</div>
<div class="form-group col-md-6">
<label for="inputEmail">Email</label>
<input type="email" class="form-control" id="email" name="email" placeholder="Email">
</div>
<button type="submit" class="btn btn-primary">Track Order</button>
</div>
</div>
<div class="col my-4">
<h2>Your Order Status:</h2>
<div class="my-4">
<ul class="list-group" id="items">
</ul>
</div>
</div>
</div>
{% endblock content %}

How do you implement input( or form) dependent on a select menu(drop down list)?

I'm working on grading system and I'm currently working on the form that's deals with the user entering the students results now the form I have, has 2 drop-down list(classroom, students) that are dependent. The issue and where I'm stuck is
When the user select the classroom the second drop-down menu will only show the students in that class, I have already figure that out..the issue is I want the input fields for how much subject the student is doing to appear so that the user can enter the grades for each subject specific to that student in the class
Eg if I select classroom 1b and selected student Mary.. if Mary is doing 5 subjects then 5 input field should appear so that I can enter the mark for the subjects
Link with a video showing what I'm talking about video showing an examplehttps://drive.google.com/file/d/11FoCZyOBVdUhTcvCqA1Ke0fEgRmMVC-G/view?usp=drivesdk
Models.py
Class Classroom(models.Models): name = models.charfield()
Class marks (models.Models): classroom = models.foreignkey(Classroom) Grade = models.Floatfield()
Html form
<div class="container-fluid">
<form id="result-form" method="post">
{% csrf_token %}
<!-- Modal -->
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel"> {% block modal-title%} Add Result {% endblock%}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12" id="msg8" style="font-size: 2rem; color:rgb(255, 144, 47)"></div>
<div class="col-md-12 form-group p-2">
<label class="form-label">Class Name</label>
{% render_field form.room class+="form-control" %}
</div>
<div class="col-md-12 form-group p-2">
<label class="form-label">Exam Name</label>
{% render_field form.exam class+="form-control" %}
</div>
<div class="col-md-12 form-group p-2">
<label class="form-label">Student</label>
{% render_field form.student class+="form-control select2" %}
</div>
<div class="hidden" id="subject-fields"></div>
<div class="form-group mb-3 pt-2">
<button type="button" id="resBtn" class="btn btn-info" title="Add">Submit</button>
</div>
</div>
</div>
</form>
</div>
{% block script%}
{% endblock%
script
$(document).on('click', '#submit-btn', function(event){
var response_data = []
var subject_name= $('.course');
var subject_objs = $('.subject_id');
for(i=0;i<subject_name.length;i++){
var subject_id = $(subject_objs[i]).find('input').val();
var grade_input = {
"Marks": subject_id,
}
response_data.push(grade_input);
}
$.ajax({
type: "POST",
url: "{% url 'marks' %}",
data: response_data,
success: function(response){
alert("Success");
}
});
});
This is how your view should look like.
def question_choice_view(request):
if request.method == "POST":
question_choice_data = request.POST['data']
I am not a jQuery User. As far as i can see i would put a eventlistener on the student form via .addEventListener('change', (event)See here. This would fire a function every time something changes on the select option. With that you could also collect the selected option values of the classroom and student name and make a request to get the subject names for the chosen student. After successful response i would insert the subject fields via JavaScript in the DOM.
**
function createInput(item) {
// This function takes a item and creates a new input
var newLabel = ' <br><label for="$item-mark">$item:</label>'
var newInput = '<input type="text" id="$item-mark-id" name="$item-mark"><br><br>';
newLabel = newLabel.replaceAll("$item", item)
newInput = newInput.replaceAll("$item", item)
// combine into a single str
newInput = newLabel + newInput
var studInput = document.getElementById("student-id");
// insert element inputs after student
studInput.insertAdjacentHTML('afterend', newInput);
}
function cleanOldInputs(item) {
var oldELement = item + "-mark-id"
oldELement = document.getElementById(oldELement)
if (oldELement) {
// remove old label and input
oldELement.previousSibling.remove()
oldELement.remove()
} else {}
}
function getAPIcall() {
// This is what your API sends
var responsObject = ["writing", "creativity"];
// loop throug
responsObject.forEach(item => {
// if you already picked a student clean old inputs from DOM
cleanOldInputs(item)
// send to function for input creation
createInput(item)
})
}
// get the Student Input
var studentSelect = document.getElementById("student-id");
studentSelect.addEventListener("click", function() {
// Fire anything you like
getAPIcall()
});
<form action="/action_page.php">
<label for="student">Choose a student:</label>
<select name="student" id="student-id">
<option value="harry">harry</option>
<option value="ivy">ivy</option>
</select>
</form>
Quick and dirty**

How can I update an already rendered built finished Chart.js page Flask?

How can I update an already rendered built finished Chart.js page Flask?
There is already ready Chart.js on the template page.
The value data for which is taken from Flask.
After what action on the page the values in the Flask code changed.
How can I make it so that after a certain action in the route, Flask is additionally updated Chart.js?
I have been thinking for a long time how to make it so that it is updated Chart.js when I change the values in the Flask route ("/range") - I can transfer them (changed DataFrame values) to the database - but then I don't know how to update Chart.js.
it's html code
<div class="row">
<div class="col-md-3">
<input type="text" name="From" id="From" class="form-control" placeholder="From Date"/>
</div>
<div class="col-md-3">
<input type="text" name="to" id="to" class="form-control" placeholder="To Date"/>
</div>
<div class="col-md-6">
<input type="button" name="range" id="range" value="Range" class="btn btn-success"/>
</div>
</div>
<div id="purchase_order"></div>
<hr>
<div class="row" style="align-content: center">
{# <div class="col col-lg-0"></div>#}
</div>
<div class="outer-wrapper" style="align-content: center">
<div class="table-wrapper" id="table-wrapper" style="align-content: center">
<table>
<thead>
{% for col in column_names %}
<th>{{col}}</th>
{% endfor %}
</thead>
<tbody>
{% for row in row_data %}
<tr>
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{# <div class="col col-lg-0"></div>#}
</div>
<div class="row">
<div class="col-md-1">
</div>
<div class="col-md-10">
<div>
<canvas id="myChart" width="800px" style="align-content: center"></canvas>
</div>
</div>
<div class="col-md-1">
</div>
</div>
<br>
</div>
It's script
</script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
$(document).ready(function (){
$.datepicker.setDefaults({
dateFormat: 'yy-mm-dd'
});
$(function (){
$("#From").datepicker();
$("#to").datepicker();
});
$('#range').click(function (){
var From = $('#From').val();
var to = $('#to').val();
if (From != '' && to != '')
{
$.ajax({
url:"/range",
method:"POST",
data:{From:From, to:to},
success:function (data)
{
$('#table-wrapper').html(data);
$('#table-wrapper').append(data.htmlresponse);
}
});
}
else
{
alert("Please Select the Date")
}
});
});
</script>
<script>
const labels = [{% for item in os_x %}
"{{ item }}",
{% endfor %}];
const data = {
labels: labels,
datasets: [{
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [{% for item in os_y %}
{{ item }},
{% endfor %}],
}]
};
const config = {
type: 'line',
data: data,
options: {}
};
</script>
<script>
const myChart = new Chart(
document.getElementById('myChart'),
config
);
</script>
it's Flask routes
#app.route('/', methods=['GET','POST'])
#app.route('/index')
def home_page(): # put application's code here
df = pd.read_sql('select * from kotel', con=db.engine)
df['date'] = df['date'].dt.round('2min')
y_data = df['tnv'].tolist()
x_data = df['date'].tolist()
df_graph = df.copy()
return render_template('index new.html', column_names=df.columns.values, row_data=list(df.values.tolist()), column_names_graph=df_graph.columns.values, os_y = y_data, os_x = x_data)
#app.route("/range", methods=["POST","GET"])
def range():
if request.method == 'POST':
From = request.form['From']
to = request.form['to']
df = pd.read_sql('select * from kotel', con=db.engine)
df['date'] = pd.to_datetime(df['date'])
df = df.loc[(df['date'] >= From) & (df['date'] <= to)]
df['date'] = df['date'].dt.round('2min')
return jsonify({'htmlresponse': render_template('response.html', column_names=df.columns.values, row_data=list(df.values.tolist()))})
If the page is already loaded, only the values sent with the first request are displayed. If you want to see constantly updated values in your chart, you should use Websockets.
I've never worked with charts.js before, but I've used Flot Plot with Flask and Websocket to stream values to a chart in real time. it works great.
You can read more about Websockets and Flask here
If you want to load new values after and action, as example a click over a button, then you have to use ajax.
i found this page that could help you.
I see you are already using ajax. I would recommend just wrapping your code in a SetInterval() which will execute the code over and over again in a specific interval, you could do it like this
<script>
$(document).ready(function (){
setInterval(function() {
$.datepicker.setDefaults({
dateFormat: 'yy-mm-dd'
});
$(function (){
$("#From").datepicker();
$("#to").datepicker();
});
$('#range').click(function (){
var From = $('#From').val();
var to = $('#to').val();
if (From != '' && to != '')
{
$.ajax({
url:"/range",
method:"POST",
data:{From:From, to:to},
success:function (data)
{
$('#table-wrapper').html(data);
$('#table-wrapper').append(data.htmlresponse);
}
});
}
else
{
alert("Please Select the Date")
}
});
},1000);
});
</script>
you can change the number at the end, it specifies how long you want your interval to be in ms, so right now it's set to run every 1 second.

i try ajax partial refresh html,but it does't work

I'm trying to load the page locally with Ajax, but the following code doesn't work.
My idea is to pass the 'MSG' information of 'views' to Ajax and refresh the page locally without loading the entire page. If the input does not meet the requirements, the front end rejects the submission and gives a prompt message.
views.py
def login(request):
hashkey = CaptchaStore.generate_key()
image_url = captcha_image_url(hashkey)
captcha = {'image_url': image_url, 'hashkey':hashkey}
if request.POST:
username = request.POST['username']
password = request.POST['password']
key = request.POST['hashkey']
capt = request.POST['captcha']
if username and password:
if captchautil.is_valid(capt, key):
user = auth.authenticate(username=username, password=password)
human = True
if user:
auth.login(request, user)
return redirect('/')
else:
msg = '用户名密码错误'
else:
msg = '请输入正确的验证码'
else:
msg = '请输入用户名与密码'
return render(request, 'login.html', locals())
return render(request, 'login.html', locals())
login.html
{% block content %}
<div id="login" class="login">
<form action="/login/" method="post" class="navbar-form">
{% csrf_token %}
<div id="input" class="form-group">
<input type="username" name="username" class="form-control" placeholder="请输入手机号或邮箱" id='user' title="请输入手机号或邮箱"><br><br>
<input type="password" name="password" class="form-control" placeholder="密码" id='pwd' title="请输入密码"><br><br>
<img src="{{image_url}}" alt='验证码' id='id_captcha'>
<span>看不清验证码?刷新</span>
<br>
<input id='captcha' placeholder="请输入验证码" name="captcha" class="form-control" type="text" data-toggle="tooltip" data-placement="bottom" title="请输入验证码">
<input value="{{hashkey}}" type="hidden" name="hashkey" id='hashkey'>
<br>
<button type="submit" class="btn btn-primary form-control" name="click" id='click'>登录</button>
</div>
<p style="margin-left: auto;" id="msg">{{ msg }}</p></div>
</form>
<div style="margin-left: 3%">
<span>
忘记密码了?
</span>
<span style="margin-left: 3%">免费注册</span>
</div>
</div>
{% endblock %}
{% block lastscript %}
<script type="text/javascript">
$(document).ready(function(){
//刷新验证码
$('#refresh_captcha').click(function(){
$.getJSON("/refresh_captcha/", function(result){
$('#id_captcha').attr('src', result['image_url']);
$('#hashkey').val(result['hashkey'])
});
});
});
$(function(){
$("#click").submit(function(){
var username = $("#user").val();
var password = $("#pwd").val();
var captcha = $("#captcha").val();
var key = $("#hashkey").val();
$(this).ajaxSubmit({
type:'post',
url: '/login/',
dataType: 'text',
data:{'username':username, "password":password, "capt":captcha, "key":key},
success:function(msg){
$("#msg").html(msg);
}
});
return false;
})
})
</script>
{% endblock %}
I didn't find out where the problem was. Please help me if you know
If you are fetching form dynamically and if you are trying to say like your javascript click functions are not working then you should try below.
$(document).on("click","#test-element",function() {
});
instead of normal click or submit an event
$("#click").submit(function(){ }); .
As per my knowledge if you are creating dynamic elements then the normal click event of jquery will not work. you need to write click event what added above.

How to get data from AJAX request with Symfony 4?

I'm trying to get data from an AJAX request with Symfony 4 and what I get is not that I'm expecting.
Here is my routes.yaml
(...)
ajax_test:
path: /ajax/test
defaults: { _controller: 'App\Controller\AjaxTestController::test' }
requirements:
_method: POST
My controller :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AjaxTestController extends AbstractController
{
public function test(Request $request) {
if ($request->isXmlHttpRequest()) {
$serializer = $this->get('serializer');
$response = $serializer->serialize('test ok', 'json');
return new JsonResponse(['data' => $response]);
}
return new Response("test ko", 400);
}
}
Here is the template where I make the AJAX request :
{% extends "layout.html.twig" %}
{% set active = 'connexion' %}
{% block page_title 'Login' %}
{% block final_javascripts %}
{{ encore_entry_script_tags('sendCredentials') }}
{% endblock %}
{% block content %}
(...)
<div class="row mt-4">
<div class="col-md-6">
<form id="connexion-form" action="{{ path('security_connexion') }}" method="post">
<div class="form-group">
<label for="email">Email</label>
<input type="text" id="email" name="_email" class="form-control">
</div>
<div class="form-group">
<label for="password">Mot de passe</label>
<input type="password" id="password" name="_password" class="form-control">
</div>
<button type="submit" class="btn btn-primary button">Se connecter</button>
</form>
</div>
</div>
</div>
</div></div>
{% endblock %}
And finally the JavaScript file (sendCredentials.js) where I make AJAX request :
$(document).ready(function() {
$('#connexion-form').submit(function(event) {
sendCredentials($('#email').val(), $('#password').val());
});
});
function sendCredentials(username, password) {
$.ajax({
method: "POST",
url: "/ajax/test",
data: {username: username, password: password},
async: false
}).done(function(msg) {
console.log(msg['data']);
console.log(msg);
});
}
The first log console.log(msg['data']); displays undefined. The second log console.log(msg); displays me the html code of the template itself, that is to say the code of the template generated by twig. I don't understand why. How to get the data wanted : 'test ok' ?
P.S. : I don't use credentials yet (username and password), I'm just making tests, I want first the AJAX request to work.

Categories