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.
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 have a modal window that has a lot of new dynamic elements (inputs, buttons, etc.). I want to see if a certain element(or in this case, and input) gets created and if it does, then change its value.
The scenario is that if I make an ajax request for populating data, and as the user browses the modal window I can reuse some of that data. When the input field I'm looking for gets created, I can just put the value of the ajax call I made previously.
I have tried: $("#myinput_id").val(sellerData['id']);
obviously the above wont work because the element doesn't exists, yet. I'm also trying to avoid new ajax calls for the same data :/
Any thoughts?
$( "#add").bind('click', function() {
$.ajax({
url: '/seller/get',
type: 'POST',
success: function(response) {
sellerData = jQuery.parseJSON(response);
//other code here
//this doesn't work
$("#myinput_id").val(sellerData['id']);
}
});
});
Then the above gets triggers. The input field doesn't exist yet. How can I make it "look for it" if in the future the input field gets created?
Try using .length http://api.jquery.com/length/
if($("#myinput_id").length) //There is at least one element selected
//Do something
a bit confusing question you are saying u want to populate the data and your are using POST
Im running into a problem where i have an ajax driven page that is drawn when a user selects something from a simple drop down:
<select id = "selectdepartment">
<option id = "default">Select an option...</option>
....
</select>
and the remainder of the page is drawn using the jquery .change() :
$('#selectdepartment').change(function(){
});
Which then runs some ajax to php script. everything works great, the problem is when i submit a form that was drawn with ajax (using $_SERVER['PHP_SELF'];), the data gets submited, the page reloads, and the page is cleared but the select box is still left where it was. The user has to move to a different option then back to the one the selected originally to re-fire the .change(). that sucks.
I could fix this by passing a php variable in all of my forms, then checking to see the variable set on every page load and if it is draw the page parts then, but this would lead to pretty messy code and it's less than desirable.
There has to be a way to do this with the jquery library, though my knowledge of the javascript language in general is not what i would like it to be. If anyone has any helpful hints please share, dont do it for me though, i wont learn that way :)
edit: code with .trigger
$('#selectdepartment').change(function(){
var department = $('#selectdepartment').val();
var day = $('#data').data('day');
var month = $('#data').data('month');
var year = $('#data').data('year');
//alert (department);
if(department === "Select an option..."){
$('.hiddenuntildepartmentisselected').css({"display":"none"});
}
else{
$('.hiddenuntildepartmentisselected').css({"display":"block"});
}
showpoints(department);
drawpointstable(department, day, month, year);
displaytheuseresforselecteddepartment(department, '');
$('#sendthedepartment').val(''+department+'');
$('#hiddendepartmentidforaddinganewpoint').val(''+department+'');
}).trigger('change');//end run functions
You can use the .trigger() function to immediately trigger the change event handler when the page has loaded:
$('#selectdepartment').change(function() {
// code here
}).trigger('change');
Or if you need to call it elsewhere via JavaScript/jQuery:
$('#selectdepartment').trigger('change'); // or just .change() as a shorthand
Updated
Your button for the form could make use of the onClick attribute, which would invoke a method to parse the form fields and post the data to your php script via .ajax().
In the success event method you then check any flags you need to and modify the element as you desire if needed.
Basic example:
Inside of .ajax():
...
url: 'xxx.xxx.xxx',
async: true,
type: 'POST',
dataType: 'html',
data: JSON.stringify( form_fields ),
beforeSend: function()
{
// Pre send stuff, like starting a loading gif
},
success: function( data, textStatus, xhr )
{
// Be sure you load the page with the content first
$( '#containing-div' ).html( data );
// Do your check here, and modify your element if needed here
if( flagtocheck === 'xxx' )
{
// Modify the element in question...
}
// I call a custom method termed `.ctrls()` here that makes any
// adjustments to the DOM once its loaded/updated.
},
error: function( xhr, textStatus, errorThrown )
{
}
Of course, you'll want to set flagtocheck appropriately in your case.
Hope that helps!
Note regarding edit
This post was edited to be a little more descriptive and more easily understood. Since the person asking the question is already using the .ajax() method, the success event method is the ideal place for doing what the person asking the question is requesting. It is 1 less method invocation to directly modify the element there than using it to call .trigger() or .change() which then also directly modifies the element.
Problem:
I've got 2 drop downs, both populated by information from a database and dependent on some initial information (a json array created in php). The second drop down is also dependent on what was selected in the first dropdown. Once the second dropdown has been selected, the users selections are saved in another database table. If the user leaves and then comes back, I want to be able to reset the drop downs to what they previously selected (but still let them change their selections).
Context:
I have some code that looks like the following:
function eventHandler2(event) {
$.ajax({
url: "someotherurl.php",
data: event.data["context"],
success: function(data) {
// Do some stuff
}
});
}
function eventHandler1(event) {
event.data["context"][$(event.target).id()] = $(event.target).val();
$.ajax({
url: "someurl.php",
data: event.data["context"],
success: function(data) {
$("#element").append(build_input("input2", data));
$("#element input2").change({"context": event.data["context"]}, eventHandler2);
}
});
}
$(document).ready(function() {
var context = // php generated json array.
$("#element").append(build_input("input1", context));
$("#element input1").change({"context": context}, eventHandler1);
});
context includes some data that has to be initialized outside of the event handler and is added to durring events, and build_input just returns an html string of a form input element built with options determined by data or someData. At times the entire html element that includes eventHandler1 (and eventHandler2) will be removed and reinitialized.
My issue is that I want to initialize the two form inputs (built using build_input) with some default values pulled from a database, but once those values have been set I don't want any reinitialization or event handling to use those initial values (which makes adding them to the context object difficult since that object will be used when binding the event handlers).
I would like to set the value for the inputs and then call a change event to simulate a user selecting those values, but because the input elements are built using ajax data, those change events are being getting called before the ajax request have returned and built the input elements.
I could solve this with timeouts, but because the the javascript might run slower on different machines and the ajax calls could take longer than normal, I don't plan on doing it that way. Still, ideally I would like something like this:
$("#element .input1 option[value='" + initial_value + "']").attr('selected', true);
$("#element .input1").change();
to be called when the page loads but only after the elements have been built and bound.
Question:
Is there any way to trigger change events (simulating the user selecting options) only when the page is first loaded and only after the ajax request to build the html input elements have returned?
Is there any way to trigger change events (simulating the user selecting options) only when the
page is first loaded
and only
after the ajax request
to build the html input elements have returned?
These are two separate events. If you need to ensure both events have ocurred use <body onload="loadedBody=true"> and take advantage of the success: attribute of the $.ajax function like this:
function eventHandler1(event) {
event.data["context"][$(event.target).id()] = $(event.target).val();
$.ajax({
url: "someurl.php",
data: event.data["context"],
success: function(data) {
$("#element").append(build_input("input2", data));
$("#element input2").change({"context": event.data["context"]}, eventHandler2);
ajaxComplete();
}
});
}
var ajaxCompleted;
function ajaxComplete() {
if((loadedBody == true) && (ajaxCompleted == false)) {
$("#element .input1 option[value='" + initial_value + "']").attr('selected', true);
$("#element .input1").change();
} else {
setTimeout('ajaxComplete()', 100);
}
}
Don't worry about the setTimeout. It will rarely be used because the page will likely have loaded before the AJAX result arrives.
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');
}
});
}
});