I have a page that generates n links in a foreach loop:
...some html and php code
<?php foreach ($tables as $table):?>
... some elements generated ...
<td><a onclick="setPortalId(<?php echo $table['id']?>);$('#fileupload').trigger('click');" class="btn-success btn-sm"><i class="icon-plus white bigger-125"></i>Add / Change</a></td>
... another elements ...
<?php endforeach;?>
As you can see, the onclick event in each link execute 2 js functions,the first sets a js var with the php value $table['id'] because i will need this value to determine my zend route and the last function trigges the input fileUpload of the type file:
<input id="fileupload" type="file" class="hidden" multiple="" name="files[]">
and in the scripts i have this:
<script src="/js/vendor/jquery.ui.widget.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="/js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="/js/jquery.fileupload.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="//netdna.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script>
var idPortal;
function setPortalId(valor) {
idPortal = valor;
}
/*jslint unparam: true */
/*global window, $ */
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
var url = '/precos/upload/id/'+ idPortal;
$('#fileupload').fileupload({
url: url,
dataType: 'json',
done: function (e, data) {
$.each(data.result.files, function (index, file) {
$('<p/>').text(file.name + " adicionado").appendTo('#files');
window.alert(file.name + " Adicionado.");
});
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .progress-bar').css(
'width',
progress + '%'
);
}
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});
</script>
My question is how I can get the idPortal of the clicked link in the last self-invoqued funtion?Any sugestions?
This is horrible design. You should try to keep your JS as unobtrusive as possible, ie. don't use event handler attributes like onclick. Attach the event handler via JS. There are times when this is impractical but I don't see any evidence that that is the case here.
What I would do on the PHP side is to add some classes and a data attribute that I can hook in to from JS:
<?php foreach ($tables as $table):?>
<td>
<a data-portal-id="<?php echo $table['id']?>" class="btn-success btn-sm btn-upload"><i class="icon-plus white bigger-125"></i>Add / Change</a>
</td>
<?php endforeach;?>
Now on the JS side I would simply read the data-portal-id from the clicked link, use it to set the URL on the file uploader, and then trigger the click to begin the upload workflow:
$(selectorForTheTable).on('click', 'a[data-portal-id].btn-upload', function (e) {
// pull the portalId from the link's data-portal-id attribute
var portalId = $(this).data('portalId'),
$uploader = $('#fileupload');
// set the url for the upload based on out portalId
$uploader.fileupload('option', 'url', '/precos/upload/id/'+ portalId);
// invoke the click
$('#fileupload').trigger('click');
});
The one thing missing here is that you might want to set something up so that when the uploader is closed or all the uploads complete the URL is set back to null or a URL of no consequence. This would help to ensure something going wrong on the client cant mistakenly upload files to the wrong endpoint.
Here is an example Fiddle that works as much as a Fiddle can :-)
You need to make your url global and update it later in that context. Use it like
var idPortal;
var url;
function setPortalId(valor) {
idPortal = valor;
url = '/precos/upload/id/'+ idPortal;
}
The easiest approach to seperate PHP (serverside business logic) and Javascript (non-business critical GUI enhencement), is to put all variables from PHP into the DOM and then later work with it:
<script>
var phpValues = <?php echo json_encode($yourPhpValuesArrayOrObject); ?>;
</script>
....
<script>
The attributes connected with business data from inside the HTML (=semantic structure) should go with a data-* attribute as already mentioned.
You're setting url when the page is first loaded, not after the user clicks on the link. Add that to the setPortalId function:
function setPortalId(valor) {
idPortal = valor;
url = '/precos/upload/id/'+ idPortal;
}
thank you everyone,but I used another approach to get the correct value of the clicked element.like was said,the function is self-invoked in the page loading,so in this moment the global var still null.I as using the blueimp jquery file upload,so reading the documentation I saw that is possible send another values during the ajax request just adding news inputs in the form.with this I solved my problem.
Related
I have looked at a bunch of different Q/A on stack and I can not seem to solve my issue for why my rest interface is not getting called on the button submit. I would appreciate it if you guys could look and see where the issue could be.
The goal is to have a form input values (for now they are hard coded until I get it to work), and submit to change the database they are in via a REST call.
EDIT: On button click, no errors in console, nothing shows up in DB.
<?php
$id = "123456";
$auth = "XYZ123"; //this will change daily
$url = "http://update/this/id/$id"; //this will change based on user
?>
<script >
const URL = <?php echo json_encode($url);?>;
const auth = <?php echo json_encode($auth);?>;
const data = {
"flag":"Y" //in the database flag has a value of N want to change to Y
}
$.ajaxSetup({
headers: {
'auth-key': '${auth}',
'api-version': '1.0',
'Content-Type': 'application/json',
'Accepts': 'application/json',
'Verbosity' : '4'
}
});
$('.btn').click(function(){
$.post(URL, data, function(data, status){
console.log('${data} and status is ${status}')
});
})
</script>
<button type="submit" class="btn">Send it!</button>
The JavaScript executes before the DOM is loaded (<script> tags interrupt the DOM parser). By the time the script executes there is no .btn element yet.
Either
move the script to the end of the body (or at least after the submit button),
or add the event listener after the DOM has been loaded,
or use the global event listener
$(document).on('click', '.btn', function() { ... }
On my page I have a list of users. Each user has a profile page on an external site (not the same domain name). To save my client updating their profile details in 2 places, I am using PHP simple HTML Dom Parser. This gets the content of the users external profile page and returns it on my site.
What I am trying to do is load the users profile information into a div on my site only when the users name is clicked.
Each user looks like this:
<div class="actor_container" data-url="www.external-profile-url.com">
<img src="http://placehold.it/500x500" />
</div>
To get the contents of the external page I use this code:
$html = file_get_html('http://www.spotlight.com/5094-1276-6177');
echo $html->find('div.credits', 0);
Obviously this works at the minute as it is hard coded. However I need to make it dynamic so that the external profile info for each user is loaded when the relevant user is clicked.
Update from answer below:
I added this script to the top of the user list:
<script>
jQuery(function ($) {
$(".actor_container").load(function () {
return "http://79.170.44.105/samskirrow.com/nial/wp-content/plugins/nial-customizations/front-end/my.php?url=" + $(this).data("url");
});
});
</script>
then in my.php
<?php
$html = file_get_html($_GET["url"]);
echo $html->find('div.credits', 0);
Currently, when I click on a user, nothing happens
UPDATE
OK I've moved to using AJAX to access my.php. Here is what I have so far:
<script>
jQuery(document).ready(function ($) {
$('.nial_actor').on("click", function (e) {
e.preventDefault();
$.ajax({
url: "http://79.170.44.105/samskirrow.com/nial/wp-content/plugins/nial-customizations/front-end/my.php?url=" + $(this).data("url"),
type: 'GET',
success: function(res) {
var data = $.parseHTML(res);
// append all data
$('#all_data').append(data);
}
});
}); //on
}); // ready
</script>
However this returns the following error:
GET http://79.170.44.105/samskirrow.com/nial/wp-content/plugins/nial-customizations/front-end/my.php?url=undefined 500 (Internal Server Error)
So for some reason the url in data-url is not adding to the end of my ajax url. Have I missed something obvious?
Something like this works?
$(function () {
$(".actor_container").load(function () {
return "my.php?url=" + $(this).data("url");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="actor_container" data-url="www.external-profile-url.com">
<img src="...actor profile img..." />
</div>
And in the PHP file, you can add url as your GET param:
$html = file_get_html($_GET["url"]);
Note that there are lots of vulnerabilities in this methods. Keep this just as a guidance.
I'm loading a custom page type that is just comments for a post. This is so I can use Disqus threads for easier usability when multiple loop posts are on a single page.
When loading an iFrame with the following structure I keep getting this syntax error. Are my escape characters wrong?
$(".boxyComments a").click(function (event) {
event.preventDefault();
var post_id = $(this).attr("rel");
$(".commentsIframeBig")
.get(0).contentWindow.location.href =
$("<?php echo get_site_url(); ?>","\/ajax-post-fold\/",post_id);
What's happening is the get retrieves the Wordpress hook to print the site url (in this case it prints http://whateverdomainex.com for the 1st call, 2nd should print /ajax-post-fold/ and the last call should print the post ID so the entire url ends up printing as http://whateverdomanex.com/ajax-post-fold/2825.
Instead my Chrome console gives me the following message:
Uncaught Error: Syntax error, unrecognized expression: /ajax-post-fold/
Update
I've put this variable into place and called it rather than the $("<?php echo get_site_url(); ?>","\/ajax-post-fold\/",post_id); as the get reference:
var postLink = $("<?php echo get_site_url(); ?>"+"\/ajax-post-fold\/"+post_id);
Implemented as such:
$(".boxyComments a").click(function (event) {
event.preventDefault();
var postLink = $("<?php echo get_site_url(); ?>"+"\/ajax-post-fold\/"+post_id);
var post_id = $(this).attr("rel");
$(".commentsIframeBig")
.get(0).contentWindow.location.href = postLink;
Which gives me the following Chrome message:
Uncaught Error: Syntax error, unrecognized expression: http://www.theciv.com/ajax-post-fold/28448
The URL that should be in the src attribute for the iFrame looks like it should be fine and good to go, so why is this syntax error still being output?
UPDATE
var postLink = "<?= site_url('\/ajax-post\/'); ?>"+post_id;
$(this).closest(".boxy").find(".commentsIframeBig")
.css("display","block")
.animate({height: "100%"}, 500)
.get(0).contentWindow.location.href = postLink;
With the proper structure above, the custom page is now loading in the iFrame. However the additional construct of +page_id which includes the rel attribute containing the post's id isn't loading properly.
Moreover when calling the new url as it's original custom page template, then adding the post's id does not load the correct page with post id. Confused yet? Read it again. Took me awhile to write that sentence.
In any case, now my mission to have the post id load when adding the custom page and the post_id as an added string for the iFrame's url to load properly.
update
Here is final working code to load Disqus comments into same page, pseudo multiple times.
Basically this is pushing a post id to the end of a custom page type, resulting in the post's content and attributable elements being loaded into the custom page template.
When stripping that custom page template down to just show the comments for the page, you can create a load/unload reaction whereby you are only calling Disqus once, removing that instance and then loading it again when another Load Comments button is clicked within a subsequently loaded post on the same page. Yay. Multiple Disqus commenting on one page with minimal Ajax loading.
Here is the structure et al that is almost working for me. Only 2 bugs left. First is the secondary load when emptying, then reloading the new Disqus page into the Ajax element using the .ajaxComplete() callback function.
What's happening now is the callback is basically not being fired at all. As far as I can tell. Clicking on it a second time however, does make the call. But this is due to the class parameters being met for the else statement.
Second bug left is I'm having a hard time figuring out how to get the appropriate elements to enlarge, while leaving the others the same size.
// Load comments and/or custom post content
$(".boxyComments a").click(function (event) {
event.preventDefault();
$.ajaxSetup({cache:false});
var post_id = $(this).attr("rel"); var excHeight = $(this).closest('.boxy').find('.initialPostLoad').height();
var postHeight = $(this).closest('.boxy').find('.articleImageThumb').height();
var postWidth = $(this).closest('.boxy').find('.articleImageThumb').width();
// close other comments boxes that may already be open
if($('.commentsOpen').length ) {
console.log('comments are open');
$('.bigBoxy').closest('.boxy')
.animate({height:(postHeight + excHeight)}, 500);
$('.showComments')
.removeClass('bigBoxy')
.removeClass('commentsOpen');
$('.commentsAjax')
.empty(function(){
$(this).closest(".boxy").find(".showComments")
.addClass("commentsOpen")
.addClass("bigBoxy");
$(".bigBoxy").find(".commentsAjax ")
.css("display","block")
.animate({height: "500px"}, 500)
.load("http://<?php echo $_SERVER[HTTP_HOST]; ?>/ajax-post/",{id:post_id});
$(this).closest(".boxy")
.ajaxComplete(function() {
var excHeight = $(this).closest('.boxy').find('.initialPostLoad')
.height();
var postHeight = $(this).closest('.boxy').find('.articleImageThumb')
.height();
$(this).closest(".boxy").animate({height: (postHeight + excHeight)}, 500)
});
});
} else {
$(this).closest(".boxyComments").find(".showComments")
.addClass("commentsOpen")
.addClass("bigBoxy");
$(this).closest(".boxy").find(".commentsAjax")
.css("display","block")
.animate({height: "500px"}, 500)
.load("http://<?php echo $_SERVER[HTTP_HOST]; ?>/ajax-post/",{id:post_id});
$(this).closest(".boxy")
.ajaxComplete(function() {
var excHeight = $(this).closest('.boxy').find('.initialPostLoad')
.height();
var postHeight = $(this).closest('.boxy').find('.articleImageThumb')
.height();
$(this).closest(".boxy").animate({height: (postHeight + excHeight)}, 500)
});
}
});
Okay, here's full working code to do what you want. You'll have to swap out a few placeholders for your actual code:
<script>
jQuery(document).ready(function($){$(".boxyComments a").click(function (event) {
event.preventDefault();
var post_id = $(this).attr("rel");
var postLink = "<?= site_url('/path/'); ?>"+post_id;
$("#myFrame").attr('src', postLink);
});
});
</script>
And sample divs & iFrame:
<div class='boxyComments'>
<a href='#' rel='some-url'>test link</a>
</div>
<div class=".commentsIframeBig">
<iframe id='myFrame' height="500px" width="800px" src=''>
</iframe>
</div>
Tested it locally and it worked no problem. You might have been running into issues with it not properly accessing the iFrame. If you can give the iFrame an id that makes it easier.
It's because you're declaring var postlink as a jQuery object. You just need to get it as a string that you can then pass to the iframe.
var post_id = $(this).attr("rel");
var postLink = "<?= site_url('/ajax-post-fold/'); ?>"+post_id;
UPDATE 2
Looks like the string shouldn't be included within the <?= get_site_url() ?> after all.
Instead I've created a few vars to affect it. Code updated below with answer:
var postDir = "\/ajax-post-fold\/";
var postLink = "<?= get_site_url(postDir); ?>"+"\/ajax-post-fold\/"+post_id;
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.
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++
}