I'm trying to write a file upload function that will return either a true or false after it uploads the file. The only return I can currently get is undefined. I have tried a few variations of the code, but I can't figure it out. I believe it's a latency or scope issue, but not really sure. Take a look and tell me what you guys think.
HTML
<div id="add-form">
make : <input type="text" id="make" name="make" />
type : <input type="text" id="type" name="type" />
caliber : <input type="text" id="caliber" name="caliber" />
cost : <input type="text" id="cost" name="cost" />
description : <textarea id="description"></textarea>
<form id="image-form">
image : <input type="file" id="image" name="image" />
</form>
<button id="add-item">ADD ITEM</button>
</div>
JQUERY
$(function()
{
$('#add-item').click(function()
{
console.log(uploader());
});
var uploader = function uploader()
{
var iframe = $('<iframe name="postiframe" id="postiframe" style="display:none" />');
$("body").append(iframe);
var form = $('#image-form');
form.attr("action","hub.php?handler=image");
form.attr("method","post");
form.attr("enctype","multipart/form-data");
form.attr("encoding","multipart/form-data");
form.attr("target","postiframe");
form.attr("file",$('#image').val());
form.submit();
$("#postiframe").load(function()
{
var _frame = $("#postiframe").contents().find('body').html();
var obj = $.parseJSON(_frame);
if(obj['status']==true)
{
return true;
}
else
{
return false;
}
});
}
});
The problem is that you're returning a value from your ajax callback
$("#postiframe").load(function() {
// ...
return true;
By the time this line of code has been reached, the original function has already terminated, returning nothing, which of course evaluates as undefined
var uploader = function uploader()
{
var iframe = $('<iframe name="postiframe" id="postiframe" style="display:none" />');
$("#postiframe").load(function()
{
var _frame = $("#postiframe").contents().find('body').html();
var obj = $.parseJSON(_frame);
if(obj['status']==true)
{
//function has already ended by this point!
return true;
}
else
{
//function has already ended by this point!
return false;
}
});
//you need to return something HERE
}
I'd say your best bet would be to pass in two callback functions, one to be run if the uploads succeeds, and the other if it fails. This won't get you to the point where the function will return true or false based on the result of the upload, but it will allow you to specify code to be run based on whether or not the upload is successful
var uploader = function uploader(successCallback, failureCallback)
{
var iframe = $('<iframe name="postiframe" id="postiframe" style="display:none" />');
$("#postiframe").load(function()
{
var _frame = $("#postiframe").contents().find('body').html();
var obj = $.parseJSON(_frame);
if(obj['status']==true)
{
if (typeof successCallback === 'function')
successCallback();
}
else
{
if (typeof failureCallback === 'function')
failureCallback();
}
});
}
The solution is you should implement a callback pattern to deal with the async nature. Here is is oversimplified.
var uploader = function(callback) {
$("postiframe").load(function () {
// success
callback(true);
});
};
Usage
uploader(function (success) {
});
Related
I'm trying to use google invisible recaptcha on my web form (php and codeigniter 3). but somehow whenever I click on the Submit button, the google recaptcha keeps generating questions as if ignoring all the other codes before the execute command. so none of the console.log and alert ever appear. what is wrong with my code?
my code looks like this:
HTML
<form id="form_signup" method="post" action="/signup">
<input type="text" name="username"/>
<div class="g-recaptcha"
id="form_signup-recaptcha"
data-size="invisible"
data-sitekey="<?php echo $mysitekey; ?>"
data-callback="onSubmitFormSignupUser">
</div>
<button type="button" id="formSignup-btnSubmit">
Submit
</button>
</form>
JS
var widgetId = '';
var onLoadRecaptcha = function() {
widgetId = grecaptcha.render('formSignup-btnSubmit', {
'sitekey' : $('#form_signup-recaptcha').attr('data-sitekey'),
'callback' : $('#form_signup-recaptcha').attr('data-callback'),
});
};
var onSubmitFormSignupUser = function(response) {
console.log('response', response);
if ($('[name="username"]').val()) {
alert('yes');
grecaptcha.execute(widgetId);
doSubmitFormToServer('#form_signup');
}
else {
alert('no');
grecaptcha.reset(widgetId);
}
}
var doSubmitFormToServer = function(selector) {
var myData = $(selector).serializeArray();
console.log('send form data', myData);
}
Well, you had a typo in the id, at least, here id="form_signup-recaptcha" and here: 'sitekey' : $('#formSignup-recaptcha').attr('data-sitekey'),, other than that, it is not clear, was it invoked at all, or not, as you've not provided the part of including the script, which should contain ?onload=onLoadRecaptcha parameter.
The code is below, but it won't work here, because of null origin. Check Codepen instead: https://codepen.io/extempl/pen/abOvBZv
sitekey used is one is for testing purposes only, as described here: https://developers.google.com/recaptcha/docs/faq#id-like-to-run-automated-tests-with-recaptcha-v2-what-should-i-do
var widgetId = "";
var onLoadRecaptcha = function() {
widgetId = grecaptcha.render("formSignup-btnSubmit", {
sitekey: $("#form_signup-recaptcha").attr("data-sitekey"),
callback: $("#form_signup-recaptcha").attr("data-callback")
});
};
var onSubmitFormSignupUser = function(response) {
console.log("response", response);
if ($('[name="username"]').val()) {
grecaptcha.execute(widgetId);
doSubmitFormToServer("#form_signup");
} else {
$(".status").text("failed");
grecaptcha.reset(widgetId);
}
};
var doSubmitFormToServer = function(selector) {
var myData = $(selector).serializeArray();
$(".status").text("submitted");
console.log("send form data", myData);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://www.google.com/recaptcha/api.js?onload=onLoadRecaptcha"></script>
<body>
<form id="form_signup" method="post" action="/signup">
<input type="text" name="username" />
<div
class="g-recaptcha"
id="form_signup-recaptcha"
data-size="invisible"
data-sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
data-callback="onSubmitFormSignupUser">
</div>
<button type="button" id="formSignup-btnSubmit">
Submit
</button>
<span class="status"></span>
</form>
</body>
it turns out that the solution is so simple.
this code
var onLoadRecaptcha = function() {
widgetId = grecaptcha.render("formSignup-btnSubmit", { // wrong element ID
sitekey: $("#form_signup-recaptcha").attr("data-sitekey"),
callback: $("#form_signup-recaptcha").attr("data-callback")
});
};
should be like this
var onLoadRecaptcha = function() {
widgetId = grecaptcha.render("form_signup-recaptcha", { // corrent element ID
sitekey: $("#form_signup-recaptcha").attr("data-sitekey"),
callback: $("#form_signup-recaptcha").attr("data-callback")
});
};
because the recaptcha element is like this
<div
class="g-recaptcha"
id="form_signup-recaptcha"
data-size="invisible"
data-sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
data-callback="onSubmitFormSignupUser">
</div>
so basically the parameters for grecaptcha.render should follow the properties in the element that has g-recaptcha class. my mistake was that I used the button id, even though the element with g-recaptcha class was the div.
I don't remember reading about this particular thing in the documentation. I guess I'm too stupid to realize that before this.. I hope this makes things clear for others with the same problem.
I have a closure function in javascript and that i just want to call on addEventListener. I am not using ES6 so that i can not use static method with class.
function validationFunction()
{
let _validateAlphaNumeric = function (param1)
{
return /^[0-9a-zA-Z]+$/.test(param1);
}
let _customValidation = function (param1,param2){
let a = new RegExp(param2);
return a.test(param1);
}
return {
ValidateAlphaNumeric : _validateAlphaNumeric,
CustomValidation :_customValidation
}
}
function valid(){
var validation = new validationFunction();
if(validation.ValidateAlphaNumeric(document.getElementById("Name").value)){
document.getElementById("ErrorName").innerHTML = "Alpha numeric";
}
else{
document.getElementById("ErrorName").innerHTML = "Some error";
}
if(validation.CustomValidation(document.getElementById("Name").value,"[A-Za-z]{3}"))
{
document.getElementById("ErrorName1").innerHTML = "True";
}
else{
document.getElementById("ErrorName1").innerHTML = "False";
}
}
<input type="button" value="Save" onclick="valid();">
<br>
<input type="text" id="Name">
<br>
<span id="ErrorName" style="color:red"></span>
<br>
<span id="ErrorName1" style="color:red"></span>
This works fine for me, problem came when i am trying to this function using addEventListener. I know that i can use pattern attribute in html5 for validation, but its not about validation i have to do some more stuff onkeypress. I do not want to make another method for it.
<input type="text" id="tnum" maxlength="50" placeholder="Enter Your Tracking ID" />
<input class="btn" type="button" value="TRACK" onclick="doTrack()" />
<div id="YQContainer"></div>
So basically, I have a page that can track packages for my customers. I want to be able to send them a link in their email that will automatically track their package from the link. ( they don't have to type in their tracking id and click track when they go to my tracking page )
example.com/track?tnum=3298439857
This is what i'm using to track packages.
https://www.17track.net/en/externalcall/single
The basic idea is as follows:
Wait for page to load
Parse the URL and extract needed query parameter
Set the value of the form element
Call the doTrack() function
// Handy function to parse the URL and get a map of the query parameters
function parseQueryParameters(url) {
var qp = {};
if (!url) {
return qp;
}
var queryString = url.split('?')[1];
if (!queryString) {
return qp;
}
return queryString.split('&')
.reduce(function(m, d) {
var splits = d.split('=');
var key = splits[0];
var value = splits[1];
if (key && value) {
m[key] = value;
}
return m;
}, qp);
}
//Wait for page to load
window.onload = function() {
//Extract tnum query parameter
var qp = parseQueryParameters(window.location.href);
//If no parameter is provided, do nothing
if (!qp.tnum) return;
//Set the value of the form element
document.getElementById("tnum").value = qp.tnum;
// Call doTrack
doTrack();
}
//Temporary doTrack function - remove when integrating ;)
function doTrack() {
console.log(document.getElementById("tnum").value)
}
<input type="text" id="tnum" maxlength="50" placeholder="Enter Your Tracking ID" />
<input class="btn" type="button" value="TRACK" onclick="doTrack()" />
<div id="YQContainer"></div>
<html>
<head>
<script>
function setURL(){
var dt_value = document.getElementById("tnum").value;
//just test here ..what is coming..
alert(dt_value );
var sjdurl = "example.com/track?tnum="+dt_value;
popup = window.open(sjdurl,"popup"," menubar =0,toolbar =0,location=0, height=900, width=1000");
popup.window.moveTo(950,150);
}
</script>
</head>
<body>
<input type="Text" id="tnum" maxlength="25" size="25"/>
<input type='button' onclick='setURL()' value='SUBMIT'>
</body>
</html>
function doTrack(tnum) {
var trackNumber = tnum;
window.open("example.com/track?tnum="+trackNumber);
}
$(".btn").on('click',function(e) {
e.preventDefault();
var tnum = $('#tnum').val();
if (tnum!="") {
doTrack(tnum);
} else {
return false;
}
});
Hello I am at my wit's end and I've been stuck creating a more complex version of the form than the example I provide.
I have JS object that is representation of the form. I use parsley's "isValid" on the form itself (checkAll and checkGroup function). These methods are fired on every input that is marked with data-parsley-required attribute. The reason for this is I need to know the state of the whole form and it's parts so I can enable/disable step buttons.
Everything works fine but I also need to call external API when all validations have successed, see line 35. The methods checkAll and checkGroup are basically firing the events again, thus making more AJAX calls (we have limit on calls to the API). Is there a way to force method isValid to just check if the field has been validated and get true/false value out of it?
The whole thing is coded and depends on this structure so the best way would be to have similar functionality. I'm not so experienced so I make lot of mistakes. My example is very simplified version of my actual form but when you open console window you can see what I mean. Uncomment lines 32 and 33 to see the difference and you will know what I mean.
Example code
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<form action="" id="myform">
<div id="section1">
<input type="text" id="field1" data-parsley-required data-parsley-trigger="input" data-parsley-group="group1" data-parsley-lengthvalidator data-parsley-remote="http://pokeapi.co/api/v2/pokemon/1" data-parsley-remote-validator="remotevalidator" /><br />
<button id="next" disabled>Next</button><br />
</div>
<div id="section2">
<input type="text" id="field2" data-parsley-required data-parsley-trigger="input" data-parsley-group="group2" />
</div>
<input type="submit" id="submit-button" disabled />
</form>
</body>
</html>
JS:
function Form(form) {
this.form = form;
this.validations = {};
this.formValid = false;
this.checkAll = function() {
var result = $(form).parsley().isValid();
if (result) {
$('#submit-button').removeAttr('disabled');
console.log('form validated');
} else {
$('#submit-button').attr('disabled', true);
}
this.formValid = result;
};
this.checkGroup = function(e) {
var group = $(e.target).attr('data-parsley-group');
var result = $(form).parsley().isValid({group: group});
if (result) {
$('#next').removeAttr('disabled');
console.log('group validated');
} else {
$('#next').attr('disabled', true);
}
this.validations[group] = result;
};
this.initialize = function() {
var self = this;
$(this.form).parsley();
$('*[data-parsley-required]').on('input', function(e) {
self.checkAll();
self.checkGroup(e);
});
$('#field1').parsley().on('field:success', function() {
console.log('calling another API')
})
Parsley.addValidator('lengthvalidator', {
validateString: function(value) {
console.log('local validator');
return value.length > 0;
}
});
Parsley.addAsyncValidator('remotevalidator', function(response) {
console.log('remote validator');
return response.responseJSON.name === 'bulbasaur';
})
}
}
var form = new Form('#myform');
form.initialize();
I'm working on a project where I'd place an search box with a default set of results, over the layout using Prototype which is triggered from a click event.
When the output is set, that new page has it's own Javascript which is uses, to dynamically filter the results.
Now the new set of results do not work with the Javascript set previously.
How can I maintain a persistent event with calling new events each time?
Or is that what I am supposed to do.
Here is a bit of code which is loaded in 'loaded_page.php'
<script language="javascript">
var o = new Compass_Modal('add_button', 'history');
var placetabs = new Tabs('tabs', {
className: 'tab',
tabStyle: 'tab'
});
$$('.add_button').each(function(s, index){
$(s).observe('click', function(f) {
loadData();
});
});
function loadData() {
new Ajax.Request('/sponsors/search', {
onComplete: function(r) {
$('overlay').insert({
top:'<div id="search_table">'+r.responseText+'</div>'
});
}
})
}
</script>
Then in the included page which is inserted via javascript:
<div id="search_overlay">
<div id="form_box">
<img src="/images/closebox2.png" class="closebox" />
<form method="post" id="search_form" class="pageopt_left">
<input type="text" name="search_box" id="search_box" value="search" />
</form>
</div>
<div id="table_overlay">
<table class="sortable" id="nf_table" cellpadding="0" border="0" cellspacing="0">
<tr>
<th id="name_th">Name</th><th id="amount_th">Amount</th><th id="tax_letter_th">Tax Letter</th><th id="date_th">Date</th><th id="add_th">Add</th></tr>
<tr>
<td>Abramowitz Foundation (The Kenneth & Nira)</td><td><input type="text" name="amount" value="" id="amount_111" /></td><td><input type="checkbox" name="tax_letter" value="1" id="tax_letter_111" /></td><td><input type="text" name="date" value="" id="date_111" /></td><td><img src="/images/icons/add.png" title="add contact" /></td></tr>
... more rows
</table>
</div>
</div>
<script language="javascript">
var c = new Compass_Search('contacts', 'table_overlay');
c.set_url('/sponsors/sponsor_search');
$$('.add_button').each(function(s, index) {
$(s).observe('click', function(e) {
$(e).stop();
var params = $(s).href.split("/");
var userid = params[5];
var amount = 'amount_'+params[5];
var date = 'date_'+params[5];
var tax = 'tax_letter_'+params[5];
if(!Form.Element.present(amount) || !Form.Element.present(date)) {
alert('your amount or date field is empty ');
} else {
var add_params = {'amount':$F(amount), 'date':$F(date), 'tax':$F(tax), 'id':userid};
if(isNaN (add_params.amount)) {
alert('amount needs to be a number');
return false;
} else {
new Ajax.Request('/sponsors/add', {
method: 'post',
parameters: add_params,
onComplete: function(e) {
var post = e.responseText;
var line = 'amount_'+add_params.id;
$(line).up(1).remove();
}
})
}
}
});
});
this.close = $$('.closebox').each(function(s, index) {
$(s).observe('click', o.unloader.bindAsEventListener(this));
})
</script>
You'll notice in the inserted portion, a new Javascript which also, updated its own content with yet new observers. When the content gets updated, the observers do not work.
Use event delegation.
Besides making it possible to replace "observed" elements, this approach is also faster and more memory efficient.
document.observe('click', function(e){
var el = e.findElement('.add_button');
if (el) {
// stop event, optionally
e.stop();
// do stuff... `el` now references clicked element
loadData();
}
});
As you're calling Element#insert, I suppose String#evalScripts should be automatically called (as having looked in the implementation of those methods)
Maybe you can try to do some console.log()/alert() messages before the Element#observe calls, to see where it is going wrong. It may be because the Javascript is not evaluated at all, or that there is something wrong with your code or something like that.
As a tip: check the documentation on Array#invoke, with that method you can rewrite something like:
$$('.add_button').each(function(s, index){
$(s).observe('click', function(f) {
loadData();
});
});
into this:
$$('.add_button').invoke('observe', 'click', function(event){
loadData();
});
// $$('.add_button').invoke('observe', 'click', loadData);