Django: request.is_ajax() returning False - javascript

I'm trying to make the search of 'patient' Dynamic with ajax. Every thing in my code is working well but I don't know wy request.is_ajax() always returns false. I search about it but I didn't find the solution yet, right now my code do the search but with changing of the url and that mean the js dosen't work. I don't know how work well with javascript in Django so please help me.
This is my views.py:
def index(request):
ctx = {}
url_parameter = request.GET.get("q")
if url_parameter:
queryset = Patient.objects.annotate(fullname=Concat('first_name', Value(' '), 'last_name'))
patients = queryset.filter(fullname__icontains=url_parameter)
#patients = Patient.objects.filter(name__icontains=url_parameter)
else:
patients = Patient.objects.all()
ctx["patients"] = patients
print(request.is_ajax())
if request.is_ajax():
html = render_to_string(template_name="patient/patients-results-partial.html",context={"patients": patients})
data_dict = {"html_from_view": html}
return JsonResponse(data=data_dict, safe=False)
return render(request, "patient/index.html", context=ctx)
index.html:
{% extends 'base.html' %}
{% block content %}
<div class="col-md-6 offset-md-4">
{# part added for dynamic search#}
{# icon and search-box #}
<form class="form-inline">
<i id="search-icon" class="fas fa-search" aria-hidden="true"></i>
<input id="patient-input" class="form-control form-control-sm ml-3 w-75" type="text" placeholder="Search" aria-label="Search" name="q">
</form>
{# artist-list section #}
<div id="replaceable-content" class="col-6">
{% include 'patient/patients-results-partial.html' %}
</div>
</div>
<div class="col-md-6 offset-md-4">
Ajouter un nouveau patient
</div>
<div class="col-md-6 offset-md-4">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Prénom</th>
<th>Nom</th>
<th>Téléphone</th>
<th>Sexe</th>
<th>Date de naissance</th>
<th>Docteur</th>
</tr>
</thead>
<tbody>
{% for field in patients %}
<tr>
<td>{{field.first_name}}</td>
<td>{{field.last_name}}</td>
<td>{{field.phone}}</td>
<td>{{field.sex}}</td>
<td>{{field.birth_date}}</td>
<td>{{field.doctor}}</td>
<td>Details</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock content %}
and this is my js code:
const patient_input = $("#patient-input");
const search_icon = $('#search-icon');
const patients_div = $('#replaceable-content');
const endpoint = '/patient/';
const delay_by_in_ms = 700;
let scheduled_function = false;
let ajax_call = function (endpoint, request_parameters) {
$.getJSON(endpoint, request_parameters)
.done(response => {
// fade out the patients_div, then:
patients_div.fadeTo('slow', 0).promise().then(() => {
// replace the HTML contents
patients_div.html(response['html_from_view'])
// fade-in the div with new contents
patients_div.fadeTo('slow', 1)
// stop animating search icon
search_icon.removeClass('blink')
})
})
}
patient_input.on('keyup', function () {
const request_parameters = {
q: $(this).val() // value of patient_input: the HTML element with ID patient-input
}
// start animating the search icon with the CSS class
search_icon.addClass('blink')
// if scheduled_function is NOT false, cancel the execution of the function
if (scheduled_function) {
clearTimeout(scheduled_function)
}
// setTimeout returns the ID of the function to be executed
scheduled_function = setTimeout(ajax_call, delay_by_in_ms, endpoint, request_parameters)
})

I think this kind of AJAX call, is clean and easier than what you have in your code.
This model AJAX is working for me.
Maybe this js code helps you to fix your bug.
$('#form').on('submit', function (event) {
event.preventDefault();
const form = $(this);
const submit_btn = form.find('#submit-button');
$.ajax({
url: 'your URL for send ajax call',
type: 'POST', // Method of call, such as POST or GET
data: 'data as JSON', // You can use 'form.serialize()' to
beforeSend: function () {
// This line calls before that AJAX is called.
},
success: function (data) {
// If the back-end returns a JSON response with 200 status code, js will run this line.
},
error: function (data) {
// If the back-end returns a JSON response with 400 status code, js will run this line.
},
complete: function () {
// After success or error is called , this function will be called
},
})
})

Related

Loading category tags with load more button

I am new to jQuery. I have implemented a "load more" button on my blog app using jQuery, however the categories tags doesn't get displayed on the html when I click on that button.
Everything works fine so far, I can't just display the tags on the post card, it keeps returning undefined.
Note: I'm getting my categories from a many to many field relationship
Here are my views:
def home(request):
post = BlogPost.objects.all()[0:5]
total_post = BlogPost.objects.count()
context = {'post': post, 'total_post':total_post}
return render(request,'blog/home.html', context)
def load_more(request):
# get total items currently being displayed
total_item = int(request.GET.get('total_item'))
# amount of additional posts to be displayed when i click on load more
limit = 3
posts = list(BlogPost.objects.values()[total_item:total_item+limit])
print(BlogPost.objects.all())
data = {
'posts':posts,
}
return JsonResponse(data=data)
Template:
<div class="blogpost-container">
<div class="blogposts" id="blog-content">
{% for post in post %}
<div class="post">
<img id="img-src" src="{{post.image.url}} " image-url="{{post.image.url}}" alt="">
<p><strong>{{post.title}}</strong></p>
{% for category in post.category.all%}
<h3>{{category}}</h3>
{%endfor%}
<a id="post-detail-link" href="{% url 'detail' post.id %}" detail-url="{% url 'detail' post.id %}"><h2>{{post.summary}}</h2></a>
</div>
{%endfor%}
</div>
</div>
<div class="add-more" data-url='{% url "load_more" %}'id="add-btn">
<button type="button" class="more-content">load more</button>
</div>
<div class="alert no-more-data" role="alert" id="alert">
No more post to load!!!
</div>
{{total_post|json_script:"json-total"}}
JS file:
const loadBtn = document.getElementById('add-btn')
const total_post = JSON.parse(document.getElementById('json-total').textContent);
const alert = document.getElementById('alert')
function loadmorePost(){
const content_container = document.getElementById('blog-content');
var _current_item =$('.post').length;
$.ajax({
url:$('.add-more').attr('data-url'),
type:'GET',
data:{
'total_item':_current_item
},
beforeSend:function(){
alert.classList.add('no-more-data')
},
success:function(response){
const data = response.posts
alert.classList.add('no-more-data')
data.forEach(posts => {
const imageurl = 'media/'+posts.image
const detailurl = 'post/'+posts.id;
const category = posts.category;
content_container.innerHTML +=`<div class="post" id=${posts.id}>
<img id="img-src" src=${imageurl} image-url="{{post.image.url}alt="">
<p><strong>${posts.title}</strong></p>
<h3>${category}</h3>
<a id="post-detail-link" href=${detailurl}><h2>${posts.summary}</h2></a>
</div>`
})
if (_current_item == total_post){
alert.classList.remove('no-more-data')
loadBtn.classList.add('no-more-data')
}
else{ loadBtn.classList.remove('no-more-data')
alert.classList.add('no-more-data')
}
},
error:function(err){
console.log(err);
},
});
};
loadBtn.addEventListener('click', () => {
loadmorePost()
});

Pass javascript output to a html <div> as a parameter

I have a m_template.html file which has a script as follow:
<script>
$("#id_country").change(function () {
var countryId = $(this).val(); // get the selected country ID from the HTML input
$.ajax({ // initialize an AJAX request
url: '/ajax/ajax_load_cities',
data: {
'countries': countryId // add the country id to the GET parameters
},
dataType: 'json',
success: function (data) { // here data comes from url output or load_cities function
$("#preview-items").html(data.tags);
}
});
});
</script>
In the same template.html I defined a section like:
<div id="preview-items">
{% for item in itemslist %}
<label class="btn btn-primary mr-1">
<input type="checkbox" id="checklist" value="{{ item.0 }}">
<span>
{{ item.1 }}
</span>
</label>
{% endfor %}
</div>
and load_cieties:
def load_cities(request):
....
data = {
'tags': list(cities)
}
return JsonResponse(data)
Where problem happens:
The problem is in the line $("#preview-items").html(data.tags); which rather than passing list, replaces list in the <div> so at the moment I have something like:
id1name1,id2name2,id3name3,...
My Question:
How to pass data.tags which is a list of tuples to section as a parameter that within which I be able to style list items as I already defined in ?
data.tags is something like [(id1, name1), (id2, name2), (id3, name3), ..]
I would use a bit more sophisticated code (like React), but would this solve the immediate issue?
First, javascript doesn't have tuples, so send it a list of lists (json) from python: [['id1', 'name1'], ['id2', 'name2'], ['id3', 'name3']];
success: function (data) {
$('#preview-items').html('');
for (var i in data) {
console.log(i, data);
$('#preview-items').append(`
<label class="btn btn-primary mr-1">
<input type="checkbox" id="checklist" value="` + data[i][0] + `">
<span>
` + data[i][1] + `
</span>
</label><br />`
);
}
}
(Note the use of backticks in the javascript multi-line string)

How do I pass a list of models from a table in a view to a controller?

I'm just learning about MVC and a problem I've run into is passing a list of models to a controller. I have AutomationSettingsModel, which contains a list of AutomationMachines. I've successfully populated a table in my view with checkboxes bound to data in AutomationMachines. However, passing the data to a method in the controller is turning out to be harder than I expected.
Here is my view with the first attempt at passing the data:
#model FulfillmentDashboard.Areas.Receiving.Models.Automation_Settings.AutomationSettingsModel
<div class="container-fluid px-lg-5">
#using (Html.BeginForm("Index", "ReceiverSettings", "get"))
{
<div>
<h2>Receiving Automation Settings</h2>
<br>
<table id="machineSettings" class="table">
<tr>
<th>Automation Machine Name</th>
<th>Divert Line Setting </th>
</tr>
#if (Model.AutomationMachines != null && Model.AutomationMachines.Count > 0)
{
foreach (var item in Model.AutomationMachines)
{
<tr>
<td> #Html.DisplayFor(x => item.Name) </td>
<td> #Html.CheckBoxFor(x => item.DivertSetting) </td>
</tr>
}
}
</table>
<div class="row">
<input class="btn btn-primary" type="button" value="Save"
onclick="location.href='#Url.Action("UpdateDivertSettings", "ReceiverSettings", new { models = #Model.AutomationMachines } )'" />
</div>
</div>
}
</div>
This resulted in UpdateDivertSettings being hit in my controller, but the data was null. After some searching, it looks like I will need to use Ajax, which I am unfamiliar with. I tried following the example at this site, which resulted in the following addition to the view:
<input type="button" id="btnSave" value="Save All" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script type="text/javascript">
$("body").on("click", "#btnSave", function () {
//Loop through the Table rows and build a JSON array.
var machines = new Array();
$("#machineSettings TBODY TR").each(function () {
var row = $(this);
var machine = {};
machine.Name = row.find("TD").eq(0).html();
machine.DivertSetting = row.find("TD").eq(1).html();
machines.push(machine);
});
//Send the JSON array to Controller using AJAX.
$.ajax({
type: "POST",
url: "/ReceiverSettings/UpdateDivertSettings",
data: JSON.stringify(machines),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (r) {
alert(r + " record(s) inserted.");
}
});
});
</script>
However that never seemed to hit UpdateDivertSettings in the controller. Some more searching resulting in the idea of serializing my AutomationSettingsModel and passing that via Ajax, but I'm not really sure how to do that. It also looks like I can do something using Ajax.BeginForm, but I can't figure out how I would structure the new form. So I'm trying to get some input on the easiest way to get this data to my controller.
Edit:
Here is the controller as it currently stands:
namespace FulfillmentDashboard.Areas.Receiving.Controllers
{
[RouteArea("Receiving")]
public class ReceiverSettingsController : BaseController
{
private readonly AutomationService automationService;
public ReceiverSettingsController(AutomationService _automationService)
{
automationService = _automationService;
}
[Route("ReceiverSettings/Index")]
public async Task<ActionResult> Index()
{
var refreshedView = await automationService.GetAutomationSettings( new AutomationSettingsModel(ActiveUserState.ActiveIdSite) );
refreshedView.AutomationMachineIdSite = ActiveUserState.ActiveIdSite;
return View("Index", refreshedView);
}
public async Task<ActionResult> UpdateDivertSettings(List<AutomationMachineModel> machines)
{
//foreach (AutomationMachineModel machine in machines)
//{
// var results = await automationService.UpdateAutomationSettings(machine, ActiveUserState.IdUser);
//}
return Json(new { #success = true });
}
}
}

Django Modal For User Login/Register - Form Render Issue

I'm trying to create a login/register modal based on the JS/Bootstrap here:
https://www.creative-tim.com/product/login-and-register-modal
I'm just looking for guidance as I'm having an issue displaying the form inputs on my modal. The modals will pop up fine upon click, yet the form inputs are not appearing.
If i visit the page accounts/sign_in or accounts/sign_up and click on one of the buttons, then i do get the popup with the form inputs (for the most part).
Thus, i think i must be improperly handling the render in my login_form view.
I created this 'login_form' view following some guidance from this post here
//views.py
def login_form(request):
signup_form = UserCreationForm()
login_form = AuthenticationForm()
context = {"signup_form": signup_form, "login_form": login_form}
return render(request, 'layout2.html', context)
and my url's:
//urls.py
app_name = "accounts"
urlpatterns = [
url(r'sign_in/$', views.login_form, name='sign_in'),
url(r'sign_up/$', views.login_form, name='sign_up'),
this is the relevant modal code in my layout2.html file:
<div class="form loginBox">
<form method="POST" action="{% url 'accounts:sign_in' %}">
{% csrf_token %}
<input type="hidden" name="form_name" value="login_form">
{{ login_form.as_p }}
<input type="submit" onclick="loginAjax()">
</form>
</div>
</div>
</div>
<div class="box">
<div class="content registerBox" style="display:none;">
<div class="form">
<form method="POST" action="{% url 'accounts:sign_up' %}" html="{:multipart=>true}" data-remote="true" accept-charset="UTF-8">
{% csrf_token %}
<input type="hidden" name="form_name" value="signup_form">
{{ signup_form.as_p }}
<input type="submit" onclick="loginAjax()">
</form>
</div>
Not sure if this is relevant to my issue in any way, but just in case here is JS handling modal pop ups:
/*
*
* login-register modal
* Autor: Creative Tim
* Web-autor: creative.tim
* Web script: http://creative-tim.com
*
*/
function showRegisterForm(){
$('.loginBox').fadeOut('fast',function(){
$('.registerBox').fadeIn('fast');
$('.login-footer').fadeOut('fast',function(){
$('.register-footer').fadeIn('fast');
});
$('.modal-title').html('Register with');
});
$('.error').removeClass('alert alert-danger').html('');
}
function showLoginForm(){
$('#loginModal .registerBox').fadeOut('fast',function(){
$('.loginBox').fadeIn('fast');
$('.register-footer').fadeOut('fast',function(){
$('.login-footer').fadeIn('fast');
});
$('.modal-title').html('Login with');
});
$('.error').removeClass('alert alert-danger').html('');
}
function openLoginModal(){
showLoginForm();
setTimeout(function(){
$('#loginModal').modal('show');
}, 230);
}
function openRegisterModal(){
showRegisterForm();
setTimeout(function(){
$('#loginModal').modal('show');
}, 230);
}
function loginAjax(){
/* Remove this comments when moving to server
$.post( "/login", function( data ) {
if(data == 1){
window.location.replace("/home");
} else {
shakeModal();
}
});
*/
/* Simulate error message from the server */
shakeModal();
}
function shakeModal(){
$('#loginModal .modal-dialog').addClass('shake');
$('.error').addClass('alert alert-danger').html("Invalid email/password combination");
$('input[type="password"]').val('');
setTimeout( function(){
$('#loginModal .modal-dialog').removeClass('shake');
}, 1000 );
}
--------------UPDATE ON VIEW---------------
Here is what it looks like on homepage if i click on Login:
And this is what it looks like if i go to accounts/sign_in and click on sign_in button:
UPDATE Here is my updatd Home view with added
class Home(generic.TemplateView):
model = Deal
template_name = 'test.html'
def get_context_data(self, **kwargs):
context = super(Home, self).get_context_data(**kwargs)
today = datetime.datetime.today()
deals = Deal.objects.all()
context['deals'] = deals.filter(Q(date_expires__gte=today))
categories = Category.objects.all()
context['categories'] = categories
signup_form = UserCreationForm()
login_form = AuthenticationForm()
context["signup_form"] = signup_form
context["login_form"] = login_form
return context
The problem is that you are attaching your def login_form(request): function to the sig_in, sign_up view and not in the home page just add and it should work as you expect
url(r'^$', views.login_form, name='')
As you already had the view home just add into the context:
signup_form = UserCreationForm()
login_form = AuthenticationForm()
context["signup_form"] = signup_form
context["login_form"] = login_form

Razor and Ajax: How to reload a table upon successful Ajax call?

I have the following table that contains Razor code, it is a list of users along with each user's basic details, along with the option to edit or delete each user:
<table class="table table-striped">
<tr bgcolor="#FF0000"><th>Username</th><th>User Role</th><th>User Privileges</th><th>Status</th></tr>
#if (Model.Count() == 0)
{
<tr><td colspan="4" class="text-center">No User Accounts</td></tr>
}
else
{
foreach (AppUser user in Model)
{
if (!(user.UserName.ToLower().Equals("admin")))
{
<tr>
<td>#user.UserName</td>
<td>#user.UserRole()</td>
<td>#user.UserPrivs()</td>
<td>
#if (#user.LockedOut)
{
#:Locked
}
else
{
#: Unlocked
}
</td>
<td>
#using (Html.BeginForm("Delete", "Admin",
new { id = user.Id }, FormMethod.Post, new { #id = "manageusersform", name = user.UserName }))
{
<button class="btn btn-primary btn-xs editUserBtn"
data-id="#user.Id" name="#user.Id">
Edit
</button>
<button class="btn btn-danger btn-xs"
type="submit">
Delete
</button>
}
</td>
</tr>
}
}
}
</table>
<div style="text-align:center;">
<button class="btn btn-primary btn-xs" id="addnewuser">
Add New User
</button>
As shown above, there is also a button to add a new user. Clicking that brings up a popup form (with id signupform) to enter the new user's details, and when that form is submitted, the following javascript gets called:
$("form#signupform").submit(function (event) {
event.preventDefault();
var form = $(this);
$.post(form.attr("action"), form.serialize(), function (res) {
if (res.status === "success") {
alert(res.message);
$(".form-control").val('');
/*
reload the table
*/
}
else {
alert(res.message);
}
});
});
My goal is to implement the commented reload the table, without having to reload the entire page, which is what I am doing now:
$("form#signupform").submit(function (event) {
event.preventDefault();
var form = $(this);
$.post(form.attr("action"), form.serialize(), function (res) {
if (res.status === "success") {
alert(res.message);
$(".form-control").val('');
/*
$.ajax({
url: "/Admin/Index",
cache: false,
data: {}
}).done(function (htmlResponse) {
$("#tabs-1ua").html(htmlResponse);
});
*/
}
else {
alert(res.message);
}
});
});
Reloading the whole page causes some javascript issues such as the popup not working again, so I am trying to reload just the table now, and would like help.
Thank you.
You may create an action method which returns the partial view for the table markup.
public ActionResult GetUserTable()
{
var list = new List<AppUser>();
// to do : Populate list with data from your data source( user table?)
return PartialView(list);
}
and in the GetUserTable.cshtml partial view, put the view code you currently have to render the table
#{ Layout = null; }
#model List<AppUser>
<table id="usreList">
<!-- to do: loop throug model and render table rows) -->
</table>
You can use the same action method in your main view as well. Just call this action method
#Html.Action("GetUserTable","Users")
<div style="text-align:center;">
<button class="btn btn-primary btn-xs" id="addnewuser">
Add New User
</button>
This will render the user table same as what you currently have.
Now in your ajax success, you can reload your user table by calling this action method asynchronously.
if (res.status === "success") {
$("#usreList").load('/Users/GetUserTable');
}
Finally, for the jquery events you wired up to work with the newly injected/dynamic dom elements,you need to use on method.
So replace
$(".someClass").click(function(e){
// do something
});
with
$(document).on("click",".someClass",function(e){
// do something
});

Categories