jQuery fast mouse move mouseleave event triggers before previous event completes - php

If a users mouse goes over a table cell then a dropdown box replaces the html with data loaded via a post call. This works fine if the users mouse move is not too quick, but if it is too fast the html doesn't update so that when the user moves the mouse back in the html is incorrect.
$(".edit_dropdown").bind('mouseenter', function () {
$(this).unbind('mouseenter');
var a = $.trim($(this).html());
var id = $(this).attr('id');
$(this).html("<span id='s-" + id + "'></span>");
$.post('save/dropdown.php', {
id: id,
a: a
}, function (data) {
$("#s-" + id).html(data);
$(".edit_dropdown").bind('mouseleave', function () {
var id = $(this).attr('id');
var a = $("#e-" + id).val();
var dir = $(this).attr('class');
$(this).html(a);
$(this).bind('mouseenter', function () {
$(this).unbind('mouseenter');
var a = $.trim($(this).html());
var id = $(this).attr('id');
$(this).html("<span id='s-" + id + "'></span>");
$.post('save/dropdown.php', {
id: id,
a: a
}, function (data) {
$("#s-" + id).html(data);
});
});
});
});
});
html
<tr>
<td>customer county</td>
<td class="edit_dropdown" id="customer-cust_s_county"><?php echo $row['cust_s_county']; ?></td>
</tr>
The $.post file returns a list of UK counties, if the county name matches the html then that county is returned as the selected option.

The problem occurs because the mouseleave handler is only put in place in response to an asynchronous response to the mouseenter handler.
You should be looking for a simpler overall code structure that doesn't involve detaching and reattaching handlers.
It should be possible to write two handlers that remain permanently attached, as follows :
$(".edit_dropdown").on('mouseenter', function () {
//Perform all mouseenter actions here.
//If necessary, test for different states and branch as required.
}).on('mouseleave', function () {
//Perform all mouseleave actions here.
//If necessary, test for different states and branch as required.
});
Another point: As the list of counties is static, you can serve it once as part of the page's original HTML. You then need to return only the name or id of the county to be selected rather than repeatedly returning the whole list.

Related

Codeigniter 3 application: update MySQL table column and the corresponding view through Ajax

I am working on a Register and Login application with CodeIgniter 3 and Twitter Bootstrap.
I have a "users" MySQL table and a corresponding "users.php" view that renders the "users" table in an HTML format, like the image below illustrates:
The "Actions" column in the Bootstrap table has, on each row, an "Enable" or "Disable" button, depending on the state of he user. The code for this part of the view is:
// Status column
<td>
<?php if ($user->active == 1) {
echo '<span class="text-success">' . 'Enabled' . '</span>';
} else {
echo '<span class="text-danger">' . 'Disabled' . '</span>';
}
?>
</td>
// Enable/Disable buttons
<?php if ($user->active == 1) { ?>
<span class="glyphicon glyphicon-ban-circle"></span> Disable
<?php } else { ?>
<span class="glyphicon glyphicon-ok"></span> Enable
<?php } ?>
I activate/deactivate users without page refresh, via AJAX:
$('.state-change').on('click', function(evt) {
evt.preventDefault();
var id = $(this).data('id');
var role = $(this).data('role');
if (role == "activate") {
var stateUrl = 'users/activate/';
} else {
var stateUrl = 'users/deactivate/';
}
$.ajax({
url: stateUrl + id,
method: 'GET',
dataType: 'php',
success: function(){
console.log(id);
console.log(role);
}
});
});
The problem is that the data regarding the state of the user does not come back to the view and the columns "Status" and "Actions" do not render correctly.
I wish I didn't have to update the view "statically" from the success callback, with jQuery's html() method or something similar.
function(){
console.log(id);
console.log(role);
//change columns html here
}
What shall I do to update the view "dynamically"?
The above answers are adequate - you must use JavaScript given your scenario. It seems the trouble lies in making the leap from dynamic web pages to dynamic HTML.
Read the last line of the summary here:
https://en.wikipedia.org/wiki/Dynamic_HTML
You will need to use javascript to modify your table after you get the data back. Since you're already using jQuery, you have tools to make that pretty simple.
Your problem can be broken into two steps: Identify the right part of the page to update, and then modify the cells of interest.
Identifying the right cells is simplified because the mouse event passed to your function includes a reference to the thing that was clicked.
To make finding the right parts of the table easier, it's good to give each <td> a class:
// Status column
<td class="status-column">
// your php status stuff from above
</td>
// Button column
<td class="activate-column">
// your php button-drawing stuff from above
</td>
Now it will be easy to find what you're looking for to modify.
Here's your ajax call with a few additions to redraw the cells in question:
$('.state-change').on('click', function(evt) {
evt.preventDefault();
var id = $(this).data('id');
var role = $(this).data('role');
if (role == "activate") {
var stateUrl = 'users/activate/';
} else {
var stateUrl = 'users/deactivate/';
}
$.ajax({
url: stateUrl + id,
method: 'GET',
dataType: 'php',
success: function(){
console.log(id);
console.log(role);
// find the row that is the parent of the clicked button - http://api.jquery.com/parent/
var row = evt.target.parent('tr');
// use the class of the table cell to identify it. http://api.jquery.com/find/
var statusCell = row.find('.status-column').first();
// now put in the new status. http://api.jquery.com/html/
if (role == "activate") {
statusCell.html('<span class="text-success">Enabled</span>');
} else {
statusCell.html('<span class="text-danger">Disabled</span>');
}
}
});
});
I'll leave the button column for you to practice with :).
Edit: you can also manipulate the DOM with non-jQuery methods that are perhaps more to your liking. This is what jQuery is doing under the hood anyway.
You can read more about them at MDN.
// build the new DOM node
var newStatusCellContent = document.createElement('span');
newStatusCellContent.setAttribute('class', role == 'activate' ? 'text-enabled' : 'text-danger');
newStatusCellContent.textContent = role == 'activate' ? 'Enabled' : 'Disabled';
// get the parent <td> node from the jQuery object
var statusCell = row.find('.status-column').get(0);
// swap the old contents for the new
var oldChild = statusCell.childNodes[0]
statusCell.replaceNode(newStatusCellContent, oldChild);
Careful study of the documentation at the above link will probably reveal ways to make that more efficient for your particular case. Keep in mind that this is the same thing the jQuery html() method does — or Angular or any other — and that while it keeps you away from HTML, it doesn't really improve your code in this case. I really hate HTML, but it's the tool we're given.
Note that php also has DOM libraries; if you wanted, you could use those to build your original page as well, and be done with HTML forever. But I don't recommend it except in certain cases.

Conflicting jquery functions

I have built two functions which work separately (when the other is deleted) but do not work together. The overall aim is that when a person selects the number of results they want to see per page, this then reloads the page, and the value is put in the url and then retrieved using get in php; and then on the new page the selected value in the drop down menu to is the value what triggered the reload.
Jquery
$(document).ready(function(){
//the first section takes the value from the php script and then selects the option if it's not null - this works fine on it's own
var data = "<?php echo $rp;?>";
if (data){
$("#bo2 option[value="+data+"]").attr('selected', 'selected');
}
//this too works fine on it's own but not with the above
$('#bo2').change(function(){
var opt = $(this).val();
var url = "sales.php?results=";
var newurl = url + opt;
window.location.replace(newurl);
});
});
Together, the first works fine, in that it re-selects the right value if, say, I put ?results=50 after sales.php but then the jQuery to trigger the reload doesn't work. What am I doing wrong?
Just to clarify. The first page is called "sales.php" and the drop down menu has the currently selected value of "10", with 25 and 50 being other options. When I click on another number the jquery doesn't work. However should I type into the url the ending "?result=50", for example, it does work; and the drop down menu now shows 50; when i click on ten, the url updates, and the drop down shows ten also; the problem then is they seem to conflict only at the start, as it were.
It would seem the problem may concern how jquery deals with php. Take for example the following first example which works, and then the second which doesn't:
1)
$(document).ready(function(){
$('#bo2').change(function(){
var opt = $(this).val();
var url = "sales.php?results=";
var newurl = url + opt;
window.location.replace(newurl);
});
});
2) This change function however will not trigger a reload of the page because of the inclusion of the php defined jquery variable.
$(document).ready(function(){
var data = "<?php echo $rp;?>";
$('#bo2').change(function(){
var opt = $(this).val();
var url = "sales.php?results=";
var newurl = url + opt;
window.location.replace(newurl);
});
});
This achieves what I want (I don't know if the php posed a problem or not). The function is from here - Get url parameter jquery Or How to Get Query String Values In js.
Also, I'm surprised nobody more experienced than me didn't point out what also seems to have made a difference; the "first" function in the original post needs to in fact be second.
So the below will reload a new page, when a user clicks on an option in a select menu with pre-defined options for how many results they want to see per page; this value will then show in the url, and, importantly, the current select value of the select menu will now be this value also; this is important so that if the user goes back to the original number of views, the change() function works still.
$(document).ready(function(){
var getUrlParameter = function getUrlParameter(sParam) {
var sPageURL = decodeURIComponent(window.location.search.substring(1)),
sURLVariables = sPageURL.split('&'),
sParameterName,
i;
for (i = 0; i < sURLVariables.length; i++) {
sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] === sParam) {
return sParameterName[1] === undefined ? true : sParameterName[1];
}
}
};
var data = getUrlParameter('results');
$('#bo2').change(function(){
var opt = $(this).val();
var url = "sales.php?results=";
var newurl = url + opt;
window.location.replace(newurl);
});
if (data)
{
$("#bo2 option[value="+data+"]").attr('selected', 'selected');
}
});

Can I nest clicks for ajax calls within previously appended call results?

I'm making some early attempts at educating myself in AJAX and trying to speed pages rather than relying on PHP to show results. I have hit a hurdle.
I essentially have 3 tiers of data. With 3 database tables.
The first tier of data is pulled via a PHP loop and displayed upon page load.
The second tier of data is loaded via AJAX when A is clicked and then appended to the page via jQuery.
The third tier (where I'm having trouble) is loaded via AJAX when the second tier is clicked...and appended within the previously appended B data.
Like so....
<!-- language: lang-html -->
<!-- PHP loop to pull list if Item A data upon page load -->
<p>Item A</p>
<!-- click Item A -> AJAX pull B data and append results to .a-results -->
<div class="a-results">
<p>Item B</p>
<!-- click Item B -> AJAX and append results to .b-results -->
<div class="b-results">
<p>B resultrow</p>
<p>B resultrow</p>
<p>B resultrow</p>
<p>B resultrow</p>
</div>
</div>
Ajax examples:
<!-- language: lang-js -->
$('a.a-call').click( function (e) {
e.preventDefault();
var sid = $(this).attr('data');
$.ajax({
url: 'secondtier.php',
type: 'POST',
dataType: 'json',
data: ({sid: sid}),
success: function(rows) {
for (var i in rows) {
var row = rows[i];
var id = row[0];
var name = row[1];
var type = row[2];
$('.a-result').append("<p><a href='#' id='s"+id+"' data='"+id+"' class='b-call'>id: " + id + " name: " + name + " type: " + type + "</a></p><div class='b-data'></div>");
}
}
});
});
$('a.b-call').click( function (e) {
e.preventDefault();
var bid = $(this).attr('data');
$.ajax({
url: 'thirdtier.php',
type: 'POST',
dataType: 'json',
data: ({bid: bid}),
success: function(rows) {
for (var i in rows) {
var row = rows[i];
var id = row[0];
var data = row[1];
var cost = row[2];
$(this).next('.b-data').append("<p>date: " + date + " cost: " + cost + "</p>");
}
}
});
});
My AJAX calls work in themselves, however I can't get the B call to append results within the A results. The Item B AJAX works just fine if it's hard coded into the HTML, it's only when it's appended that I can't get it work. No console errors anywhere. Just nothing happening on the page.
I'm not totally current on jQuery usage. I tried .live('click', function() for the Item B click, however the console is telling me it's not valid. I assumed jQuery dropped that at some point.
Using google to link to jquery 1.9.1
<!-- language: lang-html -->
<script language="Javascript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Am I going about this wrong? Can I get the appended anchor in B to call another ajax function and append more to the previously appended div?
I don't want to load all this data at once. This is my very reason for learning AJAX. The page currently loads everything via PHP and due to the amount of datasets within datasets it's a slow page load. I'm trying to get specific data to only load upon a click.
You need to use delegate() , because .b-call elements does not exist on page load, so jQuery doesnt know where those elements are. So you need to delegate an event to an element that will exist after page load.
$('.a-result').delegate('.b-call','click',function (e) {
e.preventDefault();
var bid = $(this).attr('data');
$.ajax({
url: 'thirdtier.php',
type: 'POST',
dataType: 'json',
data: ({bid: bid}),
success: function(rows) {
for (var i in rows) {
var row = rows[i];
var id = row[0];
var data = row[1];
var cost = row[2];
$(this).next('.b-data').append("<p>date: " + date + " cost: " + cost + "</p>");
}
}
});
});
I think the problem is due to the fact that the link for fetching the B data is created when A is fetched.
The click event handler ($('a.b-call').click) is registered before the actual DOM element exists and therefore it does not get triggered.
To get this event handler working you need to change your code. The a-results div exists on page load, so you can attach the event handler to this element and simply specify the selector for a.b-call:
Example:
$('.a-results').on('click', 'a.b-call', function(e) {
// your B load code here
}

develop Chat module in php, mysql and ajax jquery

I am trying to implement a small chat application where user can text chat with any one of the online users.
My logic behind this is some thing like the following:
Login first.
Fetch the users who are online from DB and show them as list of online users.
Click on the users, then another small window is opening for text chatting.
Create a form(two hidden fields- one is for sender id and another is for receiver id, one textarea and a button for submitting) for this chatting.
Through jQuery, fill the value of receiver id.
By session id, fill the value of sender id.
After submitting the button, I call a page through ajax jquery which is responsible to insert and show the current data from DB.
My code for the ajaxJquery is like :
$(document).ready(function(){
$('#send_btn').click(function(){
var receiver_id = $('#hide_receiver_id').val();
var sender_id = $('#hide_sender_id').val();
var messagebox = $('#messagebox').val();
$.ajax({
type:"POST",
url:"chat_history.php?receiver_id="+receiver_id+"&sender_id="+sender_id+"&message="+messagebox,
success:function(result){
$('#history').html(result);
}
});
$('#messagebox').val('');
});
});
</script>
Up to this, its working fine. But I need to autoload the <div id="history"></div> portion. For that also I am thinking to do by using setInterval() in jQuery. My code is like :
<script type="text/javascript">
var auto_refresh = setInterval(
function (){
$('#history').load("chat_history.php?receiver_id=''&sender_id=<?php echo $_SESSION['id']?>&message=").fadeIn("fast");
}, 1000); // refresh every 1000 milliseconds
</script>
But in this scenario, how to pass the value of receiever_id in load() which is necessary to find out the respective data from DB?
Please let me know whether the requirement is cleared to you or not.
Thanks in advance.
<script>
$(function () {
// function wide variables
var receiver_id = $('#hide_receiver_id').val();
var sender_id = $('#hide_sender_id').val();
var messagebox = $('#messagebox').val();
// button click
$('#send_btn').click(function () {
receiver_id = $('#hide_receiver_id').val();
sender_id = $('#hide_sender_id').val();
messagebox = $('#messagebox').val();
$.ajax({
type : "POST",
url : "chat_history.php?receiver_id=" + receiver_id + "&sender_id=" + sender_id + "&message=" + messagebox,
success : function (result) {
$('#history').html(result);
}
});
$('#messagebox').val('');
});
var auto_refresh = setInterval(function(){
$('#history').load("chat_history.php?receiver_id="+receiver_id+"&sender_id=<?php echo $_SESSION['id']?>&message=").fadeIn("fast");
}, 1000); // refresh every 1000 milliseconds
});
</script>

Linking PHP into Mootools on select

How would I fill in the boxes of my form if I select one of the values from the dropdown menu (The dropdown is got from the DB) Somehow in my javascript I need to connect to functions as there is to different tables involved with the form fields.
Question
Do I need to set the fields using $field name?
if(document.id('LoadExtension') && document.id('ExtensionResponse')) { // id of select box
var sel = document.id('LoadExtension'); // ser select box as var.
sel.addEvent('change', function(chg) { // add change event to select box.
if(sel.getSelected().get('value') != '') { // on change if selected value is not empty.
new Request.HTML({
url : 'http://domain.co.nz/index.php?extension='+ sel.getSelected().get('value'),
onRequest: function() {
},
onComplete: function(r1, r2, html, js) {
document.id('ExtensionResponse').set('html', html);
}
}).send();
}
});
}
The above code was set up to get from another document in the url: box but I would like to do it in one page.
for your code:
http://www.jsfiddle.net/dimitar/TXHYg/4/
(function() {
// anon closure for scope purposes of local vars.
// cache selectors used repeatedly into local vars.
var sel = document.id('LoadExtension'), resp = document.id('ExtensionResponse');
// if they are in the dom...
if (sel && resp) {
// ... then attach event listener.
sel.addEvent('change', function(event) {
// this == sel.
var value = this.get("value"); // cache getter.
if (value === '') {
return false; // do nothing if not selected/
}
// otherwise, it will run the request
new Request.HTML({
method: "get", // or post.
data: {
extension: value // etc etc, can add more object properties and values
},
url: 'http://domain.co.nz/index.php',
onComplete: function(r1, r2, html, js) {
resp.set('html', html);
}
}).send();
});
} // end if
})(); // end closure.
you should really look at some tutorials and examples and the documentation for Request and Request.HTML/JSON/JSONP
an example, similar to yours that works for jsfiddle through its echo testing service (slightly different data object that simulates the response)
http://www.jsfiddle.net/dimitar/TXHYg/3/
instead of document.id('ExtensionResponse') you can write $('ExtensionResponse')
an if you only update a content of a element you can use the update parameter from Request.HTML.
new Request.HTML({
url : 'http://domain.co.nz/index.php',
data: 'extension='+ sel.getSelected().get('value'),
update: $('ExtensionResponse')
}).send();
#medrod;
That's right about the $(), but using the latest version of mootools + making sure Jess stays library safe, document.id() is a much safer option for compatibility.
you need to build the rest of your form, and populate it, with in the result of the ajax request.
eg: http://domain.co.nz/index.php?extension=
start your first HTML form with only the drop down, then your ajax'd script will build and populate the rest of the form.

Categories