I've been building an application with PHP/MySQL and JavaScript with Prototype/Scriptaculous.
A page has a search contacts field, with a default set of data in an HTML table. A user types in some characters, and the table get updated.
What's actually happening is the table is getting replaced with a new table and new data.
I've got a JavaScript that works against that table, which is loaded in the standard fashion via script tags at the bottom of the page.
Problem is, it only works on the default data (the part that's loaded with the page), when the search updates the table data, the script stops working. The search still will work since that was originally loaded with the page but it seems my script is unaware of page updates or new data.
How can I get this to work? Do I have to include the script with every Ajax call?
Thanks
Rich
Posting the relevant code would help, but you have most likely attached an event listener to an element that is replaced by the AJAX call.
If that is the case, you will need to recreate and reattach the event handler to the new element, even if that new element is exactly equivalent to the element it is replacing.
OK, I'll post a bit of code here.
But yes an event listener is attached to an element.
Here's a bit of the JavaScript class I was building which looks for events from a search field, collects data from that field and other form elements and sets them up in this.params.
After the data is returned to the AJAX object, it's updated to the page, which is identical to the original code (different rows).
var Compass_Search = Class.create({ ...
search: function() {
$('search_form').observe('change', this.get_data.bind(this));
},
get_data: function(e) {
var ele = e.target;
var filters = $$('.search_option');
if($(ele).tagName == 'INPUT') {
if($(ele).readAttribute('type') == 'checkbox') {
this.watch_filters(filters);
}
}
if(this.default_text == $('search_box').value) {
this.set_text_value('null');
} else {
this.set_text_value($('search_box').value);
}
new Ajax.Request(this.url, {
method: 'post',
parameters: this.params,
onComplete: function(r) {
result_text = r.responseText;
$('main').update(result_text);
}
});
},
...});
Related
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 simple JS file that uses Jquery to apply rules to the loaded page.
I starts with the traditional $(document).ready(function(){
Nevertheless, when I load more posts (load more button) or submit a new post, those rules don't apply. I think I understand why...though it is not clear.
Is there a way to apply the same rules to each new added post? Is the only way defining events directly on the html code like e.g onclick....?
I may be a very simple question. I'll appreciate any answers :)
Thanks
JS Code
$(document).ready(function(){
(...)
$('button#cancel').on('click',function () {
$(this).parents('.footer').hide();
$(this).parents('.footer').siblings('.small-textarea-main-feed').removeClass('set-large');
$(this).parents('.footer').siblings('.small-textarea-main-feed').val('');
});
(...)
}); closes all
I am using the following code in load_questions.js to load a new post:
$('form.ajax').submit(function() {
//
var that = $(this),
url = that.attr('action'),
type = that.attr('method'),
data = {};
that.find('[name]').each(function(index, value) {
var that = $(this),
name = that.attr('name'),
value = that.val();
data[name] = value;
});
//event.preventDefault();
$.ajax({
url: url,
type: type,
data: data,
cache: false, // it will force requested pages not to be cached by the browse
success: function(html){
console.log(html);
$("ol#list-feed").prepend(html);
$("ol#list-feed li:first").slideDown(600);
document.getElementById('set-width1').value='';
document.getElementById('tags').value='';
if ($("ol#list-feed > li").size() <= 3) {
$('#loadmorebutton').hide();
} else {
$("ol#list-feed > li:last").remove();
$('#loadmorebutton').show();
}
}
});
//event.preventDefault();
return false;
});
I want that this type of rules apply to new posts I submit.
The DOMDocumentReady event fires exactly once on the page, when the entire HTML document has been loaded and parsed, so any DOM element you should be able to expect be on the page, will be.
Any DOM elements you add to the page from this point on, need to be decorated again. This can be as simple as calling the DOMDocumentReady handler again, in which case you'd want to make it a named function, and pass that named function to $(document).ready(...). Something like this:
var onReadyHandler = function() { };
$(document).ready(onReadyHandler);
$.ajax({
success: function(html) {
$("ol#list-feed").prepend(html);
onReadyHandler();
}
});
Now, it's likely that a better way of handling this (it's really unclear to me what precisely you're trying to accomplish, but that's not a real problem), is to not bind anything to your new posts at all. If you're concerned about events, bind the events to the container you know will be on the page, using 'event delegation' (jQuery link: http://api.jquery.com/delegate/). This pattern takes advantage of the fact that events 'bubble' in the DOM, meaning you can listen higher in the DOM then the elements you actually want to respond to, and just check that the click event happened on the event you do care about ($.delegate does this check automatically). The end result? You bind far fewer event handlers, since you're not decorating each post individually.
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.