.load() html content into a container in a loop - php

I have a container $('#container') and I want to dynamically load several elemtents into the container. I have a php layout called subElement.php. So my code looks like:
for(i = 0;i<10;i++){
$('#container').load('subElement.php?id='+i,function(data){});
}
Only one subElement.php layout is loaded in to the container. How can I do this in a better way?

Ideally, you should rewrite your PHP script to get all the data at once, so you only need one .load. Doing so will be faster and much gentler on the user's network connections.
However, since you asked us to work with what you have:
for(i = 0;i<10;i++){
$('#container').append($('<span>').load('subElement.php?id='+i));
}
If those <span> elements are going to mess up your code, though, you should go with a solution like Explosion Pills' instead.

.load will overwrite the contents each time. Instead, you have to append them, possibly like so:
$.get('subElement.php?id=+1', function (data) {
$("#container").append(data);
});

Each time through the loop, load() replaces the contents of $('#container') with the new thing that you've requested.
For efficiency, the best thing to do would be to ajax for all of the sub elements in one gulp, instead of making 10 separate HTTP requests.
Another way to do it, if for some reason you can't change the api to support getting multiple elements, is to use .get() and collect all of the answers before doing a single replacement.

You can use $('#container').append('some content') to add to #container.

Related

Replicating preloaded HTML /DOM method results in an array using AJAX/PHP

I have a function that creates an array that contains the return value from the HTML DOM method : window.document.getElementById()
function makearray1(){
var array1=[1,window.document.getElementById('divID'),['a','b'],[1,2]];
}
then I pass the array into another function
use(array1)
function use(xxx){
xxx[1].innerHTML=xxx[2][0];
}
and 'a' is written in the appropriate div
later I decided to put the array in a form and post it to a txt file on the server using php and:
JSON.stringify(array)
So now I use AJAX to call the data from the txt file after the rest of the page has loaded etc... and the original function used to make the array is not included at all.
so my php is basically this:
$a1='use(';
$data1 =file_get_contents("text_file.txt") ;
$a2=')';
echo $a1.$data1.$a2;
and the response text:
var n= XMLHttpRequestObject.responseText;
eval(n);
which pretty much means this:
use(text_file)
function use(xxx){
xxx[1].innerHTML=xxx[2][0];
}
the problem is that the array in the text file looks like this:
[1,null,['a','b'],[1,2]]
instead of:
[1,window.document.getElementById('divID'),['a','b'],[1,2]]
My question: Is there any way that I can do the equivalent of what I'm trying to do here, which is immediately replicate the return value of the HTML/DOM method in an array using AJAX/php?
To clarify: this is a simple example. I actually have a huge, multidimensional array that already has established pointers, or prefetched DOM nodes in it. Now I'm trying to replicate the array when a text version is loaded using ajax. I'm looking for a recursive approach to changing all of the null assignments with something that will immediately fetch the appropriate DOM node. Most likely I will need to do it with the response text, but was hoping I could do it with the php portion.
You're trying to stringify a reference to a javascript object in the memory of whatever computer is evaluating getElementById first, and that has no chance to represent something on the end client's computer.
Send the id instead:
function makearray1(){
array1=[1,'divID',['a','b'],[1,2]];
}
then, in the client:
function use(xxx){
window.document.getElementById(xxx[1]).innerHTML=xxx[2][0];
}
If you really want to eval it at the end, you can use this, I guess
function makearray1(){
array1=[1,"window.document.getElementById(\"divID\")",['a','b'],[1,2]];
}
I've no idea why you would want to do that though
Assuming the dom element exists in the second page, it should look something like this.
JS:
function packDomData(){
return {
"MySpecificYetBriefProperty0":1,
"DomID":"divID",
"MySpecificYetBriefProperty1":['a','b'],
"MySpecificYetBriefProperty2":[1,2]
};
}
function useDomData(domData){
document.getElementByID(domData.DomID).innerHTML=domData.MySpecificYetBriefProperty1[0];
}
PHP:
//Make sure the contents of this file is the json from packDomData. use json_encode in php or JSON.stringify in js
echo file_get_contents("text_file.txt");
var myData = JSON.parse(XMLHttpRequestObject.responseText);
useDomData(myData);
I used to code like you. Here are some tips that have helped turn my coding horror into a fun job:
Use objects with descriptive properties instead of arrays whenever you aren't actually looping through the array - I promise it will save you and others headache! "DomID" is much more flexible than 1, and if you change the order in the array, javascript gods help you that array is everywhere - including however many random text files on your server!
Also use descriptive names for functions
Always return a value from a function instead of using globals whenever possible, even where the result is then used as a nasty global. Trust me.
Never put javascript function names in an ajax call. Use JSON instead and keep the functions and other script in the javascript file where it belongs.
Mysql will save your life!!
Disclaimer - I didn't run this code but it should basically work when you get everything hooked up right.

Context-aware AJAX call in a modular site

Edit: I thought about a possible solution, but I made another question as it is very specific: see AJAX proxy with PHP, is it possible?
A couple of times I've encountered this problem...
I create sites that have a certain degree of modularity. So, it is possible that there are "components" (think of a rough CMS) which carry their own PHP code, CSS, and JavaScript, all dynamically included. Think about a structure like:
{siteroot}/component/datagrid/datagrid.php
{siteroot}/component/datagrid/js/datagrid.js
{siteroot}/component/datagrid/css/datagrid.css
{siteroot}/component/datagrid/ajax/getsomedata.php
Now, the question is: for JavaScript files, and expecially AJAX calls, how do I make them context-aware with the URLs?
For example, if in datagrid.js I want to call siteroot/component/datagrid/ajax/getsomedata.php with AJAX I should write (with JQuery):
$("#ajax").load("siteroot/component/datagrid/ajax/getsomedata.php");
First problem: siteroot changes on different installations. I've managed that by including a general
var codeBase = <? echo json_encode(Config::$siteRoot); ?>
with PHP on every page, from a Config file that can be easily edited for every installation, so I can do with whatever JavaScript something like:
$("#ajax").load(codeBase + "/component/Datagrid/ajax/getsomedata.php");
What do you think of this approach?
Second problem: but I have PHP functions that return to me also the components folder, or the folder of other components. It would be nice to make the whole URL dynamic. This would account also for changes in the structure of the component if I want.
The only solution I've found is to use a .js.php dynamic Javascript. This is very unelegant, and I have to include all the framework in the JavaScript file, like:
<?php
include "../../libs/framework.php"; // get my functions...
$myUrl = Config::$siteRoot . Framework::getComponentAjaxDir("datagrid") . "/getsomedata.php";
?>
$("#ajax").load(<?=json_encode($myUrl)?>);
Another side effect is that I have to know exactly the include the path for framework.php... I don't want this so hard-codedin my ".js.php" file.
Any smart solutions about that?
As nobody answered in a suitable way, I answer to myself to provide a solution I've found out that can be useful.
The key to my solution is simple:
I create an AJAX proxy at a fixed location in my site structure, so I can use codeBase to reference the proxy from JavaScript
I call this proxy with two parameters: plugin and action, which identify a) the plugin folder in which the "real" ajax is and b) the ajax file to use, along with the other params:
$("#...").load( codeBase + "/main/ajax.php?plugin=Datagrid&action=gettable&otherparams"...)
In ajax.php I sanitize the parameters, and use plugin and action to obtain the "real" ajax file:
{serverRoot}/components/{plugin}/ajax/{action}.php
Then i simply include that file in ajax.php
To be honest your problems are realistic options and aren't that bad practice in general quite frankly.
But let's explore this a little further.
What would be the best approach is for you to have 1 main config.php file which you can then specify modules, i.e. your datagrid etc.
You could store all modules in an array variable like so:
$_SITE_PATH = "/var/www/html/";
$_HTTP_PATH = "http://example.com/";
$_MODULES_PATH = $_SITE_PATH."modules/"
$_MODULES = array(
"datagrid"=>$_MODULES_PATH."datagrid/init.php",
"something_else"=>$_MODULES_PATH."something_else/init.php"
);
Each module would have it's own directory with instantiation init.php so that it would load all it required to get going.
This way you could code as you liked and when you needed something (preferably in the header state) do something like this.
global $_MODULES;
require_once($_MODULES["datagrid"]);
Everything will be easily available as and when required without any variable path issues later down the line.

Is there a simple way to get and manipulate nested <div> tags with php

First off, I'm far from awesome with PHP - having only a basic familiarity with it, but I'm looking for a way to manipulate the contents of nested divs with php. This is a basic site for a local non-profit food bank that will allow them to post events for their clientelle.
For example, the file I want to parse and work with has this structure (consider this the complete file though there may be more than 2 entries at any point in time):
<div class="event">
<div class="eventTitle">title text</div>
<div class="eventContent">event content</div>
</div>
<div class="event">
<div class="eventTitle">title2</div>
<div class="eventContent">event content2</div>
</div>
My thoughts are to parse it (what's the best way?), and build a multidimensional array of all div with class="event", and the nested contents of each. However, up to this point all my attempts have ended in failure.
The point of this is allow the user (non-technical food bank admin) to add, edit, and delete these structures. I have the code working to add the structures - but am uncertain as to how I would re-open the file at a later date to then edit and/or delete select instances of the "event" divs and their nested contents. It seems like it should be an easy task but I just can't wrap my head around the search results I have found online.
I have tried some stuff with preg_match(), getElementById(), and getElementByTagName(). I'd really like to help this organization out but I'm at the point where I have to defer to my betters for advice on how to solve the task at hand.
Thanks in advance.
To Clarify:
This is for their website, hosted on an external service by a provider that does not allow them to host a DB or provide ftp/sftp/ssh access to the server for regular maintenance. The plan is to get the site up there once, and from then on, have it maintained via an unsecure (no other options at this point) url.
Can anyone provide a sample php syntax to parse the above html and create a multidimensional array of the div tags? As I mentioned, I have attempted to thumb my way through it, but have been unsuccessful. I know what I need to do, I just get lost in the syntax.
IE: this is what I've come up with to do this, but it doesn't seem to work, and I don't have a strong enough understanding of php to understand exactly why it does not.
<?php
$doc = new DOMDocument();
$doc->load('events.php');
$events = array();
foreach ($doc->getElementsByTagName('div') as $node) {
// looks at each <div> tag and creates an array from the other named tags below // hopefully...
$edetails = array (
'title' => $node->getElementsByTagName('eventTitle')->item(0)->nodeValue,
'desc' => $node->getElementsByTagName('eventContent')->item(0)->nodeValue
);
array_push($events, $edetails);
}
foreach ($events as &$edetails) {
// walk through the $events array and write out the appropriate information.
echo $edetails['title'] . "<br>";
echo $edetails['desc'] . "<br>";
}
print_r($events); // this is currently empty and not being populated
?>
Error:
PHP Warning: DOMDocument::load(): Extra content at the end of the document in /var/www/html/events.php, line: 7 in /var/www/html/test.php on line 4
Looking at this now, I realize this would never work because it is looking for tags named eventTitle and eventContent, not classes. :(
I would use a "database", whether it's an sqlite database or a simple text file (seems sufficient for your needs), and use php scripts to manipulate that file and build the required html to manage the text/database file and display the contents.
That would be a lot easier than using DOM manipulation to add / edit / remove events.
By the way, I would probably look for a sponsor, get a decent hosting provider and use a real database...
If you want to keep using the "php" file you have (which I think is needless complex), the reasons your current code fails are:
1) The load() method for DOMDocument is designed for XML, and expects a well formed file. The work around for this would be to either use the loadHTMLFile() method, or to wrap everything in a parent element.
2) The looping fails as the getElementsByTagName() is looking for tags - so the outermost loop gets 6 different divs in your current example (the parent event, and the children eventTitle and eventContent)
3) The inner loops fail of course, as you're again using getElementsByTagName(). Note that the tag names are all still 'div'; what you're really trying/wanting to search on is the value of 'class' attribute. In theory, you could work around this by putting in a lot of logic using things like hasChildNodes() and/or getAttribute().
Alternatively, you could restructure using valid XML, rather than this weird hybrid you're trying to use - if you do that, you could use DOMDocument to write out the file, as well as read it. Probably overkill, unless you're looking to learn how to use the PHP DOM libraries and XML.
As other's have mentioned, I'd change the format of events.php into something besides a bunch of div's. Since a database isn't an option, I'd probably go for a pipe delimited file, something like:
title text|event content
title2|event content2
The code to parse this would be much simpler, something along the lines of:
<?php
$events = array();
$filename = 'events.txt';
if (file_exists($filename)) {
$lines = file($filename);
foreach ($lines as $line) {
list($title, $desc) = explode('|', $line);
$event = array('title'=>$title, 'desc'=>$desc);
$events[] = $event; //better way of adding one element to an array than array_push (http://php.net/manual/en/function.array-push.php)
}
}
print_r($events);
?>
Note that this code reads the whole file into memory, so if they have too many events or super long descriptions, this could get unwieldy, but should work fine for hundreds, even thousands, of events or so.

Load an external file using Javascript

I would like to load an external file using javascript. I'm planning to add ad codes in the external file and include it using javascript wherever necessary. This will help me to change ad codes easily when the need arises.
Also I believe various third party solutions such as Google Admanager are complex and unnecessary. So I need your suggestion for the same.
Note : The external file may contain PHP / Javascript source.
What I thought was to add something like this ...
document.write("<script type='text/javascript' src='ad1.js'></script>");
What's your opinion ?
Correct me if I'm wrong, but it sounds like you want to display ad codes separate from the content of the page (such as in iframes). Most ad providers don't like this, since the ads displayed won't be relevant to site content.
Another way to do it however (that makes everyone happy) is to use php's include statement and include the external file. This will dump the contents of the page into the current page, so make sure you don't have multiple <html> elements or inaccurate paths.
I wouldn't use document.write, is that would overwrite the content already on the page, thus making your solution quite static. Try this instead:
function addScript(src) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = src;
document.head.appendChild(script);
}
You'll want to make sure that the page has loaded enough that the document.head is defined. You could use an event listener for this.

Inserting output into page after document has been executed

In PHP have a situation where I need the page to be mostly executed, but have an item inserted into the output from that page.
I think output buffering may be of some help, but I can't work out how to implement it in my situation.
My code looks like this:
//this document is part of a global functions file
function pageHeader (){
//I'm using $GLOBALS here because it works, however I would really rather a better method if possible
$GLOBALS['error_handler'] = new ErrorHandler(); //ErrorHandler class sets a function for set_error_handler, which gets an array of errors from the executed page
require_once($_SERVER['DOCUMENT_ROOT'].'/sales/global/_header.php');
//I would like the unordered list from ->displayErrorNotice() to be displayed here, but if I do that the list is empty because the list was output before the rest of the document was executed
}
function pageFooter (){
$GLOBALS['error_handler'] ->displayErrorNotice(); //this function displays the errors as an html unordered list
include($_SERVER['DOCUMENT_ROOT']."/sales/global/_footer.php");
}
Most pages on the site include this document and use the pageHeader() and pageFooter() functions. What I am trying to achieve is to put an unordered list of the PHP generated errors into an HTML list just at a point after _header.php has been included. I can get the list to work as intended if I put it in the footer (after the document has been executed), but I don't want it there. I guess I could move it with JS, but I think there must be a PHP solution.
UPDATE
I'm wondering whether a callback function for ob_start() which searches the buffer by regex where to put the error list, and then inserts it will be the solution.
UPDATE 2 I have solved the problem, my answer is below. I will accept it in 2 days when I am allowed.
Worked it out finally. The key was to buffer the output, and search the buffer for a given snippet of html, and replace it with the unordered list.
My implementation is like this:
function outputBufferCallback($buffer){
return str_replace("<insert_errors>", $GLOBALS['error_handler']->returnErrorNotice(), $buffer);
}
function pageHeader (){
ob_start('outputBufferCallback');
//I'm using $GLOBALS here because it works, however I would really rather a better method if possible
$GLOBALS['error_handler'] = new ErrorHandler(); //ErrorHandler class sets a function for set_error_handler, which gets an array of errors from the executed page
require_once($_SERVER['DOCUMENT_ROOT'].'/sales/global/_header.php');
echo '<insert_errors>'; //this snippet is replaced by the ul at buffer flush
}
function pageFooter (){
include($_SERVER['DOCUMENT_ROOT']."/sales/global/_footer.php");
ob_end_flush();
}
If I'm getting this right, you're trying to insert some calculated code/errors between the header and footer. I'm guessing that the errors are being totalled/summed up at the very end of the page and would be completed after the page footer.
If this is true, I can't think of anyway to do this with pure php. It can only run through a page once, and cannot double back. What you can do is create an element after the footer and move it using javascript to the area where you want to display it. This would be the easiest way I would think. You can do this easily with jquery.
I can explain further if I am on the right track, but I'm not 100% sure what you're asking yet...
The jquery command you would use is .appendTo().

Categories