My first contact with Ajax is happening right now, and I'm kind a confused. I've read many of questions asked, but I'm not able to read the answer, that is most likely here somewhere.
Situation is, I'm using OOP PHP approach, and all I do go through index.php with parameters. So I do not call any other .php file in form posts, button clicks..
I've created an HTML listbox (which I'd like to remove vertical scrollbar, but that's just a bonus to resolve), which feeds my categories in it.
Now, by clicking each category I'd like to call certain function that would then generate output for the other div.
function swapContent(){
$("#myPresentDiv").html('<img src="../../imgs/ajax-loader-big.gif"/>').show();
var cat = $('#listbox').val();
$("#action").change(alert(cat));
var url = "&s=".cat;
$.post(url, {contentVar: cat} ,function(data) {
$("#myPresentDiv").html(data).show();
});
}
So, my JQuery script picks up correct Category, I alert it to alert dialog, so I'm sure that's fine, and then with code as it is at the moment, I reload my whole page so I get, page in page in page in page...
I'm trying to figure out how to write JQ ajax call, that would return only the results, not the whole page.
can I put URL "index.php&s="cat, and then somehow tell to ajax "go through index, call function displayresults ($cat); ?
Hope everything I wrote make sense to you :)
Tnx.
The url's your ajax function call, must return only the page parts and not the whole html document.
If you have
$.post('ajax.php',data,function(d){
$('#responsediv').html(d).show();
});
The file ajax.php must only return the page parts,like
<div>This is the new content</div>
so you will not have page inside page.
If you look at the frameworks or cms out there, they basically have routes that map calls to your index.php function to methods of the controller.
This is a complex argument, you could try to start out reading this article
Yeah, that makes sense. Your question is basically: when you get a result of an AJAX op and insert it into your page, it inserts the whole layout again, rather than the template.
OK, so the solution is to make a call to a PHP script that is "unstyled" i.e. has no template data. Your PHP script should therefore just output a short HTML snippet rather than a page (you might have a 'header' and 'footer' that can be removed for this page). What action you need to take depends what you're using on the server side - framework? CMS? Custom PHP app?
I did the exact thing for a internal app quite some time ago....What happened was i was passing the class name, function name and the function parameters via ajax variables and reading the same in php at the backend and then call the appropriate function in the class with those paraeters.
The PHP code:
$option = trim($_GET['v']);
switch ( $option ) {
case 1:
$sid = trim($_GET['q']);
$page = trim($_GET['p']);
$method = trim($_GET['m']);
$class = new $page( $link );
echo $class->$method( $sid );
break;
case 2:
$page = trim($_GET['p']);
$method = trim($_GET['m']);
$class = new $page( $link );
echo $class->$method();
break;
default:
echo '';
break;
}
But this was an internal app, so there was no injection attacks, xss,xsrf,session hijack issues....things might differ for you
Hope this helps.
I think you are searching for a GENERAL strategy to handle ajax requests its upto you
for example Server Side Ajax
unless you are using a specific framework (CI , yii etc)
You might want to look into some frameworks, as they can make this for you infinitely easier to implement:
http://demo.atk4.com/demo.html?t=20
Related
Is it possible to submit a query without updating the URL?
On a dictionary, I want to do first one simple query: www.example.com/?q=word
On the result page there will be a button with which I want to search for more results with another query.
This second query will be done normally with www.example.com/more.php?q=word.
That code would look as follows:
<button onclick="window.location.href = 'more.php?q=<?php echo "$trimmed"; ?>';">search for more results</button>
However, I want that the URL remains unchanged so that the next dictionary query starts again with a simple query. In other words, I want to hide the part "more.php" from the URL.
Assuming that your www.example.com?q=word points to the index.php.
Assuming also that your more.php contains functions.
Assuming as third, that your index.php returns something displayable in the browser even if there is no GET-parameter i.e. the initial page call.
Doing so, a really simple solution would be to fire every query against the index.php.
There you can handle every query, even different types, based on a new GET-parameter type use use.
#index.php
require 'more.php';
// do something here to validate the parameters you use
switch($_GET('type')) {
case 'simple':
return simpleCall();
break;
case 'more':
return additionalInfo();
break;
}
function simpleCall() {
// do stuff here
// access $_GET for other paramters
}
#more.php
function complexCall() {
//do complex stuff here
}
Finally, your HTML would look something like this
<button onclick="window.location.href = '/?type="more"&q=<?php echo "$trimmed"; ?>';">search for more results</button>
Until you get more than these two types it becomes cluttering at your switch-statement.
For this reason, it would be a good idea to think about different solutions like:
having a routing system like this https://medium.com/the-andela-way/how-to-build-a-basic-server-side-routing-system-in-php-e52e613cf241
using asynchronous calls from your frontend with the help of JavaScript to call to different PHP files on the server but stay on the same page in the frontend. This will immediately lead to some kind of API. But this is generally not the badest idea.
Please validate your parameters regardless if POST or GET before you do anything with them in the rest of your code. Having the example of a dictionary sounds extremely like to query a database where SQL injection is, for example, a big thing if data us used unchecked.
I hope this helps a bit.
Im looking for an elegant way to hand over data/params when using $f3->reroute();
I have multiple routes configured in a routes.ini:
GET #sso: /sso/first [sync] = Controller\Ccp\Sso->first, 0
GET #map: /map [sync] = Controller\MapController->second, 3600
Now I reroute(); to #map route, from first();
class Sso {
public function first($f3){
$msg = 'My message!';
if( !empty($msg) ){
$f3->reroute('#map');
}
}
}
Is there any "elegant" way to pass data (e.g. $msg) right into $MapController->second(); ?
I donĀ“t want to use $SESSION or the global $f->set('msg', $msg); for this.
This isn't an issue specific to fat-free-framework, but web in general. When you reroute, you tell the browser to redirect the user's browser page using a 303 header redirect code.
Take a minute to read the doc regarding re-routing: http://fatfreeframework.com/routing-engine#rerouting
There seems to be some contradicting information in your question, which leads me to question the purpose of what you are trying to achieve.
If you are rerouting, you can either use the session, cookies, or use part of the url to pass messages or references to a message.
If you do not need to redirect, but just want to call the function without changing the passed parameters, you could abstract the content of the function and call that function from both routes. You could also use the $f3 globals, which are a great way of passing data between functions in cases where you don't want to pass the data using the function call. is there a reason why you don't want to to use this? The data is global for the single session, so there is no security concern, and the data gets wiped at the end of the request, so there is very little extra footprint or effect on the server.
If you're alright with not using #map_name in re-routes you can do something like this:
$f3->reroute('path/?foo=bar');
Not the prettiest I'll admit. I wish $f3->reroute('#path_name?foo=bar') would work.
I have a PHP page where the header and footer are PHP includes.
I want to know if there is any possibility of the includes loading asynchronously - or does PHP gather all the files required, compile them and send them as one file?
The reason I ask is that I've seen an interesting PHP app that seemed to keep the connection open and do things in sequence before closing the connection - I wondered if that's what happens with includes.
PHP version is 5.3.6
EDIT:
What I actually want is for the page to load all at once, to prevent my layout mashing as each bit loads. Sorry to any who misunderstood this
PHP does gather and compile them; everything goes to the browser as a single document. If you don't want this, you'll have to do something with XMLHTTPRequest on the frontend
Generally any output will be output as it is generated.
echo 'A';
sleep(1000);
echo 'B';
sleep(1000);
echo 'C';
This slowly outputs "ABC". Includes are included when they are encountered, the same way echo outputs anything at that specific point. It's all in order, never asynchronously.
A web server may buffer all output before sending any of it to the client. In the above example, you'd receive "ABC" all together after 2 seconds of nothing.
If your objective is to receive all the page at once you need to use ob_start() and ob_end_flush(). Do something like:
ob_start();
...
write all your outputs
...
ob_end_flush();
This will force the server to buffer the output until the whole page is prepared.
Good luck!
I use the following architecture when loading a page on my application:
index.php
<script src="path/to/js/lib/jslib.js" type="text/javascript"></script>
window.addEvent('load', function()
{
BuildPg(PgStatus); //PgStatus is a variable I use in a state machine to build different pages
});
<form>
<div id="DivPgTop"></div>
<div id="DivPgMiddle"></div>
<div id="DivPgBottom"></div>
</form>
This is the entire index.php
In my jslib.js I have functions like:
function BuildPg(Pg) {
BuildPgTop(Pg);
BuildPgMiddle(Pg);
BuildPgBottom(Pg);
}
function BuildPgTop(Pg) {
var Content="";
if (Pg == 1) {
Content = function_a(); // function_a builds the top of the page
else if (Pg == 2) {
Content = function_b();
etc...
}
document.getElementById("DivPgTop").innerHTML = Content; //here is where I load the top of the page
}
And I do the same for the other parts of the page Middle and Bottom.
Using this framework, if you changed my BuildPg() function to something like:
function BuildPg(Pg) {
BuildPgTop(Pg);
sleep(foo);
BuildPgMiddle(Pg);
sleep(bar);
BuildPgBottom(Pg);
}
Your user would experience the top of the page loading first, a delay, the middle of the page, another delay, and the bottom.
And if you change the order of the function calls you could even have the bottom of the page load first, then the middle and the top.
I hope this makes sense. Good luck!
PHP sends a single document. What you want to do is achieved with something called AJAX (http://en.wikipedia.org/wiki/Ajax_%28programming%29)
Basically you write some JavaScript code that uses XMLHTTPRequest object to connect to the server and download some extra info.
So I have a site with a dozen pages on it using Drupal as a CMS. Wanted to know how to set/append all href links on any page with a dynamic attribute?
so here is an example URL:
http://www.site.com/?q=node/4
and I wanted to append to the URL like so:
http://www.site.com/?q=node/4&attr=1234
Now I have a nav bar on the site and when I hover over the link I see the url but I need to append the &attr=1234 string to the end of it. The string is dynamic so it might change from time to time.
I was thinking jQuery would be a good choice to do this but does Drupal have any functionality as well?
Now I've seen a couple of posts on Stack:
Post 1
Post 2
Problem is I'm learning my way around Drupal and have minimal experience with jQuery but getting better with both. I see the jQuery can replace a HREF but looks like they hard coded the HREF, could jQuery find all HREF's on a page and append the string to it? Also does Drupal have this functionality and what would be the best approach?
Also need this to work for clean or standard URL format, so I think Apache would handle this I just wanted to make sure.
Thanks for any help
EDIT:
Looks like the general consensus is the Drupal should handle this type of request. Just looking for the best implementation. Simple function call would be best but I would like it to dynamically add it to all existing href's as I want this to be dynamic instead of hard coding any url/href calls. So I could add/remove pages on the fly without the need to reconfigure/recode anything.
Thanks for the great tips though
EDIT #2:
Okay maybe I'm asking the wring question. Here is what I need and why it's not working for me yet.
I need to pass a value in the url that changes some of the look and feel of the site. I need it to be passed on just about every href tag on the page but not on User logout or Admin pages.
I see in my template code where the nav links get generated, so I though I could pass my code in the attributes array as the second parm to the function, but that is setting the tag attributes and not the URL attributes.
Now I see the bottom nav links use this Drupal function: menu_navigation_links() in menu.inc but the top nav uses a custom function.
This function in the template.php script looks to be the one creating the links
function lplus($text, $path, $options = array()) {
global $language;
// Merge in defaults.
$options += array(
'attributes' => array(),
'html' => FALSE,
);
// Append active class.
if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
(empty($options['language']) || $options['language']->language == $language->language)) {
if (isset($options['attributes']['class'])) {
$options['attributes']['class'] .= ' active';
}
else {
$options['attributes']['class'] = 'active';
}
}
// Remove all HTML and PHP tags from a tooltip. For best performance, we act only
// if a quick strpos() pre-check gave a suspicion (because strip_tags() is expensive).
if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
$options['attributes']['title'] = strip_tags($options['attributes']['title']);
}
return '<a href="'. check_url(url($path, $options)) .'"'. drupal_attributes($options['attributes']) .'><b>'. ($options['html'] ? $text : check_plain($text)) .'</b></a>';
}
not sure how to incorporate what I need into this function.
So on the home page the ?q=node/ is missing and if I append the ampersand it throws an error.
http://www.site.com/&attr=1234 // throws error
But if I mod it to the correct format it works fine
http://www.site.com/?attr=1234
Assuming that when you mean pages, you mean the content type of pages (will work for any other content type as long as it's really content and not something in a block or view).
You can easily replace the contents of any node that is about to be viewed by running a str_replace or with a regular expression. For instance, using str_replace:
function module_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch($op) {
case "view":
$node->body = str_replace($expected_link, $desired_link);
break;
}
}
where you define desired link somewhere else. Not an optimal solution, but non-Javascript browsers (yes, they still exist!) can't get around the forced, desired URLs if you try to change it with Javascript.
I think doing it in Drupal/PHP would be cleaner. Check out Pathauto module: http://drupal.org/node/17345
There is a good discussion on a related topic here:
http://drupal.org/node/249864
This wouldn't use jquery (instead you would overwrite a function using PHP) but you could get the same result. This assumes, however, that you are working with menu links.
I think you should consider exploring PURL ( http://drupal.org/project/purl ) and some of the modules it works with e.g. spaces and context.
I don't suggest you use jQuery to do this. It's a better practice to do this server side in PHP (Drupal).
You can overwrite the links dynamically into your preprocess page function.
On your template.php file:
function *yourtheme*_preprocess_page(&$vars, $hook){
//You can do it for the region that you need
$vars['content'] = preg_replace('/<a href="(.*?)"/i', '<a href="$1&attr=1234"', $vars['content']);
}
Note:
I did not try it, its only a hint.
It will add your parameters to the outside links too.
I need to detect where the user has just clicked from - as my AJAX content needs to be displayed differently depending on the source page it is to be inserted into.
If it's to go into about.php it needs to be data only, but if it's to go into about-main.php it needs to be the whole middle column so needs a header/footer wrapper around the data.
The html called via AJAX is held in a php page which uses this code to see who's asking, and then formats the HTML response appropriately.
$array[] = "/cf/about.php";
$array[] = "/cf/about/about-main.php";
$array[] = "/cf/about/other-page.php";
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] != $value) {
$ispage = "";
} else {
$ispage = "woot";
}
}
if ($ispage == "woot") {
echo $content;
} else {
include_once 'about-header.php';
echo $content;
include_once 'about-footer.php';
}
The problem is... HTTP_REFERER seems to be a bit hit and miss. It works just fine while I'm at work on the network, but I've tried it out on my computer at home and it's obviously completely failing to work - the results are horrible :o
Is there another way of achieving this? I guess session variables could be used but then I've not got much experience of that!
Any and all hints/tips are appreciated ;)
Thanks!
edit:
The page is actually a staff profile page. Its normal location is about.php and the 2nd column div displays a grid of thumbnails which when clicked, load the profile in that place via AJAX. All nice and simple - back button reloads the grid of photos.
The problem is, each staff member also needs a static page. I've created these at about/staff-name.php. The content is THE SAME though. I want the server to detect if someone has come to the about/staff-name.php directly and if so, wrap a header/footer around it.
If the request has come from the grid of photos (ie AJAX) then it doesn't need the header/footer wrapper.
Is that clear? :o
1) If AJAX request - no wrapper
2) If not AJAX request - add header/footer wrapper
Wouldn't it be easier to just pass a flag in your AJAX call to tell the script which type of content to display?
Edit:
So about/staff-name.php displays the content. Call it via AJAX as about/staff-name.php?FromAjax=1
Then in the about/staff-name.php file:
if (isset($_REQUEST['FromAjax']) ) {
echo $content;
} else {
include_once 'about-header.php';
echo $content;
include_once 'about-footer.php';
}
No matter what, the Referer is not an information you should base your whole website upon : it is sent by the client, which means (at least) :
the client does not necessarily have to send it
it can be disabled in the browser
some firewall / antivirus remove it
it can be forged / altered (an easy way with firefox is to use an extension to do that)
You definitly must find a better/saffer/more reliable way to do what you need.
One solution (which you already discarded) would be to pass an additionnal information in all your links, saying which page the request comes from. In my opinion, this would probably be the best thing to do...
Maybe a simpler way would be to add a parameter to your Ajax request, saying where it comes from ? ie, instead of relying on the Referer in the PHP script, just have a look at a parameter in the request, which would act as some "kind of referer", but put by you ?
It will not be more secure (users could still forge request, with that parameter), but, at least, it would not be disabled / modified (except if the user does it by hand)
In the end, you also say this :
1) If AJAX request - no wrapper
2) If
not AJAX request - add header/footer
wrapper
Well, if it's only a matter of determining if the PHP script was called through an Ajax request, here too, two solutions :
Add a parameter to the Request when it's done through Ajax (you only add this parameter in the JS script doing the request ; and when the parameter is here, PHP knows it's an Ajax request)
Or, in the PHP script, look for an X-Requested-With HTTP header, which is often here with the value XMLHttpRequest when a request is made through an Ajax call. (But you should check that it's set with your JS Framework / or maybe it depends on the browser -- not sure about that :-( )
Why don't you just create the static pages on the server without using ajax at all, including the header and footer and the profile bit? If the page is static you shouldn't have any need to load content using javascript.
If you do need to load it using javascript, then Vex's solution is good. You could pass some optional parameters in the ajax call which control how the page is rendered - that way, the included page doesn't need to know about the pages that use it, it just needs to understand the parameters that tell it how to render itself. You can then reuse it more easily in future.
I did notice an error in your code however - this probably won't work as expected:
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] != $value) {
$ispage = "";
} else {
$ispage = "woot";
}
}
If a page name is matched, but then the next one isn't, $ispage will be set back to ''. You'd probably better off doing something like:
$ispage = "";
foreach ($array as $value) {
if ($_SERVER['HTTP_REFERER'] == $value) {
$ispage = "woot";
break;
}
}
or
$ispage = '';
if (in_array($_SERVER['HTTP_REFERER'], $array)) {
$ispage = 'woot';
}
Tai kucing -
If you format your links like this:
link
Then the php just needs to be this:
if (isset($_REQUEST['setvariablehere']) ) {
do something for when variable IS set
} else {
do something for when variable IS NOT set
}