I am currently developing a website and i need that the pages loads dynamically based on what actions the user does.
Example: If the user clicks on the button 'Settings' an ajax function will load from an external page the code and will put into the div with tag 'settings'.
This is the code i use to make the Ajax request:
function get_page_content(page, target_id)
{
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById(target_id).innerHTML = xmlhttp.responseText;
// After getting the response we have to re-apply ui effects or they
// won't be available on new elements coming from request.
$('button').sb_animateButton();
$('input').sb_animateInput();
}
}
xmlhttp.open('GET', 'engine/ajax/get_page_content.php?page=' + page, true);
xmlhttp.send();
}
And this is where the ajax results will be put by first snippet:
<div id="settings_appearance">
</div>
The code is called from a function here:
<div class="left_menu_item" id="left_menu_settings_appearance" onclick="show_settings_appearance()">
Appearance
</div>
And this is the html that the ajax function will put into the settings_appearance div:
<script type="text/javascript">
$(function()
{
$('#upload_hidden_frame').hide();
show_mybrain();
document.getElementById('avatar_upload_form').onsubmit = function()
{
document.getElementById('avatar_upload_form').target = 'upload_hidden_frame';
upload_avatar();
}
});
</script>
<div class="title">Appearance</div>
<iframe id="upload_hidden_frame" name="upload_hidden_frame" src="" class="error_message"></iframe>
<table class="sub_container" id="avatar_upload_form" method="post" enctype="multipart/form-data" action="engine/ajax/upload_avatar.php">
<tr>
<td><label for="file">Avatar</label></td>
<td><input type="file" name="file" id="file" class="file_upload" /></td>
<td><button type="submit" name="button_upload">Upload</button></td>
</tr>
<tr>
<td><div class="hint">The image must be in PNG, JPEG or GIF format.</div></td>
</tr>
</table>
I would like to know if there's a way to execute also the javascript code that's returned by the ajax function (upload button in the returncode doesn't work because of this) and if it's possible to apply some customized ui effects i build that are loaded with the main page.
Thanks for helping.
P.S. This is the script that applies the UI effects:
<script type="text/javascript">
// UI effects
$(document).ready(function()
{
$('button').sb_animateButton();
$('input').sb_animateInput();
$('.top_menu_item').sb_animateMenuItem();
$('.top_menu_item_right').sb_animateMenuItem();
$('.left_menu_item').sb_animateMenuItem();
});
</script>
P.P.S. ui effects are not applied to html elements (such as input and buttons) returned by the Ajax function. I used a little workaround by applying again ui-effects after ajax function returns the response. Probably there's another way of doing it... the same that will help me solve this problem.
If you use the jQuery ajax function (or the simplified jQuery get function), and set the datatype to html, then jQuery will evaluate the contents of any script tags included in the results.
Your $.get call would look something like:
$.get('engine/ajax/get_page_content.php?page=' + page,null,function(result) {
$("#"+target_id).html(result); // Or whatever you need to insert the result
},'html');
I also suggest you don't, but after loading the content in the div, pass the element ID to this function. This will even handle document.write
function do_JS(e){
var Reg = '(?:<script.*?>)((\n|.)*?)(?:</script>)';
var match = new RegExp(Reg, 'img');
var scripts = e.innerHTML.match(match);
var doc = document.write;
document.write = function(p){ e.innerHTML = e.innerHTML.replace(scripts[s],p)};
if(scripts) {
for(var s = 0; s < scripts.length; s++) {
var js = '';
var match = new RegExp(Reg, 'im');
js = scripts[s].match(match)[1];
js = js.replace('<!--','');
js = js.replace('-->','');
eval('try{'+js+'}catch(e){}');
}
}
document.write = doc;
}
A better solution will be to add a function that you can call at the end of the update to show the effects.
I recommend you not to, it might lead to a security breach.
If you already use jquery, use it's ajax functionallity instead of the raw one.
When the ajax request completes execute the animation code (just leave it on the page that does the ajax call).
In your content HTML (the one you get from the call) make a common javascript function for every content page, that will be called every time the content is loaded on the master page...
the function name will be something like: loadContentJavascript() {}
and this function is in charge of loading all the functionalities that it will be load on a onload event.
Related
I have been using Ajax with JavaScript. All such calls are made with a mouse hover on a particular text. The mouse hovering shows the JavaScript method being called at the bottom of the status bar. I have seen at some websites where this is totally masked. No display at the status bar.
Is it possible to do it in JavaScript, without going for jQuery like frameworks?
The sample code is given below.
JavaScript Code
<script language="javascript">
function doAjaxSearch()
{
//1. Get the Input value
var inputTxt = document.getElementById('inputTxt').value;
//2. Get XMLHttpRequest (XHR)
var xhttp = getXMLHttpRequest(); //separate method gives a 'xhttpr'
var url = "getTasks";
var params = "input="+inputTxt;
var httpMethod = 'GET';
xhttp.onreadystatechange = function()
{
if(xhttp.readyState==4 && xhttp.status==200)
{
console.log(xhttp.responseText);
//prepare the response
prepareOutput(xhttp.responseText);
}
};
xhttp.open(httpMethod, url+"?"+params, true);
xhttp.send();
}
</script>
HTML Code
//rest of the code omitted for brevity..
<input type=text name="inputTxt" id="inputTxt" size=20/>
Search
I could always see that the bottom left of the status bar showing the text "javascript:doAjaxSearch()".
I want to hide this display in the status bar of the browser, in the plain JavaScript itself. Any help would be appreciated.
Adding event listeners to javascript elements will not show a message in the status bar when hovering over them:
function searchEventHandler(ev)
{
// do something
}
el.addEventListener('click', searchEventHandler);
And can be removed later, if necessary with:
el.removeEventListener('click', searchEventHandler);
EDIT:
Credit to RDeving for the improvement for removing event handlers as well.
UPDATE:
You see the status message because you are using <a> tags to invoke your javascript function. Change this to a <span> and add an event handler as outlined above to execute your click event.
<script>
function searchEventHandler(ev)
{
// do something
}
var search = document.getElementById('search');
search.addEventListener('click', searchEventHandler);
</script>
<span id='search' style='cursor: pointer;'>Search</span>
I wonder how it is possible that using javascript, images can be loaded asynchronously by changing the src of the img element after the page has been loaded. I thought that AJAX is for things like that(getting data from server without refreshing the page). Please clarify why it is working that way. The images are on server side, so I thought that i should refresh the page before the result will be visible.
Here is a sample code:
<!DOCTYPE html>
<html lang="en">
<head>
<script>
var photos = ["baloon", "game", "cliff"];
function changePhoto() {
var input=document.getElementById("ph1");
var iValue=input.value.trim();
for(var tmp in photos) {
if(photos[tmp] === iValue){
var img=document.getElementById("photo");
img.setAttribute("src", "img/"+iValue+".jpg");
}
}
}
</script>
</head>
<body>
<input class="form-control" id="ph1" type="text" onkeyup="">
<p>Photo: <span id="txtHint" onclick="changePhoto()"></span></p>
</div>
<div class="container" id="photocontainer">
<img id="photo">
</div>
</body>
</html>
The user agent simply sends a GET request in response to the changing of the src attribute, the same that is done when a page loads initially.
AJAX is a technology that allows for asynchronous requests in JavaScript on the client. Browsers can make any requests they want at any time, as in this case, but without AJAX that couldn't be done in client-side code loaded by a website.
For example, I just changed the src property of an element in a page through Chrome Developer Tools and watched the GET request execute.
What you're doing in your code is not Ajax. Is simple javascript.
To make this work with Ajax you need a server side aplication that actually renders the image or get the contents from an existing file, and after that you show your loaded file on the browser.
Look for a jQuery ajax calls.
On the return of the call you can put your code.
Like this:
$.ajax({
url: "SomeUrl/SomeMethod/"
})
.done(function (response) {
//Do stuff here with the response to show the image
});
When you change src atrribute of an img element browser automatically starts downloading this image asynchronously.
Your code is almost ok. You iterate through array incorrectly.
You can try doing it this way instead:
var photos = ["baloon", "game", "cliff"];
function changePhoto() {
var input=document.getElementById("ph1");
var iValue=input.value.trim();
if(photos.indexOf(iValue) > -1) {
var img=document.getElementById("photo");
img.setAttribute("src", "img/"+iValue+".jpg");
}
}
Iterating through array
You can iterate through array for example like this:
for(var i=0; i<photos.length; i++) {
var photo = photos[i];
//...
}
or like this:
for(var k in Object.keys(photos)) {
var photo = photos[k];
//...
}
Basically I'm trying to build a functionality in which I only really edit my index.php, I got a lot of other php files with just a form in them or just a few lines of text.
What I want to achieve is to load these other files in the contentwrapper of my index.php.
I have been successfull on doing this with an iframe and with a html <object>.
The problem with these though is that first of all they load an all new #document in the DOM, and also my webpage has no set height so height: 100% won't work on those and I would get these ugly scrollbars and stuff.
after searching a lot on SO today I found a few interesting solutions which I combined, this is what I'm trying now:
<script type="text/javascript" href="js/csi.min.js"></script>
<script type="text/javascript">
function load_content(target){
document.getElementById('contentwrapper').innerHTML='<div data-include="' + target + '" ></div>';
return false;
}
</script>
now you may question what data-include is, this is a very nice workaround I found on SO.
THIS is what it does, it basically calls a .js file that replaces the containing element with the data that is in the file (target in the above example)
I call this functionality like this:
Update profile
It works as far as adding this to the DOM:
<div id="contentwrapper">
<div data-include="update.php" ></div>
</div>
but besides that it does nothing, I think that it doesn't call the .js file for the data-include attribute. But I can't find a solution for this nowhere.
(BTW: the data-include attribute does work if I put it in a tag manually without javascript)
I Hope I didn't overexplain the situation, and I thank everyone that tries to help in advance!
The csi.js script is only run once after the page is loaded. It just goes over all the elements with the data-include attribute and runs the fragment function.
<script type="text/javascript">
function fragment(el, url) {
var localTest = /^(?:file):/,
xmlhttp = new XMLHttpRequest(),
status = 0;
xmlhttp.onreadystatechange = function() {
/* if we are on a local protocol, and we have response text, we'll assume
* things were sucessful */
if (xmlhttp.readyState == 4) {
status = xmlhttp.status;
}
if (localTest.test(location.href) && xmlhttp.responseText) {
status = 200;
}
if (xmlhttp.readyState == 4 && status == 200) {
el.outerHTML = xmlhttp.responseText;
}
}
try {
xmlhttp.open("GET", url, true);
xmlhttp.send();
} catch(err) {
/* todo catch error */
}
}
function load_content(target){
fragment(document.getElementById('contentwrapper'), target);
return false;
}
</script>
Then call it like this:
Update profile
So, the only thing you need is to call this function for the new created element. Pass the DOM element and the url to this function and it will take care of loading the contents of the requested resource in the corresponding element.
May we assume that you followed this advise from the repository: The only caveat is Chrome, which restricts access to local files via AJAX. To resolve this, simply add --allow-file-access-from-files to your Chrome runtime.
If you didn't, and you're using Chrome, then this stands out to me, and you didn't indicate that you'd corrected the security block that Chrome puts in place.
The csi.js only runs on window.onload.
Try
<a href="#" onclick="function() {load_content('update.php'); window.onload(); }">
Update profile</a>
I'm writing some code that will get executed before the DOM loads, basically, using Modernizr to get scripts. Now my issue is that I want to show a loading animation if the DOM loads and the scripts are still loading.
Modernizr is executed in the head. If I put the code to use document.getElementById in the head also, error is thrown because the DOM hasn't loaded. Now I have no idea how to solve this.
Here is the code I have so far:
<head>
<script>
var FileManager = {
IsLoading = false;
LoadRequiredFiles: function (config) {
config = config || {};
this.OnLoading = config.onLoadingCallback;
this.OnComplete = config.onCompleteCallback;
this.IsLoading = true;
if (this.OnLoading) {
this.OnLoading();
}
var self = this;
Modernizr.load([{
load: '/jquery.min.js',
complete: function () {
if (self.OnComplete) {
self.OnComplete();
}
self.IsLoading = true;
}
},
]);
}
};
var globalLoadingId = 'globalLoader';
FileManager.LoadRequiredFiles({
onLoadingCallback: function () {
document.getElementById(globalLoadingId).style.display = 'block';
},
onCompleteCallback: function () {
document.getElementById(globalLoadingId).style.display = 'none';
}
});
</script>
I used to execute this code below the <body> tag, and it worked. Now I moved it into the <head>. So I used to pass 2 callbacks to it. Now I'd rather attach events to it and handle them in the body (assuming thats where the DOM is loaded).
What I'd like to do:
<head>
<script>
FileManager.LoadRequiredFiles();
</script>
</head>
<body>
<script>
//Bind the event, not sure if this is even possible in javascript.
FileManager.OnCompleted += fileManagerCompleted;
fileManagerCompleted()
{
document.getElementById(globalLoadingId).style.display = 'none';
}
if(FileManager.IsLoading)
{
document.getElementById(globalLoadingId).style.display = 'block';
}
</script>
</body>
The page is your canvas for display. You can't show anything before it loads. It sounds more like you want a very small page to load (quickly) where you could display your progress and then your code could dynamically load/display the rest of the page with ajax calls and javascript showing progress as it goes. That's the only way to get out in front of the rest of the page load that I know of.
The only entirely reliable way to run a script that manipulates the DOM is to use the body onload event. (window.onload is popular, but not quite 100% reliable.)
There are some browsers that implement a onDocumentReady event that can be kind-of-sort-of faked in IE, but I don't recommend its use.
Using getElementById will not, by itself, throw an error if used in the head. You might be causing an error because you aren't checking the returned value, which will be null if an element with the specified id wasn't found, e.g.
var el = document.getElementById('foo');
if (el) {
// do somethig with el
} else {
// el wasn't found
}
Your problem is how to display the image only if the scripts are still loading and the page is visible. The simple answer is don't use client-side script loading, do it at the server. :-)
If you want to persist with script loading, add a class to the loading image, say "hideOnLoad". Have a callback from the last script load that sets the rule to "display: none" (just create and add style sheet with that one rule using script).
Now you just include the loading image as the first element in the body with a class of "hideOnLoad", knowing that when scripts have finished loading they will hide the image regardless of whether it (or any other element with the same class) existed at the time or not.
We have a form with five <input type="file"/> elements that is in production and working great. We get request timeouts and MaxRequestLength exceeded errors on occasion. To prevent these errors, I planned to write some Javascript to upload the files one-at-a-time instead of all at once. Here is how I planned on doing this...
On document.ready, inject a hidden iframe into page
Change the <form> to target the iframe
Disable all elements on the form (which prevents them from being POSTed)
Enable one file-upload at a time and submit the form
Wait for the response from the server
When server response is printed into iframe, start the next upload
When all uploads are done, refresh the page, which will invoke some server-side logic that populates a grid.
My problem is with number 5. Normally I think I could figure this out no problem, but I am just having one of those days where my brain is on strike. Here is my code thus far...
$(function() {
$("<iframe/>").attr("src", "test.htm").attr("name", "postMe").hide().appendTo("body");
$("form").attr("target", "postMe").submit(function(e) {
e.preventDefault();
$("#btnSubmit").attr("disabled", "disabled").val("Please Wait, Files are Uploading");
for(var i = 1; i < 6; i++) {
$("input[type=file]").attr("disabled", "disabled");
$("#FileUpload" + i).removeAttr("disabled");
$("form")[0].submit();
// HELP!!!
// How do I wait for server before next iteration?
}
location.reload(true);
});
});
What kind of construct do I need here in order to "wait" for the server response before kicking off the next upload?
I've had a lot of success lately using Uploadify--it's very configurable, free, and allows for multiple-uploads. It also provides the option for callback functions allowing you to really configure it any way you want.
http://www.uploadify.com/
I think you should listen for iframe's load event and perform input's switching in the handler. I completed with my own uploader today and this solution worked for me.
Just FYI: jquery.forms plugin is all about making ajax form submitions. I use this plugin to submit a form (such as a file upload) in a separate iframe which the plugin takes care of automatically, and gives you a nice callback when completing.
This way most work for you is done.
http://jquery.malsup.com/form/
It can be done with the help of jQuery's queue method and load event.
<!DOCTYPE HTML>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script>
//here's an upload script
(function($){
//make 'em accessible within the scope
var $iframe, $form;
$(document).ready(function(){
//create 'em only once, but use 'em many times
$iframe = $('<iframe name="iframe" id="iframe" style="display:none"></iframe>').appendTo('body');
$form = $('<form method="post" enctype="multipart/form-data" target="iframe" style="display:none"></form>').appendTo('body');
});
var iframeUpload = $({});
$.iframeUpload = function(s){
iframeUpload.queue(function(next){
//as we only wanna this new event
$iframe.load(function(){
//we must unbind the old one
$iframe.unbind('load');
//success or error, the question is up to you
s.success();
//but remember to remove or replace the old stuff
$form.find('input').remove();
next();
});
$form.attr('action', s.url).append(s.file).submit();
});
};
})(jQuery);
//and this is how to use the script
(function($){$(document).ready(function(){
$('input[type="submit"]').click(function(){
$('input[type="file"]').each(function(){
$.iframeUpload({
url: 'http://example.com/upload.php',
file: this,
success: function(){
console.log('uploaded');
}
});
});
});
})})(jQuery);
</script>
</head>
<body>
<!-- here are multiple files -->
<input type="file" name="file" />
<input type="file" name="file" />
<input type="file" name="file" />
<!-- to upload -->
<input type="submit" />
</body>
</html>
I was able to do this, by starting with the code at A Strategy for Handling Multiple File Uploads Using Javascript. That code uses an XMLHttpRequest for each file, but actually doesn't check the result from the server. I modified it to wait for the result from the server, sequentially, as follows:
var fileNumber = 0
var fileList = [] // see the code linked above for how to handle the fileList
var resultPane = document.getElementById('resultpane') // a textarea box
sendNext = function() {
if (fileNumber >= fileList.length) {
resultPane.value += 'Done uploading '+fileNumber+' files\n'
return 0
}
var formData = new FormData()
var request = new XMLHttpRequest()
request.onreadystatechange = function() {
if (request.readystate == XMLHttpRequest.DONE) {
resultPane.value += request.responseText // show whatever the server said about each file
sendNext() // and send the next file
}
}
formData.set('file', fileList[fileNumber])
request.open('POST', 'https://example.com/upload-receiver')
request.send(formData)
resultPane.value += 'Sending file number '+fileNumber+'\n'
fileNumber++
}