JS: Changing this function to handle a link click - php

Following the example here Very Simple jQuery and PHP Ajax Request – Ready to use code
I've been successful in creating a drop down list that passes the value to an external PHP script and returns the HTML output back to a "div" on the same page and it works great.
What I want to do now is post values when I click on link instead of building a drop down list. So ...if I created this link:
Route Number 2
I want "2" passed to that external PHP script and the content changed on the " div " as it currently works with the dropdown. I don't know how to change the javascript to handle this or what "foo.php" really needs to be.
Here's the current javascript from that example:
<script type="text/javascript">
$(document).ready(function() {
$('#route_number').click(function() {
routenumber = $('#route_number').val();
$.post('api.php', { route_number : routenumber }, function(res) {
$("#mainlayer").html(res);
});
});
});
</script>
And here's what the dropdown portion of the HTML looks like:
<select name="route_number" id="route_number">
<option value="notchosen">Please Choose A Route</option>
<option value="2">Riverfront</option>
<option value="11">Magazine</option>
<option value="16">Claiborne</option>
</select>
<div id="mainlayer">
</div>
So, to be clear, instead of a dropdown that passes values, I want to create links that accomplish the same result.
Thanks in advance,
dan -

Create a class, capture its (meaning whatever link you clicked on) value, then post.
<a class="RouteNumber" href="foo.php?route_number=2">Route Number 2</a>
$(function(){
$('a.RouteNumber').on('click',function(event){
// prevent the browser's default action for clicking on a link
event.preventDefault();
// break href attribute into array, then parse desired value as int
var routenumber = $(this).attr('href').split('='),
rtnum = parseInt(routenumber[1]);
$.post('api.php',{route_number:rtnum},function(res){
$("#mainlayer").html(res);
});
});
});
If you don't need to parse the integer out of it (if a string is good enough), you don't need that second variable. You can just use routenumber[1] in the post data.
Just a heads up, I modified the jQuery to use the .on() syntax. .click() is shorthand for it, but I like using .on() just because it allows for less potential codewriting if you want to do more (like mouseenter/mouseleave, for example) because you can combine them into a single codeset.

I had hoped simply fixing #LifeInTheGrey's example would've sufficed, but there are some things I would've done differently that probably need some explaining.
Your HTML could look something like this:
<a class="route" href="foo.php?route_number=2" data-route="2">Route Number 2</a>
The JavaScript would look something like this:
$(function() {
var fill_div_with_response = function(res) {
$("#mainlayer").html(res);
};
var handle_error = function(res) {
alert('something went wrong!');
};
$(document.body).on('click', '.route', function(event) {
// prevent the browser's default action for clicking on a link
event.preventDefault();
// grab route number from data attribute
var route = $(this).data('route');
// make that post request
$.post('api.php', {route_number: route})
// handle the response
.done(fill_div_with_response)
// handle errors
.fail(handle_error);
});
});
The example uses delegated events. They're cheap to initialize and consume the least amount of memory.
The example handles errors. Most answers to questions like these neglect that. errors happen. Always. Make people aware of that. Surely throwing an alert() is not the thing you want to be doing, but it's still better than simply ignoring errors completely.
The example uses Deferreds (Promises) rather than callbacks, as this usually makes code much cleaner.
We're defining the callbacks fill_div_with_response() and handle_error() at the root closure to prevent redefining them on the next click. There's no need to feed the garbage collector.
The data attribute poses the optimal alternative to <option value="123"> in the way that it prevents you from having to parse the href attribute to extract that number from a string.

since you want to make a menu, I would modify your markup
<ul name="route_number" id="route_number">
<li value="2">Riverfront</li>
<li value="11">Magazine</li>
<li value="16">Claiborne</li>
</ul>
then simply process that list:
$('#route_number').find('li').click(function () {
var routenumber = $(this).attr('value');
$.post('api.php', {
route_number: routenumber
}, function (res) {
$("#mainlayer").html(res);
});
});
EDIT1: As an improvement (as you seem to be pretty new to this stuff) you could use the data with altered markup as such:
<ul name="route_number" id="route_number">
<li data-routenumber="2">Riverfront</li>
<li data-routenumber="11">Magazine</li>
<li data-routenumber="16">Claiborne</li>
</ul>
Then the code would be:
$('#route_number').find('li').click(function () {// add click event manager to each li
var routenumber = $(this).data('routenumber');// get routenumber of clicked
$.post('api.php', {
route_number: routenumber
}, function (res) {
$("#mainlayer").html(res);
});
});
Alternate code using .on() form
$('#route_number').on('click, 'li', function () {//click event manager for ul/li
var routenumber = $(this).data('routenumber');// get routenumber of clicked
$.post('api.php', {
route_number: routenumber
}, function (res) {
$("#mainlayer").html(res);
});
});
Note that this last form binds to the #route_number element so you could add more menu options during processing and they would still work. This is also better than attachment to the document as it is a more focused approach to the event attachment.

My understanding of your question is that the functionality you have is fine, and you just need to change the look to a piece of text from a dropdown. If so, good news! You can keep (almost) the same JavaScript.
Right now, your JavaScript is getting the value of your select box, sending it via AJAX, and using the returned value. The only change you need is to get the 'value' of the text clicked.
You don't want to use a link, since that's designed to take the user someplace. Instead you can use a span and format it to look like a link, or even a button if you want that kind of look.
You will also need to change $('#route_number').val();, probably to something passed by the click event. For example:
<span id="route1" class="routeSpan" onclick="sendVal(1)">Route 1 Name</span>
<span id="route2" class="routeSpan" onclick="sendVal(2)">Route 2 Name</span>
And your JavaScript:
function sendVal(routeVal) {
$.post('api.php',{route_number:routeVal},function(res){
$("#mainlayer").html(res);
});
}

Related

Best practice for using jquery to interact with php classes?

I have a dropdown selector on a page that allows a user to select a template type (for example, "human" or "dog").
Based on what template is selected, different fields will need to populate below the dropdown (for example, text fields for "parents names" or a dropdown list for "breed") that are unique to each template.
I will have a button that the user will click once the data fields are put in that will output data to an "output div" section of the same page when clicked (no POSTing data as it's not being saved). The output will have different output logic based on the selected template (for example, "I'm a human named X" or "I'm a dog, my breed is Y").
My real program will be more complex and each template will have a php class that stores all of the logic. Since I will be dealing with both php objects and variables gathered by jquery, what's the best way to let them interact?
For 1., I know I can do something easy like -
var selected_template = $('#my-template-dropdown :selected').text();
if (selected_template == 'Human'){
$('#my-fields').html('<?php echo HumanTemplate::render_fields(); ?>');
}
which is easy enough, but for 2. I need to pass variables from jquery to php, then return output back to jquery.
I would like some advice on the easiest way to do this before I start down the wrong path.
HTML
Allow the user to select the template type:
<form>
<select id="my-template-dropdown" name='template'>
<option value="dogs">Dogs</option>
<option value="humans">Humans</option>
</select>
</form>
<div id="my-fields"><div>
<div id="output"><div>
jQuery
Any time the user changes the template selection, request new content to display via AJAX, and insert it on the current page so the page does not have to refresh:
$('#my-template-dropdown').on('change', function() {
var template = $(this).val();
$.ajax({
url: 'http://your-site/path/to/' + template,
success: function(resp) {
$('#my-fields').html(resp);
}
});
});
PHP
http://your-site/path/to/template simply generates the HTML you want to display for that template, eg (just an example, don't know if this is suitable for your app):
if ($template == 'humans') {
echo HumanTemplate::render_fields();
} else if ($template == 'dogs') {
echo DogTemplate::render_fields();
}
For part 2, assuming all the logic you refer to is in the template rendered by PHP, you could then handle it with jQuery. This is pretty crude, you probably need something more sophisticated (eg a full template which you swap variables into?), but you get the idea:
$('#output').on('click', 'button', function(e) {
e.preventDefault();
// fields in your template which the user will fill
var species = $('#species').val(),
title = $('#title').val();
// Probably better to have this text as a template in your source
$('#output').html("I'm a " + species + ' named ' + title);
});
NOTE the gotcha in the event handler. Event handlers will only attach to elements that exist at the time the handler is defined. Since the content is injected after page load, an event handler like $('#button).on('click', function() {... would have no effect when clicking a button inserted via AJAX. The syntax here attaches to the parent #output div, which does exist at page load, and filters for clicks on a button. See the jQuery event delegation docs for more info.
Another option would be to POST the submitted data to some PHP controller, which generates and returns the output. This way all your logic is in the one place. For example, here the user's click will query the same PHP file which generated the initial template, this time including the values the user has entered. It could then generate the required output and return it, to be inserted on the page. You'd need to update the PHP so it can determine which of these cases it is handling (eg hidden field?); alternatively if you wanted to keep those separate you could hit another PHP file all together.
$('#output').on('click', 'button', function(e) {
var template = $('#my-template-dropdown').val(),
$form = $('form'),
data = $form.serialize(); // Values from all fields user has entered
$.ajax({
url: 'http://your-site/path/to/' + template,
data: data,
success: function(resp) {
$('#output').html(resp);
}
});
});
The best way to pass data from jQuery to PHP, is by using AJAX.
Mozilla has an excellent guide on getting started, that i recommend you follow.
An example of how you can achieve what you are requesting, is by trying the following:
var selected_template = $('#my-template-dropdown :selected').text();
var ajaxurl = 'ajax.php',
data = {'select_template': selected_template };
$.post(ajaxurl, data, function (response) {
console.log(response);
});
On the PHP end (Ajax.php in my example) It could look something like this
if(isset($_POST['select_template'])) {
// do something with the input from jQuery
$selected_template = $_POST['select_template'];
// return the result back to the client
echo $seleted_template;
}
?>
$selected_template will be sent back to the client, and response in the AJAX function will be whatever the server returned. So the console.log(response) should display whatever was being sent to the server
You can have a look to the function wp_localize_script.
This function make available PHP datas to JS files on the page load through the wp_enqueue_scripts action.
This will not work like an Ajax request and only populate data for a specific handle on page load. But you can mix this method with ajax in the same script.
Hope it helps even it doesn't seems to fit to your case.
As your class not fires on page load, you can use the action wp_ajax_{custom _action} and wp_ajax_nopriv_{custom_action} . For example, that's usually used to populate multiple dropdown, each time an event is trigger by the user, a php function returns result the js script.

Can a variable go to a hidden PHP page using jQuery?

My PHP page
<ul id="upvote-the-image">
<li>Upvote<img src="image.png" /></li>
</ul>​
is currently successfully sending variable to javascript
$("#upvote").each(function(index) {
var upthis = $(this).attr("rel");
var plusone = upthis;
$.post("upvote.php", {
'plusone': plusone
});
alert(plusone);
});​
(The alert in the code is for testing)
I have multiple images using the rel tag. I would like for each to be able to be upvoted and shown that they are upvoted on the page without loading a new page.
My question, and problem: what is my next step? I would just like to know how to send a value to upvote.php. I know how touse mysql to add an upvote, just not how to send a value to upvote.php, or even if my javascript code opens the page correctly.
thanks
I think you need something like this:
<ul id="upvote-the-image">
<li><span rel="50" id="upvote">Upvote</span><img src="image.png" /></li>
</ul>​
<span id="result"></span>
$("#upvote").click(function(index) {
var upthis = $(this).attr("rel");
var oOptions = {
url: upvote.php, //the receiving data page
data: upthis, //the data to the server
complete: function() { $('#result').text('Thanks!') } //the result on the page
};
$.ajax(oOptions);
}
You dont need an anchor, I changed it for a span, you can test asyc connection using F12 in your browser
Your javascript never opens the php page, it just sends data to it, and receives an http header with a response. Your php script should be watching for $_POST['plusone'] and handle database processing accordingly. Your next step would be to write a callback within your $.post function, which I recommend changing to the full ajax function while learning, as it's easier to understand and see all the pieces of what's happening.
$.ajax({
type: 'POST',
url: "upvote.php",
data: {'plusone': plusone},
success: function(IDofSelectedImg){
//function to increment the rel value in the image that was clicked
$(IDofSelectedImg).attr("rel")= upthis +1;
},
});
You'd need some unique identifier for each img element in order to select it, and send it's id to the php script. add a class instead of id for upvote and make the id a uniquely identifiable number that you could target with jquery when you need to increment the rel value. (From the looks of it, It looks like you're putting the value from the rel attribute into the database in the place of the old value.)
A good programming tip here for JQuery, Don't do:
<a href="javascript:return false;"
Instead do something like:
$(function(){
$('#upvote').on('click', function(event){
event.preventDefault();
$.post('upvote.php', {'plusone': $(this).attr('rel')}, function(data){
alert('done and upvoted');
});
});
});
That is a much better way to handle links on your DOM document.
Here are some Doc pages for you to read about that coding I use:
http://api.jquery.com/on/
http://api.jquery.com/jQuery.post/
Those will explain my code to you.
Hope it helps,

What is a good way to transfer function arguments when using selectors?

I am trying to isolate my HTML from my js by replacing the following
<div id = "foo" onclick="bar(variable)"></div>
with
<div id = "foo"></div>
$(document).ready(function() {
$("#foo").click(function(event) {
bar(???);
});
});
Now, what would be a good way to transfer the parameter for bar().
Should I merge it with some element id? Or should I declare it as a JS variable using PHP when I load the page? Or is there a better way?
You can put an attribute on the item itself and retrieve that from the click handler.
<div id="foo" data-item="29"></div>
$(document).ready(function() {
$("#foo").click(function(event) {
bar($(this).data("item"));
});
});
Of course, if you only have one of these, you don't need to abstract the data number, you can just do it like this:
$(document).ready(function() {
$("#foo").click(function(event) {
bar(29);
});
});
But, I think we all assumed that you want the 29 to come from the markup so you can use a common click handler on many elements. If that's the case, then the first method accomplishes that.
Simple - if you're getting the variable using php:
<div id="foo"></div>
$(document).ready(function() {
$("#foo").click(function(event) {
bar( <?= $variable ?> );
});
});
I would suggest the data-attribute as others have suggested. It's not valid html but It works in all browsers that are used today...
the people who prefer to write valid code(not me in this case) like to add data to the class attribute or will just set it in the javascript.
You could store the parameter as a data attribute:
<div id="foo" data-bar="29"></div>
$(document).ready(function() {
$("#foo").click(function(event) {
bar($(this).data('bar'));
});
});
Most people think they need parameters to locate elements that are a sub-element of, or an element with a known path from, the element that was clicked. For that kind of thing the best thing to do is not use a parameter at all, but traverse the DOM from the node that was clicked to find the appropriate element.
$("#foo").click(function(event) {
var doSomethingTo = $(this).find('div')[0];
doSomethingTo.hide();
});

How can I edit my drop down list to show me the results with AJAX? (No reload)

I am using a form that shows different (extra) fields based on the onChange selection of the following drop down list.
What I did, I get the value and if the value equals to an IF statement it displays the correct extra field for the selected category. This procedure is done with a reload of the page.
My question is how can I build it using Ajax and avoid reloading? An Ajax call on the OnChange otion maybe..
Thank you!
<select
onchange="if(this.options.selectedIndex>0) window.location.href = 'http://mypage/?something&value=+this.options[this.options.selectedIndex].value"
class="select" id="termid" name="termid">
<option value="46">CARS</option>
.
.
</select>
this is something I found from a tutorial
$(function() {
$('#sel').change(function() {
$("input").hide().filter("." + $(this).find("option:selected").val()).show();
});
$("input").focus(function() {
$(this).next("span").fadeIn(1000);
}).blur(function() {
$(this).next("span").fadeOut(1000);
});
});
and the css that hides everything
input{
display:none;
}
span
{
display:none;
}
There are a few steps to transform a new page load in an ajax call on the same page:
You need to make a php file that just returns the html for the extra fields (no head, body, your select, etc.)
You need to change your event handler. As you are using jQuery, you can remove all inline javascript and just replace it with $('#termid').change(function() { // your ajax stuff here });
The easiest ajax call in jQuery is the load() method so you could use that like $('#some_div_below_select').load('your_new_php_file.php&value=' + $(this).val());. That puts the contents that are generated with you new php file in the element with ID some_div_below_select.
In the part where I put your ajax stuff, you can add the necessary checks like the if statement you have now.
To sum up the javascript part (I changed the way the parameter is passed):
$(document).ready(function() {
$('#termid').change(function() {
$('#some_div_below_select').load('your_new_php_file.php', { "value" : $(this).val() });
});
});
Use the javascript change event. Bind that event to the select list and make the ajax call to update the list when change is fired.
If using JQuery nice and easy and lots of documentation

How to get element id into PHP variable

Is it possible to get an element id into a PHP variable?
Let's say I have a number of element with IDs:
<span id="1" class="myElement"></span>
<span id="2" class="myElement"></span>
How do I get this into a PHP variable in order to submit a query. I suppose I would have to resubmit the page, which is OK. I would like to use POST. Can I do something like:
<script language="JavaScript">
$(document).ready(function(){
$(".myElement").click(function() {
$.post("'.$_SERVER['REQUEST_URI'].'", { id: $(this).attr("id") });
});
});
</script>
I need to pass $(this).attr('id') into $newID in order to run
SELECT * from t1 WHERE id = $newID
jQuery is a very powerful tool and I would like to figure out a way to combine its power with server-side code.
Thanks.
This is like your question: ajax post with jQuery
If you want this all in one file (posting to active file) here is what you would need in general:
<?php
// Place this at the top of your file
if (isset($_POST['id'])) {
$newID = $_POST['id']; // You need to sanitize this before using in a query
// Perform some db queries, etc here
// Format a desired response (text, html, etc)
$response = 'Format a response here';
// This will return your formatted response to the $.post() call in jQuery
return print_r($response);
}
?>
<script type='text/javascript'>
$(document).ready(function() {
$('.myElement').click(function() {
$.post(location.href, { id: $(this).attr('id') }, function(response) {
// Inserts your chosen response into the page in 'response-content' DIV
$('#response-content').html(response); // Can also use .text(), .append(), etc
});
});
});
</script>
<span id="1" class="myElement"></span>
<span id="2" class="myElement"></span>
<div id='response-content'></div>
From here you can customize the queries and response and what you would like to do with the response.
You have two "good" choices in my mind.
The first is to initiate a post request every time the ordering changes. You might be changing the ordering using jQuery UI sortable. Most libraries that support dragging and dropping also allow you to put an event callback on the drop simply within the initialization function.
In this even callback, you'd initiate the $.post as you have written it in your code (although I would urge you to look up the actual documentation on the matter to make sure you're POSTing to the correct location).
The second strategy is to piggyback on a form submission action. If you're using the jQuery Form Plugin to handle your form submissions, they allow you to indicate a before serialize callback where you can simply add into your form a field that specifies the ordering of the elements.
In both cases, you'd need to write your own function that actually serializes the element IDs. Something like the following would do just fine (totally untested; may contain syntax errors):
var order = [];
$('span.myElement').each(function(){
// N.B., "this" here is a DOM element, not a jQuery container
order.push(this.id);
});
return order.join(',');
You're quite right, something along those lines would work. Here's an example:
(btw, using $.post or $.get doesn't resubmit the page but sends an AJAX request that can call a callback function once the server returns, which is pretty neat)
<script language="JavaScript">
$(document).ready(function(){
$(".myElement").click(function() {
$.post(document.location, { id: $(this).attr("id") },
function (data) {
// say data will be some new HTML the server sends our way
// update some component on the page with contents representing the element with that new id
$('div#someContentSpace').html(data);
});
});
});
</script>
Your approach looks perfectly fine to me, but jQuery does not have a $_SERVER variable like PHP does. The url you would want to provide would be window.location (I believe an empty string will also work, or you can just specify the url on your own). You seem to be sending the ID just fine, though, so this will work.
If you want the page to react to this change, you can add a callback function to $.post(). You can do a variety of things.
$.post(window.location, {id: this.id}, function (data) {
//one
location.reload();
//two
$("#responsedata").html(data);
//three
$("#responsedata").load("affected_page.php #output");
});
I think number 2 is the most elegent. It does not require a page reload. Have your server side php script echo whatever data you want back (json, html, whatever), and it will be put in data above for jQuery to handle however you wish.
By the way, on the server side running the query, don't forget to sanitize the $id and put it in quotes. You don't want someone SQL Injecting you.

Categories