from Javascript to Python on click [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm working on a feature for a heatmap. When I click on a cell in the chart, a boxplot will pop up, and I am using django and highcharts models for the implementation.
Currently, I am stuck with the passing of variable from a javascript function to the python server side. I know for django there is a post and get method, but I don't have a form in this case, only the clicks. Whenever I click on a cell in the heatmap, I would like to pass the x-label and y-label strings to the python server, process and grab data in python, and then feed the data back to the pop-up boxplot. Thank you !
$(function () {
$('#container').highcharts({
chart: {
type: 'heatmap'
},
plotOptions: {
series: {
events:{
click: function cellClick() {
var $div = $('<div></div>')
.dialog({
title: this.name,
width: 400,
height: 300
});
window.chart = new Highcharts.Chart({
chart: {
renderTo: $div[0],
type: 'boxplot'
},
series: [{
name: 'Observations',
data: [
//here I would like to insert data passed from the python view
// on click of a cell in the heatmap
],
}, {
name: 'Outliers',
color: Highcharts.getOptions().colors[0],
type: 'scatter',
data: [//data from python view],
}]
})
}
}
}
},
xAxis: {
opposite: true,
categories: label,
labels:{
formatter: function(){
//I would like to pass factor_x to the server(python) on click
//of a cell in the heatmap
var factor_x = this.value;
if (factor_x.length > 6){
return factor_x.substr(0,6) ;
}else{
return factor_x;
}
}
},
},
yAxis: {
categories: label2,
labels:{
formatter: function(){
// pass factor_y to the server side on-click
var factor_y = this.value;
if (factor_y.length > 7){
return factor_y.substr(0,7) + "...";
}else{
return factor_y;
}
}
},
},
series: [{
name: 'Factor Correlation',
data: correlation,
}]
});
});

Okay so what you can do is write click functions for the cells of heatmaps.
In the onclick functions, you'll get the value of that cell by using the "this" variable in javascript, as it tells you what container or DOM element you clicked.
So now $(this).data or whatever attribute of that element has the required information (which you can check in your browser on your console by inspecting element) will give you the data you want to send to your views so that you can manipulate it.
So for that you'll call another function say send_data() from this onclick function and you'll pass this required information to that function maybe as one or two variables or as a list like this:
send_data(info);
where info is a list of all the required elements.
Now inside the send_data function you'll make an ajax call to the URL corresponding to the class or def in your views to which you want to supply this information like this:
function send_data(req_info) {
$.ajax({
type: "POST",
url: "/heatmap_cell_data/",
data: req_info,
// dataType: 'json',
success: function(response){
console.log(response);
}
});
}
Now in your urls.py you'll associate a def/class in views corresponding to the URL in your Ajax function. You'll receive this data in request.POST, then you'll do whatever you want to in that view and finally return an HTTPResponse(whatever data you want to) back to the javascript which you'll receive as response in your success function.
NOTE -> Sending an HTTPRespnse from views.py back to the Ajax request is a must or else you'll get an error that no HTTPResponse found.
Now you can use this response data to modify your heatmaps again.
I hope this was what you were looking for.

The most secure way to handle this with Django is to pass the CSRF token along with each AJAX request you post data within. The easiest way to do this is to put this on your page (it appears you are using jQuery so this should work as is):
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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
crossDomain: false, // obviates need for sameOrigin test
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
What this does is grab the CSRF cookie that Django typically stores on the browser when someone accesses a form and send it along with the AJAX requests.
This means you will also need something like this on the page somewhere:
<form>
{% csrf_token %}
</form>
On your view function, you will want the csrf_protect decorator. You can also use require_post to only accept POST data on this view:
#require_post
#csrf_protect
def my_view(request):
pass
The most ideal way to handle the functionality you are looking for is when you need a plot, post it to a view like the above and then have another view for getting the latest results. This will also work better if multiple people can mess with it at the same time.
In jQuery that would mean using something like:
$.post('/my_view/', some_json_data);
And to collect the data you would use:
$.get('/my_view_updates/', success: somefunctiontoparseresponse);

Related

Refresh page after updating via AJAX request in Epi Server

I have an Epi server page template with following property:
[Display(
Name = "Selection Box",
GroupName = Global.GroupNames.Contact
)]
public virtual bool SelectionBox { get; set; }
In the view I have something like this:
#if (PageEditing.PageIsInEditMode)
{
#Html.CheckBoxFor(modelItem => Model.CurrentPage.SelectionBox,
new
{
#class = "toggle",
#data_url = Url.Action("UpdatePage", "DefaultPage"),
})
<script>
$(function () {
$('.toggle').change(function () {
var self = $(this);
var url = self.data('url');
var value = self.prop('checked');
$.ajax({
url: url,
data: { selected: value },
type: 'POST',
success: function (response) {
alert(response);
}
});
});
});
</script>
}
Basically what it does, it when I change checkbox value, it sends request to controller and updates the value on the page. What I'm missing is that when this sucesfully happens, I would like the page reload but I can't find a way to do it.
I'm not using OOTB on page editing here, as I'm looking for a way to give editors some adavnced editing for the component, yet I don't want to build a dojo widget. Any ideas how to make this work?
There is a chapter on "On-page editing with client-side rendering" in the developer guides, see https://world.episerver.com/documentation/developer-guides/CMS/editing/on-page-editing-with-client-side-rendering/
The purpose of using Ajax is to design a SPA (single page application) where no page reload is required. If you are looking for a page reload, you can probably do
window.location.reload();
But a page reload might cause you to lose data return by the Ajax call.

How to property update bootstrap autocomplete source after Ajax call

I am currently implementing the autocomplete bootstrap control from here. I only want to populate the source when characters are more than 2. I'm wondering how do I populate my type ahead source after a successful ajax call.
https://github.com/bassjobsen/Bootstrap-3-Typeahead.
var $input = $(".typeahead");
$input.keyup(function () {
var count = $input[0].value.length;
if (count >= 3) {
$.ajax({
type: "GET",
url: '/Home/GetProducts',
data: {
characters: $input[0].value
},
success: function (response) {
$input.typeahead({
source: response,
autoSelect: true
});
}
});
}
});
When I put a breakpoint at response, this is the result
So my ajax query works, but the type ahead doesn't populate with the results and aren't searchable.

AJAX query not always updating information consistently

I am experiecing some issues with AJAX updating the page. The actual data in the database is updated but this is not always reflecting in real time on the web page.
For example, I have the following event:
$("#add_note").click(function(e) {
//e.preventDefault();
$("#add_note_form").validate({
rules: {
contact_note: {
required: true
}
},
submitHandler: function(form) {
contact.modal_update({
'obj' : $('#add_note_form'),
'uri' : '/contact/add_note/'
});
}
});
});
This function when a new note is created calls a callback to validate the form fields first and then if successful calls a callback inside a seperate class to conduct the update. See the modal_update class below:
// Update modal
this.modal_update = function(data)
{//
// Declare a few variables for the data object we've received
obj = data.obj // The form element to serialize
uri = data.uri;
// Get the form ID from the data-target attribute
id = obj.attr('data-target');
// URL to send to
url = this.site_url + uri + id;
// The form object
this.post_data(obj.serialize(),url);
// Hide Modal
obj.closest('.modal').modal('hide');
// Refresh
this.refresh();
}
This then figures out the correct route to ajax and calls a ajax call back inside the same class:
// AJAX post
this.post_data = function(obj,uri)
{
$.ajax({
data: obj,
dataType: 'json',
type: 'post',
url: uri,
headers: { "cache-control": "no-cache" },
cache: false,
success: function (response) {
if (response.success == true)
{
$("#alert_success .msg").html(response.message);
$("#alert_success").fadeIn(200).delay(2000).fadeOut(200);
}
else
{
$("#alert_error .msg").html(response.error);
$("#alert_error").fadeIn(200).delay(2000).fadeOut(200);
console.log(response.error);
}
}
});
}
I am then running another class callback to "refresh" the data in all the elements on the page:
this.refresh = function()
{
// Refresh the ajax requests
this.get_contact_data();
this.get_notes();
this.get_contact_log();
this.get_contact_tasks();
}
This class re loads the functions which run on page load to get the inial data into the tables/fields on the page. See "get_notes" below:
// Get notes
this.get_notes = function()
{
// Get all notes and populate table
var log_uri = this.site_url + "/contact/get_notes/" + this.contact_id;
this.get_data(log_uri,function(data) {
notes = $("#contact_notes ul");
notes.empty("");
// Populate the contact fields, assuming there is a result to play with
if (data != false) {
//alert(JSON.stringify(data));
$("#notes-tab .count").html("(" + data.length + ")");
$.each( data, function( key, value ) {
notes.append("<li class='list-group-item' modal-id='editNoteModal' data-target='" + value.ID + "'><div class='row'><div class='col-lg-3'><i class='fa fa-sticky-note mr-3'></i>" + value.timestamp + "</div><div class='col-lg-7'>" + value.note + "</div><div class='col-lg-2'><a href='#' class='edit mr-3'><i class='fa fa-edit mr-1'></i>Edit</a><a href='#' class='delete'><i class='fa fa-times mr-1'></i>Remove</a></div></div></li>");
});
console.log('Notes loaded');
} else {
notes.append("<li>There are currently no notes for this contact</li>");
}
});
}
Now the problem:
For some reason this does not update consistently in real time. The data is updated fine on the server side but on the client side the update/refresh does not always update. I might add a note and get a correct update response but the refresh method seems to be receiving the old data and always be one note behind. So the next time I add a note, the one I added before then appears and so forth.
Another problem I am experiencing is the methods seem to stack on each event so if I add one note (or one of the other methods) I will see the console say "notes loaded" but on the second note it says "notes loaded" twice, then on the 3rd note added 3 times and so forth.
I am sure there must be something fatal flaw in the design of my code here but I am not experienced enough with javascript/jquery to notice what direction I am going wrong so I can fix it.
I thought that this was an issue with ajax caching and not refreshing the result so I have adjusted the ajax request as cache none and also to send no cache headers. I am running in wamp.
In your case, your refresh code will always run before your data got updated. Because ajax is asynchronous so the code behind and below ajax will always execute nearly the time your ajax running.
At the time you run your post_data function to call the API, the refresh function got run too. So it's done before your data got updated.
You should run refresh function inside ajax callback. For example:
this.post_data = function(obj,uri, callback)
{
$.ajax({
data: obj,
dataType: 'json',
type: 'post',
url: uri,
headers: { "cache-control": "no-cache" },
cache: false,
success: function (response) {
if (response.success == true)
{
$("#alert_success .msg").html(response.message);
$("#alert_success").fadeIn(200).delay(2000).fadeOut(200);
}
else
{
$("#alert_error .msg").html(response.error);
$("#alert_error").fadeIn(200).delay(2000).fadeOut(200);
console.log(response.error);
}
callback();
}
});
}
And in modal_update, you pass refresh function to post_data as a callback:
this.modal_update = function(data)
{//
// Declare a few variables for the data object we've received
obj = data.obj // The form element to serialize
uri = data.uri;
// Get the form ID from the data-target attribute
id = obj.attr('data-target');
// URL to send to
url = this.site_url + uri + id;
// The form object
this.post_data(obj.serialize(),url, this.refresh);
// Hide Modal
obj.closest('.modal').modal('hide');
}
You should read more about asynchronous ajax. You can use other tricky solution is setTimeout to run this.refresh but I do not recommend that because you not sure when the update is done.

Proper way of doing AJAX request to retrieve data from database

I got a database with one table in it.
Table has Company and Time columns, and some more, but these two are important.
So the user makes an appointment through the filling of the form.
In the form I have 2 <select>s - Company And Time, so he chooses both from the selections.
He clicks a button and the form is stored in the database.
How do I use AJAX to retrieve all the hours(Time) that are in use, and then disable them accordingly.
For example: I made the appointment selected Nokia from Companies and 9:30 from Time dropdowns. Now You want to make the appointment with Nokia but the 9:30 time is disabled because it has already been used.
What would be the correct way to use AJAX for this:
this is my structure
function MakeApp() {
var AppWith = $("#CompanySelect").val();
var AppTime = $("#TimeSelect").val();
var Yritys = $("#YritysNtext").val();
var Henkilonimi = $("#HenkilonimiText").val();
var Asema = $("#AsemaText").val();
var PuhelinNR = $("#PuhelinText").val();
var EMail = $("#EMailText").val();
var Keskustelun = $("#KeskustelunText").val();
var app = { AppWithYritys: AppWith, AppTime: AppTime, YritysN: Yritys, Henkilonimi: Henkilonimi, Asema: Asema, PuhelinNR: PuhelinNR, EMail: EMail, Keskustelun: Keskustelun }
var request = $.ajax({
type: "POST",
data: JSON.stringify(app),
url: "/api/Appointments",
contentType: "application/json",
dataType: "html"
});
request.done(function (podaci) {
if (podaci != -1) {
alert("You Have successfully made an appointment");
location.assign("BookAppointment.html");
}
else {
$("#p1").html("Greska pri unosu");
}
});
request.fail(function (gr) {
$("#p1").html(gr.statusText);
});
};
Actually it's your server job to manage data and database. AJAX is only a way to send information to a server aysnchronously. What you could do, is when you load the page, you retrieve only the occupied time with AJAX, you disable their options in your select, and whenever your server receive an request, it checks if there is an available place for the company and times.
I'm sorry i don't have a code for your since I think it's pretty clear. If it's not, feel free to comment, i'll try to help you the best i can.
Edit
Here I have a few lines of code, it's not complete since we are missing a few informations but it is the main algorythm.
Your server:
{GET}
public void getUnavailable() {
//get all times from Databases for today's date.,
//Encode them in JSON.
//returns the times.
}
Lets assume that your JSON looks like this:
[
{
"company": "Nokia",
"times": [
"9:30",
"10:00",
"10:30"
]
}
]
You need to retrieve your JSON and parse it to disable the time in the selected select:
$(document).ready(function(){
$.ajax({
'url': API_URL + 'event/getUnavailable',
'method': 'GET',
'success': function(data) {
$.each(data.data, function($index, $company){
var select = /* .. Get the Select of the current company .. */
$.each($company.times, function($index, $times){
select./*.. Find the time associate with $time .. */.setDisable(true); // I don't know if setDisable is the correct function, you might want to check this out.
})
})
},
'error': function(error) {
console.error(error.data);
}
});
$('.myForm').submit(function(){
// This is where you submit your data to your server.
$.ajax({
'url': API_URL + "event/create",
'method': 'POST',
'data': /* your data */,
'success': function(){
console.log('success');
},
'error': function(error) {
console.error(error);
}
})
});
})
This is the most I can do with the info I have.
The real way to handle this, is whatever web technology you have behind /api/Appointments, is to return whatever appointments are available. Your variable names don't make much sense to me, so try to understand what the code below does.
$.get( "/api/Appointments", JSON.stringify(app) )
.done(function( data ) {
//note that the "data" variable holds your returned appointments
//I would return a json document of available appointment times to filter your select
//sample json would look something like this
// { "availableAppointments": ["9:30 AM", "10:00 AM"] }
// and then iterate through available appointments and populate your select
for(var i = 0; i < data.availableAppointments.length; i++){
$('#yourSelectId').append($('<option>', {
value: 930,
text: data.availableAppointments[i]
}));
}
});
Please note this code may not be syntactically correct.
Here are some links that helped me answer this for you, in case they might help.
Adding options to a <select> using jQuery?
https://api.jquery.com/jquery.get/

How to request a web page in JavaScript

In my site, there's a pervasive search bar that is a typeahead widget. The widget has a 'selected' callback that I am currently trying to implement.
In the callback, it determines whether or not it needs to make an AJAX request on the existing page or whether it needs to go to another page. My problem is that I cannot find anywhere a way to do a redirect with POSTed variables, like in a jQuery AJAX request. Is there any way to attain a page request with posted variables that will totally refresh the page, like clicking on a normal hyperlink?
Here is my code:
function getData(event, datum, dataset) {
event.preventDefault();
// get controller action portion of current url
var Controller = '<?= preg_replace('/\/.*/', '', preg_replace('/\/.*\/web\//', '', Yii::$app->request->url)) ?>';
var Key;
// get key out of key-value pair - will either be 'game', 'developer' or 'publisher'
for (var k in datum) {
Key = k;
}
// if the controller action is the same as key, then the request is ajax
// this works fine
if (Key === Controller) {
var req = $.ajax( {
type: 'POST',
url: 'getchilddata',
data: { data: datum[Key] },
})
.done(function(data) {
$('#display-div').html(data);
})
.fail(function() {
console.log("Failed");
})
} else { // else we need to go to a page on a different controller action according to Key
// this is the best i've got so far but want it to be better
window.location.href = Key + '/datastream?q=' + datum[Key];
}
}
The only way to achieve this is creating a form with hidden inputs, because you can't send post variables via Javascript, fortunately there is a Jquery plugin who will save you some code, but at the end the plugin just create a hidden form and simulate the redirect sending the form via POST, this is how to use it:
if (Key === Controller) {
$.ajax( {...})
} else {
$().redirect(Key + '/datastream, {'q': 'datum[Key]'});
}
Note: You can pass the method (GET or POST) as an optional third parameter, POST is the default

Categories

Resources