On getData() I use an ajax get request to pull a few li and append them to the container. On the success of the ajax call I make a variable called next_load which gets the data-attribute and passes it as the url for the next get data call. The problem I have is that on the second click there is a build up of variable on the call. In the console I can see the first date being passed with the second date as well. The goal is on page load to get the first dates. Then clicking on the box to get the next dates and so on.
HTML:
<div id = "calendar">
<div class = "box">
<ul class = "label">
<li>Sun</li>
<li>Mon</li>
<li>Tue</li>
<li>Wed</li>
<li>Thur</li>
<li>Fri</li>
<li>Sat</li>
</ul>
</div>
<ul class = "box-content">
</ul>
</div>
in console:
2 calendar.js:34 2016-03-05 -> on the first get, then this and the next on the second get and it keeps building up.
calendar.js:34 2016-04-09
function getData(url) {
var next_load = '';
$.ajax({
url: 'student/calendar/' + url,
type: 'GET',
success: function(response) {
var $result = $(response).filter('li');
$('.box-content').append($result);
next_load = $result.last().attr('data-date');
useNextLoad(next_load); // dont use the value till the ajax promise resolves here
}
})
}
getData('show/2016/02');
function useNextLoad(next_load){
var load = next_load;
$('.box').click(function(){
getData('load/' + load);
console.log(load); // when i pass the next_load Im getting the previous next load and the new next load at the same time. Then on the next click the amount compounds.
});
}
If I reset the variable next_load would that keep the build up from occuring? I tried to empty the variable before the ajax call but I still get the build up.
Might be an issue with the click function being multiply applied to .box. You may want to remove any existing click handler from .box before binding a new one. See How to remove all Click event handlers in Jquery
function useNextLoad(next_load){
var load = next_load;
$('.box').off("click"); // Remove any click handlers already on .box
$('.box').click(function(){
...
Of course, you can also chain your calls in jQuery if you want to be more compact.
Related
I have a code that should delete a list item.
// Triggers when the item "element_to_click" is double clicked and calls the
// function named show_hide_function()
$( element_to_click ).one('dblclick', function(e) {
show_hide_function(input_mt_key, update_form_mt, input_mt, button_text,
csrfmiddlewaretoken)});
// Creates a button to delete the selected item, then calls delete_function()
function show_hide_function(input_key, form, input, button_text, csrf_token){
const del_btn = document.createElement("button")
del_btn.name="my_del_btn"
form.appendChild(del_btn);
const button_text_del = document.createTextNode("X")
del_btn.appendChild(button_text_del)
del_btn.setAttribute("class", "update_delete_buttons")
// On click on del_btn, calls the function named delete_function()
$( del_btn ).on('click', function(e) {
delete_function(input_key,csrf_token)});
};
// Sends a form to backend (django) and on success, calls another function
// named jsonToDict() which I believe, is not part of the problem. So I don't
// include it here.
function delete_function(input_key, csrf_token){
$(document).on('submit' , function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: '/posted/delete/',
data:{
item_id:input_key.value,
projectURL: projectURL_,
csrfmiddlewaretoken:csrf_token,
},
success: function (data){
jsonToDict(data, "update_delete_form")
};
});
});
};
And simplified version of my django view function looks like this:
def deleteDictionary(request):
print("called")
if request.method == 'POST':
var2 = request.POST['item_id']
projectURL = request.POST['projectURL']
value_holder = Task.objects.filter(taskID=var2).values_list('taskIdentifier')
.
.
.
.
.
response_data = json.dumps(jsonString)
return HttpResponse(response_data, content_type='application/json')
else:
pass
This is how my items look
This is how they look on double click:
When I delete first item, I get no error. When I do the same thing for the second item (without refreshing the page), it also gets deleted, but I get the following error on frontend:
I go back to server side and check whats going on, I see that on click onto delete button of second item, the view function is called twice (function prints "called" twice.) and naturally, it creates problem for the rest of the code which I didn't include here, since I think that is not the problem (the input provided by form should be added into a list, and then that list is being worked. Since function is called twice, it creates an empty list and function gives an error).
Moreover, when I refresh the page and delete 3 items, it creates that error twice (first call works fine, second and third creates error, meaning, django view function is called 2 times and 3 times respectively)
I think you get the idea.
So somehow, AJAX calls my django view function n times where n is the item number I attempt to delete, even tho I click on different items' delete button...
In the past, I didn't have these event listeners and functions. I had my AJAX form without being in a function and it worked perfectly. Now that I want it to work for each item separately, it gives this error.
What I tried so far:
I checked if the delete_function() function is called twice when I click on second item's delete button. The answer is NO. Everything you see in JS code above is called only once. But somehow AJAX remembers the previous attempts and calls the django view function for those attempts too.
I'd like to underline that the view function works fine. If I tried to delete 5 items, all 5 items are deleted regardless of the function creating an error or not. But since function is called multiple times unnecessarily, it slows my code dramatically.
Short version of my question is, how can I avoid AJAX to submit the form for previous attempts.
i use an jquery-Plugin: https://code.google.com/archive/p/jquery-in-place-editor/
. In the following section I use "JEIP" instead of the full name.
I try to bind JEIP not to an ID but to many objects by css class.
<div class="jeip" id='key1' data-type='elephant'>Text 1</div>
<div class="jeip" id='key2' data-type='mouse'>Text 2</div>
Now i want to pass the data-type element dynamically, too. I figured the "params" option out to pass additional data. But it seemst not to be dynamical.
To initialize JEIP I use:
$(".editInPlace").editInPlace({
url: "http://submitUrl/",
params: "datatype="+$(this).data('type'),
callback: function(){
console.log( $(this).data('type') );
},
}
But the params are wrong. I only get undifiend in the Server scripts which receives the submit action. When I use the callback function I am able to get an console output with the right data. How to pass data-elements to the Server?
Thanks for help.
Assuming all elements are in place at the time of execution of the script (i.e. they are not being dynamically added at some later point), you can simply loop the elements and call the editInPlace plug-in function with the appropriate values:
$('.editInPlace').each(function(i, el){
var $el = $(el); // cache the jQuery object corresponding to the current element
var dataType = $el.data('type');
// call the editInPlace plugin directly on the element
$el.editInPlace({
url : 'http://submitUrl/',
params : 'datatype=' + dataType,
callback : function(){
console.log(dataType);
}
});
});
I'm working with JQuery and ajax.
SCENARIO:
The scenario is the following.
I have a table with different features and each row has it's own button to call "show data " function. With the first call I check some microservices that manipulated the origin data. If data is available ,I show a button for every manipulated data to show in a chart. Every Button gets a listener created in de success method of an ajax call. So there can be three scenarios:
First: show data is called the first time. So there is no
Eventlistener created yet. In that case I create I new one for each
button.
Second: Imagine I clicked a button to show the data in a chart. After
that, the chart gets closed. Now I want to show the same data again.
So my Eventlistener should stay the same and there should not be
another one added.
Third: I click another feature in the table which might have data the
is manipulated differently or will be shown in another chart (e.g. pie
chart insted of flow chart.) So the scenario is pretty much like in
case one but now there is an old Listener to delete.
As a summary: I have to save the Eventlistener Object persistend when it gets createt because when case 3 turns up, I want to call removeEventlistener but I get an error that this object is not defined:
I'm a total noob in js.
This scenario results in the problem, that the eventarguments are not updated and you can see that the data output of listeners pops up for a second and gets overlayed by newer.
And when you do a few attemps, it ends in chaos where nothing fits. By this I mean the wrong data is shown in a wrong chart (one of an older event.).
So I wanted to delete the old listener and recreate it.
Is this a possible solution or is there a better way to do it?
The whole funtion looks like this:
function showData(id,category,feature,date,caller,already_called){
document.getElementById("originButtonDiv").style.visibility='visible';
document.getElementById("squareButtonDiv").style.visibility='hidden';
try{
//show data again -> maintain listener
if(old_already_called == 0 && already_called == 1){
old_already_called = already_called;
}
//New feature choosen -> Delete old listener and create new one
if(old_already_called == 1 && already_called == 0){
$.ajax({
type:'GET',
url:"${path}/user/...
dataType:'text',
async: false,
success:function genTable(data){
var originDataButton = document.getElementById("originDataButton");
//originDataButton.removeEventListener("click",_listener,true);
originDataButton.addEventListener("click", function _listener(){
originDataButtonClicked(id,category,feature,date);
}, true);
if(data.localeCompare("true")==1){
document.getElementById("squareButtonDiv").style.visibility='visible';
var squaredDataButton = document.getElementById("squaredDataButton");
//squaredDataButton.removeEventListener("new_click",_squared_listener,true);
squaredDataButton.addEventListener("click",function _squared_listener(){
squaredDataButtonClicked(id,category,feature,date);
}, true);
}
}
});
old_already_called = 0;
}
}
catch{
//first call --> create new Eventlistener
$.ajax({
type:'GET',
url:"${path}/user/...
dataType:'text',
async: false,
success:function genTable(data){
var originDataButton = document.getElementById("originDataButton");
originlistener = originDataButton.addEventListener("click", function _listener(){
originDataButtonClicked(id,category,feature,date);
}, true);
if(data.localeCompare("true")==1){
document.getElementById("squareButtonDiv").style.visibility='visible';
var squaredDataButton = document.getElementById("squaredDataButton");
squaredDataButton.addEventListener("click",function _squared_listener(){
squaredDataButtonClicked(id,category,feature,date);
}, true);
}
}
});
old_already_called = 1;
}
}
Update:
I'm pretty sure now that the problem is the usage of ajax. I defined a logic tree for my use case because I have to detect whether an Eventlistener should be created, persist unchanged or deleted and recreated. I guess I can differentiate these circumstances in my code but the problem is, that I define the listener in the ajax success method. Between two calls the listener is undefined. So is there a possibility to save a listener object peristent on the client between to ajax calls so that I can delete it within future calls? I guess this would be the solution for my problem.
I have a function that queries a database for info, when a button is clicked. This info gets written to innerHTML of a label. When this function returns, I read the innerHTML of this label. Problem is, it always returns the old value, not the new value that was pulled from the database. The label on the scree is displaying the correct value, though. When I click the button again, the value that I was expecting on the previous click, is now given. Seems like a timing issue but can't seem to figure it out.
example:
SQL Data - cost = 10
I expect to see 10 alerted to me when I click the button. I get a blank alerted to me, even though 10 is now in the label. When I click the button again, 10 is alerted, but 20 is now in the label.
function getInfo() {
var ctlMonthly = document.getElementById("cellMonthlyCost")
getSQLData(ctlMonthly);
alert(ctlMonthly.innerHTML);
}
function getSQLData(ctlCell){
...
var my_ctlCell = document.getElementById(ctlCell);
$.each(objData.items, function() {
my_ctlCell.innerHTML = this.Param1
});
...
}
Thanks.
you need to add the alert after the data is received from the database. I am assuming that you're sending an ajax request to fetch data. You will be able to get the new value in the callback of you're ajax request function.
Currently what is happening in your code is that
1. getSQLData(ctlMonthly);
// This sends a request to the data base to fetch data
2. alert(ctlMonthly.innerHTML);
// This shows the current value in an alert
3. data is received and shown in the label
This process happens so fast that you don't notice the difference between step 2 and 3.
Is this what you want?
I used a callback function
function getInfo() {
var ctlMonthly = document.getElementById("cellMonthlyCost")
getSQLData(ctlMonthly,alertInfo);
}
function alertInfo(info){
alert(info);
}
function getSQLDate(ctlCell,callbackFn){
...
var my_ctlCell = document.getElementById(ctlCell);
$.each(objData.items, function() {
my_ctlCell.innerHTML = this.Param1;
callbackFn(this.Param1);
});
...
}
to piggyback on Himanshu's answer, your request to your server is async. Meaning javascript will execute the GET request and continue on with the script, when the requests comes back from the server it will run whatever callback you give it. ( i.e. update label tag )
assuming getSQLData is a ajax call or something promised based, something like:
function getSQLData(ctlCell){
return $.get('/sql/data').done(function () {
var my_ctlCell = document.getElementById(ctlCell);
$.each(objData.items, function() {
my_ctlCell.innerHTML = this.Param1
});
});
}
you can change your code to:
function getInfo() {
var ctlMonthly = document.getElementById("cellMonthlyCost")
getSQLData(ctlMonthly)
.done(function () {
alert(ctlMonthly.innerHTML);
});
}
Basically the difference is your telling javascript to alert the innerHTML after the requests comes back from the server.
The more correct answer would be to alert the data straight from the response instead of reading from the DOM.
I'm unsure of the best practice for modifying the DOM based on an ajax response. I'll try to let the code do the talking because it's hard to explain.
// page has multiple checkboxes
$("input[type='checkbox']").live('click', function {
var cb = $(this); // for the sake of discussion i need this variable to be in scope
$("form").ajaxSubmit({ dataType: "script" });
}
The server sends a response back, and the js gets eval'd and that means "cb" is out of scope.
What I've done so far is create a couple of helper functions:
var target = undefined;
function setTarget(val) {
target = val;
}
function getTarget() {
return target;
}
And that turns the first snippet of code into this:
// page has multiple checkboxes
$("input[type='checkbox']").live('click', function {
setTarget($(this));
$("form").ajaxSubmit({ dataType: "script" });
}
Then on the server's response I call getTarget where I need to. This seems hackish... Any suggestions?
It's unclear what you're actually trying to do, but I feel like you want to be looking at the success parameter for that AJAX call. The success callback function should execute in parent scope and do what you're looking for.
See 'success' on this page in the jQuery docs.
So what you are trying to do is get the form to submit the content via ajax whenever the user checks/unchecks a checkbox? And because there are several checkboxes, you need to find out which one triggered the submit, so you can change its value to whatever is stored on the server?
If you submit the entire form everytime, why don't you reply with all the checkboxes values, and then change each and every one of them? If not, get the server to reply with the id and the value of the checkbox, then use jquery to find the checkbox with that ID and then change it's value.
How about:
jQuery(function($) {
// give it scope here so that the callback can modify it
var cb,
cbs = $('input[type="checkbox"]');
cbs.live('click', function {
// taking away var uses the most recent scope
cb = $(this);
// disable checkboxes until response comes back so other ones can't be made
cbs.attr('disabled', 'true'); // 'true' (html5) or 'disabled' (xhtml)
// unless you are using 'script' for something else, it's best to use
// a callback instead
$('form').ajaxSubmit({
success : function(response) {
// now you can modify cb here
cb.remove(); // or whatever you want
// and re-enable the checkboxes
cbs.removeAttr('disabled');
}
});
}
});