I created a page which gets filled by a php databasequery (all rows are being read from the MySQL-table and written to the table in HTML). All 10 seconds the same PHP-script gets requested by jQuery AJAX and should refresh the current table content. The return-value of this function will then be used to change the table HTML-value.
There are some buttons in the table. When they're clicked, they toggle from on to off (or vice versa) and another PHP-file gets called with AJAX, which then controls 433MHz wireless sockets via shell commands. Purpose of these 10-seconds ajax-refresh is to synchronize the button with the actual state of the electrical socket (which is saved in the MySQL-database).
$(document).ready(function(){
$(".toggle").click(function() {
if($(this).hasClass("ein")) {
$(this).removeClass("ein");
$(this).html("aus");
$.post("various/executeCode.php", {transmitted:true, id:$(this).attr('id'), toggle:'0'}, function(result) {
});
} else {
$(this).addClass("ein");
$(this).html("ein");
$.post("various/executeCode.php", {transmitted:true, id:$(this).attr('id'), toggle:'1'}, function(result) {
});
}
});
});
window.setInterval("reloadPage()", 5000);
function reloadPage()
{
$.get('various/reloadPage.php', function(data) {
$("#content").html(data);
});
}
$stmt = $dbh->query("SELECT * FROM `funksteckdosen`");
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($row as $r)
{
echo "<tr>";
echo " <td>" . $r['name'] . "</td>";
echo " <td><button id='" . $r['id'] . "' class='toggle" . ($r['toggle'] == 0 ? "" : " ein") . "'>"
. ($r['toggle'] == 0 ? "aus" : " ein") . "</button></td>";
echo "</tr>";
}
Now I have the following problem: As soon as the page gets refreshed by AJAX the first time, the buttons stop working. Javascript doesn't execute the click()-function anymore. Why is that?
Problem 2:
The content of the table gets deleted and replaced by the new one. Am I somehow possible to fade new lines (or the button background-color) in, instead of just showing them? That would be the final touch.
I hope you understood my explanations.
The click handlers don't work anymore because the new buttons never had the handlers attached to them. When you attach a handler like this:
$(".toggle").click(function() {
What jQuery does is find all of the currently existing .toggle elements and, for each one, add that function as a handler. Since the new ones are added later via an AJAX call, they're not included in that set and, thus, never have that function attached to them.
The way jQuery address this is with the .on() function. The structure of using is it very similar:
$('body').on('.toggle', 'click', function() {
The difference here is the element which is actually getting the click event bound to the function. With this, the click event is actually being added to the body tag, which isn't changing from the AJAX call. Any unchanging common parent for the dynamic elements will work, 'body' and document are usually used as defaults since they're pretty top-level.
When any child element raises a click event, that event continues up all of the parent elements. So it eventually reaches a common parent, such as 'body'. The .on() function then also has a second selector as its first argument. That selector filters the originating elements of the click event before calling the function.
Benefits of using this approach include:
There's only one event handler function attached to a single common parent, instead of many attached to many elements, which can be a performance improvement on large or complex pages.
Child elements added to the common parent element later in the page's lifespan are still handled, since they will still send their click events to the parent regardless of when they were added. (This is the immediate benefit in your situation.)
As for fading in the content, if I understand the effect you're looking to achieve, you can try something like fading out what's already there, removing it, adding the new content, and then fading it in. Maybe something like this:
$.get('various/reloadPage.php', function(data) {
$('#content').fadeOut(400, function() {
$("#content").html(data);
$('#content').fadeIn();
});
});
There might be newer structures to accomplish this same thing with the relatively newer "promises" model, but essentially what this does is fade the content out and then include a call-back function to call when it's finished fading out. That call-back function replaces the HTML and then fades it back in. Depending on the structure of your HTML you might need to fade out/in a parent element instead of the one I'm targeting, but hopefully you get the idea here and can tweak it until it looks right.
Problem 1: The click event handler is bound to the initial toggle class elements but dynamically created events are not bound.
Try using live() or on() to bind dynamically created elements. See: Event binding on dynamically created elements?
Problem 2: #content is replaced when using html()
Try using append() to add data into an existing element. Using html() will replace the contents of the element.
I have chained a hide() and a fadeIn() to animate the append.
$('#content').append(data).hide().fadeIn(1000);
Related
My php script creates a table with a list of courses and buttons in each row. Each set of buttons should obviously do the same thing, but for that particular row. Each row contains a button with class='add_button', class='wait_button' and class='detail_button'. The value for each button is the courseID of that particular row. This script is sent back to the main page via ajax, and inserted in the middle of the page.
When I click on one of these buttons, I would like to trigger a basic jquery event to test that each button is properly set. However, my current code does not seem to be working. I saw this in a similar post, tried the solution, and still got nothing. Therefore, I have left my initial script. Thank you for any and all suggestions.
courseDb.php:
while($row = mysqli_fetch_array($findCourses)){
echo "<tr>".
"<td><h3>" . $row['courseDept']. $row['courseNumber']. "-".$row['courseSection']."</h3>".
"<p>" . $row['courseName']."</p>".
"<td><p>Course Capacity: " . $row['courseSize']."/". $row['courseCurrent']."</p>".
"<p>Waitlist Capacity: " . $row['waitSize']."/". $row['waitCurrent']."</p></td>".
"<td><button class='add_button' value='".$row['courseID']."'>Add to Schedule</button></td>".
"<td><button class='wait_button' value='".$row['courseID']."'>Add to Waitlist</button></td>".
"<td><button href='#coursesDetailStud' class='detail_button' value=".$row['courseID'].">View detail</button></td>".
"</tr>";
}
courses.php:
$(".add_button").click(function(){
var clicked = $(this);
alert(clicked.val());
});
This script is sent back to the main page via ajax, and inserted in the middle of the page.
It seems to me that these rows (and the buttons) are returned by AJAX and is created after the page has been loaded.
As usual, any script placed directly in PHP or HTML files are executed on page load. If you simply use click method, it only bind the events on the elements already existing in the page, and have no effect if the HTML elements are added later by AJAX and DOM manuipulation.
You will need on with delegation, to make your event be bound even for elements loaded afterwards. (Assuming the parent table exists in the HTML/PHP)
$('table').on('click', '.add_button', function(){
//your code
});
When a user selects a word in a text on my website (PHP), and then right clicks, i want a jQuery context menu to come up, this can be done by using one of the already existing jQuery context menu plugins.
But besides the options like copy / paste / cut, etc. I also want something to be done with the selected word using PHP. Which, i think, is a little harder.
For example using this script:
$selection = //the selected word or text
$target = //fetch from MYSQL database
$output = array();
while ($row = //fetch $target) {
If ($selection == $row->input) { array_push($output,$row->output); }
}
echo '//menu '.print_r($output).''; // of course not print_r! Just for the example's sake.
Databse example:
(Sorry for the oversized image)
Ok so selecting the word 'lazy' in the example text, and then right clicking, the jQuery box should pop up showing the results from the database extracted by PHP.
Example:
Ok, so i know you can't just combine javascript with PHP and it can only be parsed, but i thought loading an iframe withing the menu, which does the database extraction would do the job by using javascript to set the iframe src containing the selected word in the url.
However, iFrames are not really a nice way to solve this.
The question: How can i do this effectively? Execute this script on right-click and show the database-related content in the menu?
I would need to know the plugin you're using to give you some code examples but, general, I would go about this like this:
There has to be a click handler on the items in the jQuery context menu. Use it to submit an AJAX request to the server when the "selection" term is clicked.
Make sure to give the user some feedback (a loader or spinner)
Put the results into an array server-side.
JSON encode the array and send it as the response (e.g. echo json_encode($output)
JSON.parse(response) on client-side and you now have a JS object with the results
Put those results in the context menu (again, how depends on the plugin you're using)
AJAX is a great way to do what you want.
Here is a simple AJAX example. Note that in the 2nd .PHP file, that is where you put your database lookup etc.
Whatever you echo from the 2nd script is received by the calling javascript (first script again) and can be inserted into your context menu on-the-fly. Here is another example with a very detailed, step-by-step explanation of the process at the bottom of the answer.
I think you have to use Ajax to get JSON from a PHP file, which you would process on the actual page.
I you create a PHP file called test.php, with the following in it:
<?php
echo json_encode(array('time' => time(), 'hour', date('H')));
?>
Then the Javascript:
<script>
$('#curr_menu_entry').click(function() {
$.getJSON('test.php', function(data) {
$.each(data, function(key, val) {
$('#curr_menu_entry').append('<li id="' + key + '">' + val + '</li>');
});
});
});
</script>
Would that work?
I have some tabs which have been created using Javascript and Mootools, my client wants the 'next button' at the bottom of the page to be disabled, until the tabs have been read(clicked). The page is dynamic (created with PHP and MySQL) and there could be two tabs or three, depending on the set-up. I am struggling today to think of the best solution.
Any help more than welcome...
view example working on jsfiddle:
http://www.jsfiddle.net/dimitar/THMxa/
it can work with some classes and logic added to tab clicks and next click.
// fade out next button and set it to disabled, then define the event to check state.
document.id("next").store("disabled", true).set("opacity", .5).addEvent("click", function() {
if (this.retrieve("disabled")) {
alert("please view all tabs first!");
// console.log(document.getElement("div.notclicked"));
return;
}
// insert code here that goes next.
alert("allowed to run");
});
// this is pseudo - you probably already have a function that assigns events on your tabs to change
document.getElements("div.tabs").each(function(tab) {
// first tab may already be open so no click needed
if (!tab.hasClass("clicked"))
tab.addClass("notclicked");
// add click event
tab.addEvent("click", function() {
if (document.getElement("div.notclicked"))
this.addClass("clicked").removeClass("notclicked");
// check again if that was the last one, if so, enable next button...
if (!document.getElement("div.notclicked"))
document.id("next").store("disabled", false).fade("in"); // or whatever
// regular code for tabs here...
});
});
Since the number of tabs is dynamic, I'd probably use an attribute on the tab's header/label/whatever indicating that it has not been read, and then when the tab's header/label/whatever is clicked, I'd change that attribute to indicate that it had been read and then trigger a function that may enable the button depending on whether all the other tabs had been read.
I'm not a MooTools person, but IIRC it's a fork of Prototype (although it's been a while and they've probably diverged). The click handler could look something like this in Prototype:
$$('.tabClass').invoke('observe', 'click', function(event) {
this.setAttribute("data-read", "Y");
if ($$('.tabClass[data-read=N]').length == 0) {
$('buttonId').disabled = false;
}
});
...where $$ is Prototype's "search the DOM for elements matching this CSS selector" function and $ is Prototype's "get me the element with this ID". The invoke there just calls observe for each matching element (you could do this with event delegation instead), and I think observe is fairly self-evident. :-)
The code above makes these assumptions:
Your tab header or whatever has the class "tabClass".
You've created the tables with the attribute "data-read" set to "N" (e.g., <div class="tabClass" data=read="N"> or similar). The data- prefix is to be HTML5-friendly. (Yes, we're finally allowed to put any old arbitrary attribute name on elements if we want to! We just have to prefix them with data-.)
The button has an ID, "buttonId"
The button starts off disabled
Edit Or use a marker class if you prefer, all tabs start out with class="tabClass unread":
$$('.tabClass').invoke('observe', 'click', function(event) {
this.removeClassName("unread");
if ($$('.tabClass.unread').length == 0) {
$('buttonId').disabled = false;
}
});
Double-check that MooTools supports the ".tabClass.unread" selector (it really should, I'm just saying, check). Some implementations may work more quickly with class-based selectors than attribute-based ones.
You should disable the button where you send the request to load the content,
and enable it from the callback that handles the returned content.
I would add a class to the tab when it's clicked - like "clicked". Also, check if the 'click' is the last tab, so..
$('myElement').set('class', 'clicked');
then get all of the tab elements (a elements i assume) and count them.
Then get all of the tab elements with class "clicked"
If they match, they were all 'clicked'.
Greetings Guru's, This is a little hard to explain, but I'll give it a shot.
I have a quick question regarding to the .live() function in JQuery. I'm going to simplify the example here. I have a page "index.php" that has a container "#display_files_container" which is populated with anchor links that are generated dynamically by a different page "process.php". The links are loaded into that same <div> when those links are selected based on the attributes of that link. See Examples:
INDEX.PHP
<html>
<head><title>index.php</title>
<!-- this function below loads process.php and passes it the dirid variable via post. I then use this post variable inside of process.php to pull other links from the database -->
<script language="text/javascript">
$('.directory').live("click", function() {
$('#display_files_container').load('plugins/project_files/process.php', {dirid: $(this).attr('dirid')});
});
</script>
</head>
<?php
/*This code initial populates the link array so we have the first links populated before the users clicks for the first time*/
some code to fetch the $current_directory_list array from the database initially....
>?
<body>
<div id='display_files_container'>
<?php
/*Cycle through the array and echo out all the links which have been pulled from DB*/
for($i=0;$i<$current_directory_count;$i++) {
echo "<a href='#' class='directory' dirid='".$current_directory_list[$i]['id']." '>".$current_directory_list[$i]['directory_name'].
"</a> ";
}
?>
</div>
</body>
</html>
PROCESS.PHP
this file includes code to populate the $current_directory_list[] array from the database based on the post variable "$_POST['dirid']" that was sent from the .click() method in index.php. It then echo's the results out and we display them in the #display_files_container container. When you click on those links the process repeats.
This works..... you can click though the directory tree and it loads the new links every time. However, it seems to want to .load() the process.php file many times over for one click. The number of times process.php is loaded seems to increase the more the links are clicked. So for example you can click on a link and firebug reports that process.php was loaded 23 times..... Eventually I would imagine I would record a stackoverflow. Please let me know if you have any ideas. Are there any ways that I can assure that .live() loads the process.php file only once?
Thanks,
-cs
What happens, is that everytime you click a link, you bind new click event handler to every link. This is possible because there can be multiple handlers for the particular event. You must return false in your handler to stop the event bubbling.
Update: I'm not sure why the handler gets bound multiple times, but my guess is that it has something to do with the special nature of 'live event' implementation. See chapter Event Delegation from the docs:
The handler passed to .live() is never bound to an element; instead, .live() binds a special handler to the root of the DOM tree.
Another solution is to use bind() or click() instead of live() and call it explicitly after the ajax has been loaded:
function bind_link_handler() {
$('.directory').click(function() {
$('#display_files_container').load('...', bind_link_handler);
})
}
Just so everyone is in the loop my new line of .live() code looks like this:
$('.directory').live("click", function() {
$('#display_files_container').load('plugins/project_files/process.php', {dirid: $(this).attr('dirid')});
return false;
});
I use this to toggle my div elements, and hide all them when the DOM is ready...
$('div[class*="showhide"]').hide();
$('input:image').click( function() {
var nr = $(this).attr('id').substr(7,2);
$('div.showhide' + nr).toggle(400);
});
I have dynamically created div elements with class showhide0;showhide1;showhide2...etc...
Inside the DIV tags I have search boxes.
First when page is loaded all DIV tags hide.
I toggle one of them to show.
Start a search, so the page is reloaded with the result of the query.
Of course all DIV is hide again, because the page is reloaded. Unfortunately...
Is it possible to not hide again after I searched for something? It would be nice when I open the page, all the divs are hidden, but after then just when I toggle it...
If you need a specific element or elements to stay visible upon a page reload, then you're going to need to do something to maintain state across requests, and then modify your jQuery to utilize that state information when initializing the visible state of the elements.
This can be done in numerous ways which include but are not necessarily limited to
Include it in the query string
Include it in the URL hash
Use a cookie
Well, yeah, you just don't run the initial hide() if there's a search request. I'd just exclude that line from the output if, on the PHP level, you know you're executing a search.
We do something similar to this where I work.
We opted instead of have the class name just be hide for all elements and instead have the ids named.
So, we'd have it something like:
<div id="hide1" class="hide"> </div>
along with this CSS to hide all those divs by default
.hide {
display: none;
}
Finally, we use something like this to show them:
$('input:image').click( function() {
var nr = $(this).attr('id').substr(7,2);
$('#hide' + nr).toggle(400);
});
}
This works because of CSS precedence rules. The toggle()/hide()/show() method overrides the hide class's style.
As for the unhiding part, if you pass the ID to unhide to your script, you can parse it and unhide the appropriate div.
You can read and process the query string from window.location.search. Unfortunately, you then have to manually parse it or use a plugin, such as jQuery Query String Object or jQuery URL Utils.
var id = $.query.get('unhide_id'); // This is using Query String Object
$('#' + id).show(400);