Convert checkbox 'on' to Boolean before posting to Django view - javascript

I am building a Django app that has a main dashboard with a bunch of on/off toggles. My goal would be to allow the user to toggle their settings on or off and have their changes automatically saved to the database.
So I followed this tutorial to leverage Ajax form submissions in my Django app so that the user would not have to reload the page. The problem that I am having (I think) is that the checkbox values are being POSTed to my Django views as 'on' whereas they should be POSTed as 'True'.
I think that this is the cause of the error, because I see this in my error logs:
Exception Type: IntegrityError at /update_usersettings/
Exception Value: dataplan_usersettings.normalize_person_name_proper may not be NULL
...
POST:
id_normalize_person_name_proper = u'on'
id_normalize_company_name_proper = u'on'
My existing JavaScript and Django views.py are here: https://gist.github.com/joefusaro/25b6221536291c1ba0d1
Update:
I've added the relevant Django template and forms code here. Not that I am using widget_tweaks for form rendering. The form renders like so:
<form action="/update_usersettings/" method="POST" id="usersettings_form">
<input checked="checked" class="bootstrap-switch-default" id="id_normalize_person_name_proper" name="bootstrap-switch" type="checkbox" />
<input checked="checked" class="bootstrap-switch-default" id="id_normalize_company_name_proper" name="bootstrap-switch" type="checkbox" />
<input type="submit" value="Post">
FINAL UPDATE
Thanks to Animesh for a great starting point. Here is the final Ajax code required. Special thanks to Victor K. for his help figuring this out!
Here is the final Ajax code:
$(function() {
// Submit post on submit
$('#usersettings_form').on('submit', function(event){
event.preventDefault();
console.log("Form submitted...") // sanity check
save_usersettings();
});
$('input[type="checkbox"]').on('switchChange.bootstrapSwitch', function(event, state) {
$('#usersettings_form').submit();
});
// AJAX for posting.
function get_post_data() {
var data = {};
$('input:checkbox').each(function () {
var $this = $(this);
var id = $this.attr('id');
data[id.replace('id_', '')] = $this.is(':checked');
});
return data;
}
function save_usersettings() {
console.log("Saving user settings...") // sanity check
$.ajax({
url : "update_usersettings/", // the endpoint
type : "POST", // http method
data : get_post_data(),
// handle a successful response
success : function(json) {
console.log(json); // log the returned json to the console
// $("#talk").prepend("<li><strong>"+json.text+"</strong> - <em> "+json.author+"</em> - <span> "+json.created+
// "</span> - <a id='delete-post-"+json.postpk+"'>delete me</a></li>");
console.log("Successfully saved user settings."); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
// $('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
// " <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
};
And here is the final views.py:
class UpdateUserSettings(LoginRequiredMixin, UpdateView):
model = UserSettings
form = UserSettingsForm
def post(self, request, *args, **kwargs):
if request.method=='POST':
response_data = {}
form = UserSettingsForm({})
us = UserSettings.objects.get(user=1)
VALUE_MAP = {
'false': False,
'true': True
}
for name, field in form.fields.items():
if isinstance(field, BooleanField):
if request.POST.get(name):
if request.POST[name] in VALUE_MAP.keys():
setattr(
us,
name,
VALUE_MAP[request.POST[name]]
)
us.save()
response_data['result'] = 'Update successful!'
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({"nothing to see": "this isn't happening"}),
content_type="application/json"
)

You can handle this inside the view.
CHECKBOX_MAPPING = {'on':True,
'off':False,}
class UpdateUserSettings(LoginRequiredMixin, View):
model = UserSettings
def post(self,request,*args,**kwargs):
normalize_person_name_proper = CHECKBOX_MAPPING.get(request.POST.get('normalize_person_name_proper'))
You can do this for all the fields you are supposed to receive in checkboxes from the user.
Also, one thing to note here is that you need not use request.method=='POST'check inside the post method of a class based generic view. The method will be called only when the request is POST.What you are looking for is if request.is_ajax():
Hope this helps.

Related

Ajax is not sending multiselect data to Django views

I am quite new to Django so bare with me.
I have a multiselct list in my webpage and I need to send the selected items to my views in order to make use of them.
To do so, I used ajax but when it doesn't seem to work for some reason.
This is the script:
$("#var_button").click(function(e) {
var deleted = [];
$.each($("#my-select option:selected"), function(){
deleted.push($(this).val());
});
alert("You have deleted - " + deleted);
e.preventDefault();
$.ajax({
type: "post",
url: "/description/upload-csv/" ,
data: {
'deleted' : deleted }
}); // End ajax method
});
I checked with alert if maybe the variable deleted is empty but it return the selected values so the problem is in my ajax query.
This is the part where I retrieve the data in my views.py
if request.method == 'POST':
del_var = request.POST.getlist("deleted[]")
my_class.del_var = del_var
I changed the data type to text but it doesn't do anything
I cant help you on the Django side.
$.each($('#selector'), (i, e) => {
deleted.push($(e).val());
})
but this will add the value to the "deleted" variable.

display ajax result on new page

I would like to display the results of an ajax request on a new page rather than the page the ajax call was made from. Essentially I have a membership directory page. When the user clicks on the member ID cell on that page, an ajax call sends the ID to the server and completes an HTML table to display that member profile. If I add a <div> element below the membership directory page, I can make the profile information table display below the membership directory table. But I want the profile table to display on different page.
JavaScript:
$jq.ajax({
url : ajax_mmmp.ajax_url,
type : 'post',
data : {
action: 'mmmp_profile_member_id_callback',
mem_id : member_id
},
success:function(data) {
// This outputs the result of the ajax request
console.log(data);
// Return response to client side
alert("Submit Success");
$jq('#display_profile').html( data );
return false;
},
error: function(errorThrown){
console.log(errorThrown);
}
}); // End of AJAX function
But when I create a new page with the same <div> element and try to open that page prior to the ajax call, the result does not display.
var mem_profile = "http://localhost:81/wordpress/view-member-profile"
window.open (mem_profile,'_self',false)
$jq.ajax({
url : ajax_mmmp.ajax_url,
type : 'post',
data : {
action: 'mmmp_profile_member_id_callback',
mem_id : member_id
},
success:function(data) {
// This outputs the result of the ajax request
console.log(data);
// Return response to client side
alert("Submit Success");
$jq('#display_profile').html( data );
return false;
},
error: function(errorThrown){
console.log(errorThrown);
}
}); // End of AJAX function
Putting aside the question of whether it is a good idea to take that approach, the answer to your question is yes. You can open a new window and write the resulting HTML to it:
// open a new window with no url and a title. check the docs for other args to open()
let win = window.open('','My New Window');
// write some HTML to that window
win.document.write('<table><tr><th>test</th></tr></table>');
After some further research, I'm almost there. I do not presently have a "form" to submit. The user simply clicks on a table cell which contains a member ID number. I want to 'submit' that value as input on another page which displays the membership profile. I have been successful in temporarily adding a HTML form that works as desired if I type the member ID in an input field. So I decided what was needed was to create a hidden form in JS that used the ID value that was clicked on. It appears that I can not insert revised code into a comment, so I opted to 'Answer' my original question with updated code.
Working HTML Form included on Membership Directory Page:
$site_url = site_url();
$location = $site_url . "/view-member-profile";
?>
<form action="<?php echo $location;?>" method="post">
<input type="text" class="input_member_id" id="input_member_id" name="Member_ID">
<input type="submit" id="submit_member_id" name="submit_member_id" value="Submit">
</form>
My attempt to create a similar hidden form in JS:
var $jq = jQuery.noConflict();
$jq(document).ready(function(){
// Add listener for Member ID click in member directory
$jq("#mem_dir").delegate(".member_id", "click", function() {
var mem_id = $jq(this).text();
var mem_id = mem_id.trim();
alert ("ID is: " + mem_id);
var site_url = document.location.origin + '/wordpress';
var form_location = site_url + '/view-member-profile';
alert ("Submit to location is: " + form_location);
var form = $jq('<form method="post" class="js:hidden">').attr('action', form_location);
//var input = $jq('<input type="hidden"'>).attr('value', mem_id );
//form.append(input);
//$jq('body').append(form);
form.submit();
}); // End of Click Member ID Listener
}); // End of Main Document Ready Function
The problem I am having with the JS file is with inserting the mem_id value into the input form. The JS file correctly opens the new View Member Profile page. (Note the 3 // lines just prior to the form.submit). When uncommented, the Profile page opens, but table values are empty (i.e. mem_id value was not passed to the page).
Thanks for any advice. If I was supposed to list this as a new question, please let me know.

Django render template in template using AJAX

My site currently renders forms on their own page. I'm trying to get them to render inside a sidebar div tag now on my main page. However, I can't figure out how to shape the JavaScript and/or View so I get the HTML of the form template back and inserted into the div tag.
UPDATE
I'm getting the following error in the console: GET http://127.0.0.1:8000/new_trend/ 500 (Internal Server Error)
HTML (tag on the main page which I want to inject the form template into):
<div id="sidebar">
</div>
JavaScript
$(function() {
$("#new-trend").click(function(event){
alert("User wants to add new trend"); //this works
$.ajax({
type: "GET",
url:"/new_trend/",
success: function(data) {
$('#sidebar').html(data),
openNav()
}
})
});
});
VIEW
def new_indicator(request):
# if this is a POST request we need to process the form data
if request.method == "POST":
# create a form instance and populate it with data from the request:
form = IndicatorForm(request.POST)
# check whether it's valid:
if form.is_valid():
indicator = form.save(commit=False)
indicator.author = request.user
indicator.modified_date = timezone.now()
indicator.save()
return redirect('dashboard')
else:
form = IndicatorForm()
return render(request, 'mysite/sidebar_trend.html', {'form': form})
I was able to figure this out on my own. For others who come across this (myself included!), here's how I got it working.
JavaScript
There was a couple of fixes here. First you need to include the csrftoken, which yo can get through another JS function. Second, the AJAX request needs to be a POST, not a GET (not sure why, if you know please comment below). Here's the updated code snippet...
// Get cookie for CSRF token (from Django documentation)
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
// Load new Trend form
$(function() {
$("#new-trend").click(function(event){
var csrftoken = getCookie('csrftoken');
$.ajax({
type: "POST",
url: "/new_trend/",
data: {'csrfmiddlewaretoken': csrftoken},
success : function(data) {
$('#sidebar').html(data);
openNav()
}
})
alert("User wants to add new trend") //this works
});
});
VIEW
The second thing that needs to be corrected is the View function. First you need to render the HTML into a string, then return the string in an HttpResponse. This blog post provides a detailed explanation of why so I'm not going to go into it here. This is what the new code looks like...
#login_required
def ajax_indicator_form(request):
form = IndicatorForm()
html = render_to_string('mysite/sidebar_trend.html', {'form': form})
return HttpResponse(html)

codeigniter: I can't change view page

I'm having some problems changing the view page in the code. Note: i'm using ajax.
This is part of the controller function called "insert_inventario" after the information is saved in array_db it compares with the inventario_model and the result "true" or "false" is saved in obj_inv.
$obj_inv = $this->Inventario_model->insert_inventario($array_db);
if($obj_inv){
$edit_view = $this->load->view(base_url()."inventario/edit",$array_db,TRUE);
$response = array('mensaje' => $edit_view,
);
$this->output
->set_status_header(200)
->set_content_type('application/json', 'utf-8')
->set_output(json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES))
->_display();
exit;
}
This is part of the view page called create, this is the submit button that executes the Javascript code that execute the controller function
<input type="submit" class="btn btn-danger" id="btn_enviar" value="Guardar">
The javascript Function
$("#btn_enviar").click(function(){
var r = confirm("Make sure the information you fill is correct");
if (r == true){
var url = base_url + "/inventario/insert_inventario";
$.ajax({
type: "POST",
url: url,
data: $("#form_inventario").serialize(),
success: function(data)
{
$("#contenido").html(data.mensaje);
}
});
}
return false;
});
The problem is, when i fill the form and press submit, the message box appears and when I click accept, it does nothing. I'm burning my brain so much to understand what I'm doing wrong, please help me.
The main problem is a error called jquery-2.1.4.min.js:4 POST http://161.196.112.19:8080/Inventario_Remedy/inventario/insert_inventario 500 (Internal Server Error) it happens when the code try to insert the array
$obj_inv = $this->Inventario_model->insert_inventario($array_db);
So, in order to fix this, you have to check your database values and keep trying.

Django + Ajax error in returning data

I have a model called Item and I'm trying to create Items with Ajax, everything looks to be working ok, but I'm getting and error at the end of the process, in the success function in Ajax. I have been reading a lot of answers to questions like this here in StackOverflow but I couldnt make it work:
This is my model:
PRIORITY_CHOICES = (
(1, 'Low'),
(2, 'Normal'),
(3, 'High'),
)
class Item(models.Model):
name = models.CharField(max_length=60)
description = models.TextField(max_length=1000)
created = models.DateTimeField(auto_now_add=True)
priority = models.IntegerField(choices=PRIORITY_CHOICES, default=1)
done = models.BooleanField(default=False)
meeting = models.ForeignKey(Meeting)
def __str__(self):
return self.name
This is my view, whichs is working Ok and saving the data into de database:
from .forms import AddItemForm
from .utils import render_to_json_response
class AjaxFormResponseMixin(object):
def form_invalid(self, form):
return render_to_json_response(form.errors, status=400)
def form_valid(self, form):
# save
self.object = form.save()
# initialize an empty context
context = {}
# return the context as json
return render_to_json_response(self.get_context_data(context))
class AjaxItemCreateView(AjaxFormResponseMixin, CreateView):
form_class = AddItemForm
def get_context_data(self, context):
context['success'] = True
context['name'] = self.object.name
context['description'] = self.object.description
return context
as you can see, I'm using a custom shortcut called render_to_json_response in order to parse data in Json
this is the code of the shortcut (Please notice that I'm printing the context, in order to verify the data):
from django.http import JsonResponse
def render_to_json_response(context, **response_kwargs):
print (context)
return JsonResponse(context)
(if you're wondering why I'm using this simple shortcut it's because previously I was trying to return the response with HttpResponse and specifying content_type="application/json", but it also wasn't working)
This is my ajax code:
function AddItem(event){
var csrftoken = getCookie('csrftoken');
var item_name = $('#item-name').val();
var item_desription = $('#item-description').val();
var item_priority = $('#item-priority').val();
var item_meeting_pk = $('#item-meeting-pk').val();
var url = "/item/add/";
$.ajax({
type: "POST",
url: url,
data: {
'name': item_name,
'description': item_desription,
'priority': item_priority,
'meeting': item_meeting_pk ,
'csrfmiddlewaretoken': csrftoken
},
success: function(data){
alert("success");
alert(data);
},
complete: function(data){
alert("completed");
alert(JSON.stringify(data));
}
});
}
and, finally, this is the form that calls the AddItem() function:
<form>
{% csrf_token %}
<input type="text" placeholder="Nombre del item" id='item-name'/>
<input type="text" placeholder="Descripción del item" id='item-description'/>
<select id="item-priority" name="provider" class="form-control">
<option value="1">Baja</option>
<option value="2">Normal</option>
<option value="3">Alta</option>
</select>
<input type='hidden' id='item-meeting-pk' value='{{ meeting.pk }}'>
<button onclick='AddItem()' class="button-blue" >Agregar</button>
</form>
When I submit the form, everything goes fine, and in my django shell I can see that the post request is returning 200 and the data is printing ok:
{'name': 'asdkkasd', 'description': 'sdksdksjd', 'success': True}
[29/Aug/2015 08:34:22]"POST /item/add/ HTTP/1.1" 200 65
in the ajax function I have javascript alerts in both success and complete, but only the complete's one is executing and this is what I'm getting with the execution of alert(JSON.stringify(data));:
{"readyState": 0, "responseText":"", "status":0, "statusText": "error"}
I hope you can help me, thank you :)
Your form is almost certainly invalid; you're returning a 400 status in that case from form_invalid, which triggers jQuery to call the failure function if there is one, rather than success.
Unfortunately, you can't use proper RESTful status codes in this kind of situation. An invalid form submission should still return a 200.
There is a difference between success and complete function of the ajax function that you are using...
success
It gets called on a response of 200 (OK).
complete
This will get called always , well as the name suggests the request did succeed, even if was a failure on the server side or OK response. It just succeeded (ie: landed your server and brought something back to offer to your client(browser,mobile whatever).So that's complete method for.
You can do away with this method and can use only success if not needed otherwise.
For more info. Read here
FYI :
The readystate output you showed says 0 , hence the request isn't initialized.It should be 4 for the request to be complete.

Categories

Resources