I am trying to create an application that will show, and periodically change, a paragraph of text (like a news article or similar).
I want the data to come from an xml file so other people can add stories/remove old stories etc.
I'm trying to get my JavaScript to populate a single html field with data from an xml file. Then after a given time, for now we'll say 4 seconds, it will change to the next piece of data.
Below is a very crude version of what I've been trying to do:
HMTL:
<head>
<script src="script.js"></script>
</head>
<body>
<div id="text"></div>
</body>
XML:
<document>
<text>one</text>
<text>two</text>
<text>three</text>
</document>
JavaScript:
var timer = setInterval(addText,4000);
var xhttp = new XMLHttpRequest();
xhttp.onreadystaechange = function() {
if(this.readyState == 4 && this.status == 200) {
addText(this);
}
};
function addText(xml) {
var xmlDoc = xml.responseXML;
var count = 0;
var max = xmlDoc.GetElementsByTagName("text");
document.getElementById("text").innerHTML =
xmlDoc.getElementByTagName("text")[count].childNodes[0].nodeValue;
if (count < max.length) {
count++;
} else {
count = 0;
}
}
xhttp.open("GET", "XMLFile.xml",true);
xhttp.send();
The current problem I am experiencing is that the first xml field populates successfully, but then I get an error saying "Unable to get property 'responseXML' of undefined or null reference".
Ideally what I'd also like is for the xml document to be opened everytime the function occurs, so the application doesn't have to be restarted if extra data is added to the xml file - if that makes sense (and is possible)
You can place addText in the scope of onreadystatechange handler. Something like this.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
var xmlDoc = this.responseXML;
var count = 0;
var xText = xmlDoc.getElementsByTagName("text");
var max = xText.length;
var docText = document.getElementById("text");
function addText() {
//docText, xText and count are available from parent scope
docText.innerHTML =
xText[(count++) % max].childNodes[0].nodeValue;
}
var timer = setInterval(addText,4000);
}
};
xhttp.open("GET", "XMLFile.xml",true);
xhttp.send();
This is a tangent from the question here:
Returning value to Javascript from PHP called from XMLHttpRequest
I am adding an "image upload" button to my AjaxChat. I am using an XMLHttpRequest to send the image to the server, where I run a PHP script to move it to my images folder. Below is the Javascript function in charge of opening the XMLHttpRequest connection and sending the file:
function uploadImage() {
var form = document.getElementById('fileSelectForm');
var photo = document.getElementById('photo');
var uploadButton = document.getElementById('imageUploadButton');
form.onsubmit = function(event) {
event.preventDefault();
// Update button text
uploadButton.innerHTML = 'Uploading...';
//Get selected files from input
var files = photo.files;
// Create a new FormData object
var formData = new FormData();
// Loop through selected files
for (var i = 0; files.length > i; i++) {
var file = files[i];
// Check file type; only images are allowed
if (!file.type.match('image/*')) {
continue;
}
// Add file to request
formData.append('photo', file, file.name);
}
// Set up request
var xhr = new XMLHttpRequest();
// Open connection
xhr.open('POST', 'sites/all/modules/ajaxchat/upload.php', true);
// Set up handler for when request finishes
xhr.onload = function () {
if (xhr.status === 200) {
//File(s) uploaded
uploadButton.innerHTML = 'Upload';
var result = xhr.responseText;
ajaxChat.insertText('\n\[img\]http:\/\/www.mysite.com\/images' + result + '\[\/img\]');
ajaxChat.sendMessage();
} else {
alert('An error occurred!');
}
form.reset();
};
// Send data
xhr.send(formData);
}
}
Here is upload.php:
<?php
$valid_file = true;
if($_FILES['photo']['name']) {
//if no errors...
if(!$_FILES['photo']['error']) {
//now is the time to modify the future file name and validate the file
$new_file_name = strtolower($_FILES['photo']['tmp_name']); //rename file
if($_FILES['photo']['size'] > (1024000)) { //can't be larger than 1 MB
$valid_file = false;
}
//if the file has passed the test
if($valid_file) {
//move it to where we want it to be
move_uploaded_file($_FILES['photo']['tmp_name'], '/var/www/html/images'.$new_file_name);
$message = $new_file_name;
exit("$message");
}
}
}
?>
I currently have the multiple image upload disabled, so the "Loop through selected files" only executes once.
The upload worked for a little bit on my PC, but then I tried uploading an image from my phone. When I did so, the entire server (and my browser) crashed, presumably due to an infinite loop somewhere. Every time I close my browser and log back in, or restart the server, or restart my computer, it hangs and eventually crashes again (on my PC or on my phone). I have been unable to find the script that is causing the issue. I get the feeling it's right under my nose. Does anyone see the problem? If you need the HTML form code then I can provide that, but I don't think it's necessary.
I want to upload a video file using PHP and show the progress of the upload via an Progress Bar. But this is more difficult like i thought and i tried to put the pieces ive found together but unfortunately i didnt found a working piece of code that has the needed php, ajax and html code all together, so ive tried to put different pieces together.
My Code functions nearly completely. The only thing is, that the current process of the file upload, which i've got in percent, is loaded by my javascript only AFTER the process has ended, and not from the beginning.
Here is my PHP Code:
function file_get_size($file) {
//open file
$fh = fopen($file, "r");
//declare some variables
$size = "0";
$char = "";
//set file pointer to 0; I'm a little bit paranoid, you can remove this
fseek($fh, 0, SEEK_SET);
//set multiplicator to zero
$count = 0;
while (true) {
//jump 1 MB forward in file
fseek($fh, 1048576, SEEK_CUR);
//check if we actually left the file
if (($char = fgetc($fh)) !== false) {
//if not, go on
$count ++;
} else {
//else jump back where we were before leaving and exit loop
fseek($fh, -1048576, SEEK_CUR);
break;
}
}
//we could make $count jumps, so the file is at least $count * 1.000001 MB large
//1048577 because we jump 1 MB and fgetc goes 1 B forward too
$size = bcmul("1048577", $count);
//now count the last few bytes; they're always less than 1048576 so it's quite fast
$fine = 0;
while(false !== ($char = fgetc($fh))) {
$fine ++;
}
//and add them
$size = bcadd($size, $fine);
fclose($fh);
return $size;
}
$filesize = file_get_size('remote-file');
$remote = fopen('remote-file', 'r');
$local = fopen('local-file', 'w');
$read_bytes = 0;
while(!feof($remote)) {
$buffer = fread($remote, 2048);
fwrite($local, $buffer);
$read_bytes += 2048;
//Use $filesize as calculated earlier to get the progress percentage
$progress = min(100, 100 * $read_bytes / $filesize);
fwrite(fopen('files/upload/progress.txt', 'w'), $progress);
//you'll need some way to send $progress to the browser.
//maybe save it to a file and then let an Ajax call check it?
}
fclose($remote);
fclose($local);
This is my Javascript Code:
function main()
{
var pathOfFileToRead = "files/upload/progress.txt";
var contentsOfFileAsString = FileHelper.readStringFromFileAtPath
(
pathOfFileToRead
);
document.body.innerHTML = contentsOfFileAsString;
}
function FileHelper()
{}
{
FileHelper.readStringFromFileAtPath = function(pathOfFileToReadFrom)
{
var request = new XMLHttpRequest();
request.open("GET", pathOfFileToReadFrom, false);
request.send(null);
var returnValue = request.responseText;
return returnValue;
}
}
main();
function progressBarSim(al) {
var bar = document.getElementById('bar-fill');
var status = document.getElementById('status');
status.innerHTML = al+"%";
bar.value = al;
al++;
var sim = setTimeout("progressBarSim("+al+")",1000);
if(al == 100){
status.innerHTML = "100%";
bar.value = 100;
clearTimeout(sim);
var finalMessage = document.getElementById('finalMessage');
finalMessage.innerHTML = "Process is complete";
}
}
var amountLoaded = 0;
progressBarSim(amountLoaded);
The Progressbar does currently work over an Timer, because the main() function doesnt read the content of the "progress.txt" from the beginning but only at the end. so i would like to have some help to combine progressBarSim with main().
*Edit: * I have found a working piece of code: http://www.it-gecko.de/html5-file-upload-fortschrittanzeige-progressbar.html and am using that now.
Here is a ajax function for modern browsers:
//url,callback,type,FormData,uploadFunc,downloadFunc
function ajax(a,b,e,d,f,g,c){
c=new XMLHttpRequest;
!f||(c.upload.onprogress=f);
!g||(c.onprogress=g);
c.onload=b;
c.open(e||'get',a);
c.send(d||null)
}
more about this function https://stackoverflow.com/a/18309057/2450730
here is the html
<form><input type="file" name="file"><input type="submit" value="GO"></form>
<canvas width="64" height="64"></canvas>
<canvas width="64" height="64"></canvas>
<pre></pre>
you can add more fields inside the form and you don't need to change anything in the javascript functions. it always sends the whole form.
this is the code to make this ajax function work
var canvas,pre;
window.onload=function(){
canvas=document.getElementsByTagName('canvas');
pre=document.getElementsByTagName('pre')[0];
document.forms[0].onsubmit=function(e){
e.preventDefault();
ajax('upload.php',rdy,'post',new FormData(this),progressup,progressdown)
}
}
function progressup(e){
animate(e.loaded/e.total,canvas[0],'rgba(127,227,127,0.3)')
}
function progressdown(e){
animate(e.loaded/e.total,canvas[1],'rgba(227,127,127,0.3)')
}
function rdy(e){
pre.textContent=this.response;
}
this is the animation that moves the circular canvas progress bar
function animate(p,C,K){
var c=C.getContext("2d"),
x=C.width/2,
r=x-(x/4),
s=(-90/180)*Math.PI,
p=p||0,
e=(((p*360|0)-90)/180)*Math.PI;
c.clearRect(0,0,C.width,C.height);
c.fillStyle=K;
c.textAlign='center';
c.font='bold '+(x/2)+'px Arial';
c.fillText(p*100|0,x,x+(x/5));
c.beginPath();
c.arc(x,x,r,s,e);
c.lineWidth=x/2;
c.strokeStyle=K;
c.stroke();
}
you can extend this function with some nice bounce effect on initializzation or on progresschange.
http://jsfiddle.net/vL7Mp/2/
to test i would just simply use a upload.php file like that
<?php
print_r(array('file'=>$_FILE,'post'=>$_POST));
?>
test it with chrome first... then apply the necessary changes to use it with older browsers... anyway this code should work with all the newest browsers now.
i understand that this functions are not simple to understand so ...
if you have any questions just ask.
maybe there are some syntax error or something is missing... because i just copied the whole functions and applied some changes on the fly.
some other useful functions:
display a readable filesize:
https://stackoverflow.com/a/20463021/2450730
convert MS to time string or a time string to MS
function ms2TimeString(a){
var ms=a%1e3>>0,s=a/1e3%60>>0,m=a/6e4%60>>0,h=a/36e5%24>>0;
return (h<10?'0'+h:h)+':'+(m<10?'0'+m:m)+':'+(s<10?'0'+s:s)+'.'+(ms<100?(ms<10?'00'+ms:'0'+ms):ms);
}
function timeString2ms(a){
var ms=0,b;
a=a.split('.');
!a[1]||(ms+=a[1]*1);
a=a[0].split(':'),b=a.length;
ms+=(b==3?a[0]*3600+a[1]*60+a[2]*1:b==2?a[0]*60+a[1]*1:s=a[0]*1)*1e3;
return ms
}
A simple PAD LEFT function
function padL(a,b,c){//string,length=2,char=0
return (new Array(b||2).join(c||0)+a).slice(-b);
}
ps.i'm also working on a conversion progress bar. if you are intrested i can show you my progress.
So, I'm pulling a query from a php file using javascript, then publishing it to another javascript that will then put another php query in another text area.
In other words:
[input text area 1] -> [javascript live search] -> [Query results]
[Query results] -> [onClick event] -> [Load results in text area 2]
The idea is that live searches in one textarea will come out with its approximate match in another live.
However, when I try to load the data in the second textarea it comes out as raw data. I'm confused on how to view it properly.
HTML:
The first text area is the input with a function to call a script, which is here:
function showResult(str) {
if (str.length == 0) {
document.getElementById("livesearch").innerHTML = "";
document.getElementById("livesearch").style.border = "0px";
return;
}
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("livesearch").innerHTML = xmlhttp.responseText;
document.getElementById("livesearch").style.border = "1px solid #000";
}
}
xmlhttp.open("GET", "ajax-search.php?keyword=" + str, true);
xmlhttp.send();
}
The php returns the result:
echo '<li onclick="grabID('.$row['dir_id'].')" >'.$row['eng_dir'].'</li><br />';
Which then initiates a clicked event:
function grabID(num){
xmlhttp.open("GET","ajax-result.php?result="+num,true);
xmlhttp.send();
document.getElementById("output").innerHTML="Something here?!?!?!";
}
Once again the results from the other php are returned correctly. The problem is that because it's a loop, it returns a lot of results instead of just 1. I just want the 1 result that matches the ID of the previous search.
I have a script (javascript) that works in firefox but not in chrome or IE. I opened chromes debug console to find the problem. No errors are reported and the code works perfectly. Running it again with the console closed does not work again.
I verified that the version of the script is correct (not old and cached). The console does not report any warnings or errors.
I tried putting in simple logging that writes to a div at the bottom of the page - no information.
(in the debug console it works - including logging info in the div).
The function is the callback after an XMLHttpRequest is made to the server.
I verified that the php script is called by including error_log calls. The error_log shows the return value correctly. A page refresh also show the row has been deleted.
It appears as if the function removeRow() is never called unless the console is open. (method or reserved words conflict??) Tried changing the function name to delRow (including callback) - still not working.
All other Ajax calls seem to work fine.
A Code snippet follows:
var pos = 0;
var xhr;
function eraseRow() {
var myImage = this;
var fullid = myImage.id;
// split row no and record id eg 5_1223 => row=5 and recordid=1223
var idComponents = fullid.split("_");
if (idComponents.length > 1) { // check if image has complete row info
rowid = idComponents[1]; // extract row number from id
pos = parseInt(idComponents[0]);
xhr = new XMLHttpRequest(); // only support IE8 or +
xhr.onreadystatechange = removeRow;
xhr.open("GET","valid_del.php$delrow="+rowid;
xhr.send(null);
}
}
function removeRow() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var err = document.getElementById("errormsg");
var str = xhr.responseText;
err.innerHTML = "Server returned "+str;
if (str === "go-ahead") {
var table = document.getElementById("tableid");
table.deleteRow(pos);
}
}
}
}
PHP (valid_del.php):
<?php
include(funclib.php);
if (isset($_GET['delrow']) && strlen($_GET['delrow'] > 0) {
$recid = $_GET['delrow'];
$db = createDbConn(); // function that connects to mysql server db
$result = $db->query("delete from doclibrary where doc_id='$recid'");
if ($result===true) {
echo 'go-ahead';
error_log('Script successful - returns go-ahead',0);
} else {
echo 'stop';
error_log('Script not successful - returns stop',0);
}
$db->close();
} else {
echo 'stop';
error_log('Script not given record id - returns stop',0);
}
?>
I think the DOM is not ready, try to add your code calls into window.onload, or in $(document).ready if you are using JQuery.