How to update the right span? - javascript

On my forum-based website, I have a link below every post for reporting spam or abuse. Whenever this link is clicked, a web service is called on the server, when the call returns, the span containing the link (see the code below) is updated with something like 'Post reported' or if an error occurs it shows something like 'An error occurred while reporting the post', this is the javascript code:
<script src="/js/MicrosoftAjax.js" type="text/javascript" language="javascript"></script>
<script type="text/javascript" language="javascript">
var spanToUpdate;
function ReportPost(updateSpan, postID)
{
if (confirm("Are you sure you want to report this post as spam or abuse?"))
{
spanToUpdate = updateSpan;
var proxy = SiteWS.ReportPost(postID, onReportPostSuccess, onReportPostFailure);
}
}
function onReportPostSuccess(sender, e)
{
spanToUpdate.innerHTML = "Post reported";
}
function onReportPostFailure(sender, e)
{
spanToUpdate.innerHTML = "An error occurred while reporting the post";
}
</script>
And this is the reporting link:
<div class="post">
<p>post text here</p>
<span>Report Post</span>
</div>
Other posts ...
As you can see, I use a variable, spanToUpdate, to hold a reference to the span that contains the reporting link, which means that if the user reports another post (ie. clicks another reporting link) before the call returns, the span of the last post will be updated twice and the previous one won't be updated at all, is there any workaround for this?
Many thanks

You can use anonymous functions and closures for that.function ReportPost(updateSpan, postID) {
if (confirm("Are you sure you want to report this post as spam or abuse?")) {
var proxy = SiteWS.ReportPost(
postID,
function(sender,e) {updateSpan.innerHTML = "Post reported" },
function(sender,e) {updateSpan.innerHTML = "An error occurred while reporting the post" }
);
}
}
edit: hmm .. just wondering, will updateSpan be referring to the same span when the anonymous method is called? – Waleed Eissa
Yes, that's the magic of closures. Try this little example:
<head>
<script>
function foo()
{
bar(1, 100);
bar(2, 150);
bar(3, 200);
bar(4, 250);
bar(5, 300);
document.getElementById("div1").innerHTML += "foo() is done. ";
return;
}
function bar(val, timeout) {
window.setTimeout(
function() {
document.getElementById("div1").innerHTML += " " + val + " ";
},
timeout
);
}
</script>
</head>
<body>
<button onclick="foo()">click</button>
<div id="div1"></div>
</body>You will see that each time the anonymous function is called it has preserved "its own" value of val from the time/context when bar() was called.

Not a JavaScript developer so this might not work. Would it be possible to hold a reference to the post id and the spanToUpdate and then have the response from the server include the post id. Then you could retrieve the correct spanToUpdate.

Related

Google reCaptcha response "Uncaught (in promise) null"

I'm use reCaptcha v2 but in dev console response Uncaught (in promise) null in in any case (and moving the .reset() function)
console:
my code for recaptcha:
<div class="text-xs-center" style="text-align: center; height:150px;">
<p style="color: black;"> Complete the verification: </p>
<div style="display: inline-block;" class="g-recaptcha" data-sitekey="xxxxxxxxxxx" data-callback="callback"></div>
</div>
my callback function:
function callback() {
if (grecaptcha === undefined) {
alert('Recaptcha non definito');
return;
}
var response = grecaptcha.getResponse();
console.log(response);
if (!response) {
alert('Coud not get recaptcha response');
return;
}
$.ajax({
'url' : 'validate-recaptcha.php',
'type' : 'POST',
'data' : {
'response' : response
},
'success' : function(data) {
alert('Data: '+data);
},
'error' : function(request,error)
{
alert("Request: "+JSON.stringify(request));
}
});
grecaptcha.reset();
}
and my validate-recaptcha.php:
<?php
//debug
$fp = fopen('debug.txt', 'a');
fwrite($fp, print_r($_POST, TRUE));
fclose($fp);
//enddebug
if (empty($_POST['recaptcha'])) {
exit('Please set recaptcha variable');
}
// validate recaptcha
$response = $_POST['recaptcha'];
$post = http_build_query(
array (
'response' => $response,
'secret' => 'yoursecretkey',
'remoteip' => $_SERVER['REMOTE_ADDR']
)
);
$opts = array('http' =>
array (
'method' => 'POST',
'header' => 'application/x-www-form-urlencoded',
'content' => $post
)
);
$context = stream_context_create($opts);
$serverResponse = #file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
if (!$serverResponse) {
exit('Failed to validate Recaptcha');
}
$result = json_decode($serverResponse);
if (!$result -> success) {
exit('Invalid Recaptcha');
}
exit('Recaptcha Validated');
Searching on the internet, probably the problem is the .reset() function, but I do not understand the solution.
Turns out it also occurs when a site is not "registered" in the Google recaptcha/admin Domains area.
Solution: Add the domain in the recaptcha admin area:
Sign into your Google account where your recaptcha keys are registered
Type into Google "google recpatcha admin console"
Go to your settings for your (production) key
In "Domains", add these two entries:
localhost
127.0.0.1
Save it and test your recaptcha.
I made this error when I switched from a development key to a production key. The production key did not have any entries for localhost.
I configured the API response to sit behind a proxy-redirect. Therefore the verification was working in a localhost environment which was not configured in the Google Admin console which caused this generic error.
Credit to #Christian Žagarskas who pointed it out in his comment.
I had this error too and I found is related with the recaptcha callback (in your case data-callback="callback"). If you remove your data-callback attribute the error won't come up.
The console error Uncaught (in promise) null indicates the callback is waiting for a promise. Here's a basic callback function for recaptcha using promises:
function callback() {
return new Promise(function(resolve, reject) {
//Your code logic goes here
//Instead of using 'return false', use reject()
//Instead of using 'return' / 'return true', use resolve()
resolve();
}); //end promise
};
In your case you need to adjust your code to something like this:
function callback() {
return new Promise(function(resolve, reject) {
if (grecaptcha === undefined) {
alert('Recaptcha non definito');
//return;
reject();
}
var response = grecaptcha.getResponse();
console.log(response);
if (!response) {
alert('Coud not get recaptcha response');
//return;
reject();
}
$.ajax({
'url' : 'validate-recaptcha.php',
'type' : 'POST',
'data' : {
'response' : response
},
'success' : function(data) {
alert('Data: '+data);
resolve();
},
'error' : function(request,error)
{
alert("Request: "+JSON.stringify(request));
reject();
}
});
grecaptcha.reset();
}); //end promise
}
This is my first answer in SO, so please be patient and let me know if I forgot or missed something :)
Another trigger for this error that plagued me was having a button in the form with a name attribute of 'submit'. If using the automatic binding example code from the reCaptcha documentation, this will trip it up, since 'form.submit' will refer to the button rather than the submit() function of the form itself. Doh!
<html>
<head>
<title>reCAPTCHA demo: Simple page</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
function onSubmit(token) {
document.getElementById("demo-form").submit();
}
</script>
</head>
<body>
<form id='demo-form' action="?" method="POST">
<!-- Oops.... avoid the name="submit" below -->
<button name="submit" class="g-recaptcha" data-sitekey="your_site_key" data-callback='onSubmit'>Submit</button>
<br/>
</form>
</body>
</html>
This can happen when your callback code causes an error. In my case, my callback just referenced some variable that didn't exist and I saw the same error. Very weird error for something so simple!
I also saw the same error when I left a . after a variable name on accident. Seems like this is a super generic error that means fix the code in your callback!.
I feel I should add an answer here with my specific experience. I give credit to the top answer, which will be part of my answer.
I was getting: Uncaught (in promise) null. When I expanded the error in the console it was empty.
I changed my code from this:
function onSubmit(token) {
if (grecaptcha.getResponse() !== "") {
$('#request-form').submit();
}
grecaptcha.reset();
}
To this:
function onSubmit(token) {
return new Promise(function (resolve, reject) {
if (grecaptcha.getResponse() !== "") {
$('#request-form').submit();
}
grecaptcha.reset();
});
}
What this change does is allows you to receive a specific error message in your console. You can then proceed to fix your specific problem.
Similar to John Rix issue/solution. I also got the error when the id of the submit element was 'submit'.
<!-- Avoid id="submit" below -->
<input type="submit" id="submit" value="submit">```
In my case I was using jquery.3.4.1.slim.js then I changed to jquery.3.4.1.min.js and the error disappeared. I'm on ASP.NET WebForms .
I had this issue. It was because in my callback function jquery code was there and for some reason, I had forgotten to include the jquery script. So if you are having this issue, I suggest you to carefully go through each line of your call back code. May be reduce the complexity line by line and you will get the solution. The error handling should have been done in a better way.
I was using ASP.NET Core 3.1 Identity, I had this issue and solved it by updating jquery.validate.min.js and jquery.validate.unobtrusive.min.js to the latest version in _ValidationScriptsPartial.cshtml.
I had the same issue and the problem was that I didn't add localhost to the list of supported domains.
I hit this error because I had:
const onChange = e => {
e.preventDefault();
console.log('success')
}
<ReCAPTCHA sitekey="yeet" onChange={onChange} />
Removing e.preventDefault() removed the error.

How do use the varible outside of the function?

I have created a function to get the IP Address of the user. Then I tried to give separate AD to the user. So I use if condition and try to use the value of the function (getIP) to execute the if condition. But I am not success. The main problem is that I couldn't able to use the ip variable out side of the function. Can anybody see to help me.
<script type="application/javascript">
function getIP(json) {
ip=json.ip; //Here I got the user IP Address
}
getIP(json);
var KivaHan="221.120.101.58"
var Office="221.120.99.186"
if( ip==KivaHan ){
document.write("Kiva Han IP Address: " + ip);
}else{
document.write("Office IP Address: " + ip);
}
</script>
<script type="application/javascript" src="https://api.ipify.org?format=jsonp&callback=getIP"></script>
Change it like this.
function getIP(json) {
return json.ip;
}
var ip = getIP(json);
If your getIP function is synchronous, return the IP address from it:
function getIP() {
var ip; // Don't forget to declare this
// ...get the IP address into `ip`
return ip;
}
usage
var ip = getIP();
if (ip) {
// Your code uses `ip` here
} else {
// Failed to get it, handle that here
}
If your getIP function is asynchronous, you have two options:
Have it accept a callback, and call the callback with the IP:
function getIP(callback) {
var ip; // Don't forget to declare this
// ...get the IP address into `ip`, maybe have it set to null on error
callback(ip);
}
usage:
getIP(function(ip) {
if (ip) {
// Your code uses `ip` here
} else {
// Failed to get it, handle that here
}
});
Or use a Promise (ES2015, but there are libs that polyfill it well enough on JavaScript engines that don't do it natively):
function getIP(callback) {
var ip; // Don't forget to declare this
return new Promise(function(resolve, reject) {
// ...get the IP address into `ip`
if (/* we got the IP */) {
resolve(ip);
} else {
// it failed:
reject();
}
});
}
usage:
getIP()
.then(function(ip) {
// Your code uses `ip` here; perhaps ip == null means failure
})
.catch(function() {
// Failed to get it, handle that here
});
Only place where javascript creates a new scope is function. Whenever you see function keyword, its safe to assume that a new scope will be created. The problem you are facing here is you are defining ip inside a function and trying to access it outside which is logically not possible. However, you can make a global variable and can access it anywhere in your program. But downside of it is, it will clutter your global namespace and if you are unlucky you may face issues that will be weird and hard to debug.
You can make use of IIFE (Immediately Invoked function expression) which is one of the most used design pattern in javascript.
(function(){
var ip = ""; //Define ip variable here.
function getIP(json) {
ip=json.ip; //Here I got the user IP Address
}
getIP(json);
var KivaHan="221.120.101.58"
var Office="221.120.99.186"
if( ip==KivaHan ){
document.write("Kiva Han IP Address: " + ip);
}
else{
document.write("Office IP Address: " + ip);
}
})();
Hope this be of some help.
Happy Learning :)
I have tried with most of the Solution but not get real output which I want. Perhaps there is problem withe the function getIP(json) and the site from where I get the function to get user IP address. I think the value of this can't run out side of the function. So I used another site to get the user IP.
Now I give the alternative solution of my demand.
In this topic I want the IP Address of an user which I get in that function. But I could not trace out this from the function which I couldn't use more time in this page.
So I use the solution given below to fill my demand..
<head>
<script type="text/javascript" src="https://l2.io/ip.js?var=userip"> </script><!-- To get IP Address of the user -->
<script type="text/javascript"><!-- Here variables are decleared.. -->
var userip;
var KivaHan="221.120.101.58"
var Office="221.120.99.186"
</script>
</head>
<!-- Javascript for tracking and comparing the user IP-->
<!-- Below code is for implementation-->
<div class="main-bottom">
<div class="ad">
<script type="text/javascript">
if (userip==KivaHan){
document.write("Welcome");
}
else
{
document.write("Coming Soon");
}
</script>
</div>
<div class="ad">
<script type="text/javascript">
if (userip==KivaHan){
document.write("Welcome");
}
else
{
document.write("Coming Soon");
}
</script>
</div>
<div class="ad">
<script type="text/javascript">
if (userip==KivaHan){
document.write("Welcome");
}
else
{
document.write("Coming Soon");
}
</script>
</div>
</div>

AJAX and YQL doesn´t work using dreamweaver (cross-domain-request)

I use a js to display some content on my app (I use Dreamweaver and PhoneGap). When i preview the html separately works, but when i load the html from other page dont.
I receive this msg on the Firefox Security: ReferenceError: requestCrossDomain is not defined
This is my HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery Mobile Web App</title>
<script src="js/jquery-1.11.0.min.js"></script>
<script src="js/cross-domain-request.js"></script>
</head>
<body>
<div id="container">
<p id="sitename"> http://catedralaltapatagonia.com/invierno/partediario.php? default_tab=0
</p>
function codeAddress(){
var elem = document.getElementById("sitename");
elem.value = "http://catedralaltapatagonia.com/invierno/partediario.php? default_tab=0";
var path =$('#sitename').val();
requestCrossDomain(path, function(results){
$('#container').html(results);
});
return false;
};
</script>
</body>
</html>
And my cross-domain-request.js:
/ JavaScript Document
// Accepts a url and a callback function to run.
function requestCrossDomain( site, callback ) {
// Take the provided url, and add it to a YQL query. Make sure you encode it!
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + 'http://catedralaltapatagonia.com/invierno/partediario.php?default_tab=0' + '"'+' AND xpath="//*[#id=\'meteo_recuadro\']"') + '&format=xml&callback=?';
// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
$.getJSON( yql, function(data){
// If we have something to work with...
if ( data.results[0] ) {
// Strip out all script tags, for security reasons.
// BE VERY CAREFUL. This helps, but we should do more.
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
// If the user passed a callback, and it
// is a function, call it, and send through the data var.
if ( typeof callback === 'function') {
callback(data);
}
}
// Else, Maybe we requested a site that doesn't exist, and nothing returned.
else throw new Error('Nothing returned from getJSON.');
});
}
Some clue to resolve it?
You appear to have an error in your external JS file, and it's not running. The final else statement is not correct. Try this:
/ JavaScript Document
// Accepts a url and a callback function to run.
function requestCrossDomain( site, callback ) {
// Take the provided url, and add it to a YQL query. Make sure you encode it!
var yql = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent('select * from html where url="' + 'http://catedralaltapatagonia.com/invierno/partediario.php?default_tab=0' + '"'+' AND xpath="//*[#id=\'meteo_recuadro\']"') + '&format=xml&callback=?';
// Request that YSQL string, and run a callback function.
// Pass a defined function to prevent cache-busting.
$.getJSON( yql, function(data){
// If we have something to work with...
if ( data.results[0] ) {
// Strip out all script tags, for security reasons.
// BE VERY CAREFUL. This helps, but we should do more.
data = data.results[0].replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
// If the user passed a callback, and it
// is a function, call it, and send through the data var.
if ( typeof callback === 'function') {
callback(data);
}
}
// Else, Maybe we requested a site that doesn't exist, and nothing returned.
else {
throw new Error('Nothing returned from getJSON.');
}
});
}
I add the line
<script src="js/cross-domain-request.js"></script>
and the js is loaded

Google+ signinCallback called twice and losing authresult in process

There is a bug in my code.
I am able to sign in and retrieve user information. But the signinCallback is called again(I don't know how). And it shows User information that I had earlier is gone!
Here is the HTML side:
<span id="signinButton">
<span
class="g-signin"
data-callback="signinCallback"
data-clientid="CLIENT_ID"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.profile.emails.read"
data-width="standard"
data-height="short">
</span>
</span>
and here is the javascript side:
var AuthStates = {
google: null
};
function signinCallback(authResult) {
console.dir(authResult);
console.log('Sign-in state: ' + authResult['error']+authResult['access_token']);
AuthStates.google = authResult;
console.log('signinCallback');
chooseAuthProvider();
}
function chooseAuthProvider() {
if (AuthStates.google && AuthStates.facebook) {
if (AuthStates.google['access_token']) {
// Signed in with Google, you can now use Google+ APIs.
console.log(AuthStates.google);
gapi.client.load('plus','v1', function(){
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
document.getElementById('cname').value =resp.displayName;
document.getElementById('cemail').value =resp.emails[0].value;
console.log('Retrieved profile for:' + resp.displayName + ' ' + resp.emails[0].value);
});
});
}
}
It gives this response to the console on the second signinCallback
Sign-in state: user_signed_outundefined
signinCallback
Try updated instructions at
"Integrating Google Sign-In into your web app" page.
Your call to request.execute() in your callback method is causing the callback method to be re-triggered with "user_signed_out" value in the error property.
If you take a look at the Google documentation "Signing out the user" it reads:
When the user refreshes the page or navigates to another part of your
website, the callback will fire with user_signed_out value in the
error property until the user clicks the sign-in button again.
Hence I believe it is your call to request.execute() which is triggering the second call to the callback method.
You can guard against this second call to the callback by putting a condition within the callback method e.g.
function signinCallback(authResult) {
if (authResult['status']['signed_in']) {
console.dir(authResult);
console.log('Sign-in state: ' + authResult['error']+authResult['access_token']);
AuthStates.google = authResult;
console.log('signinCallback');
chooseAuthProvider();
}
}
See Google's documentation on "Monitoring the user's session state" for an example of the previously mentioned guard conditions.
This might be helpful for you
(function() {
var GOOGLE_PLUS_SCRIPT_URL = 'https://apis.google.com/js/client:plusone.js';
window.oauth2Callback = function(authResult) {
if (authResult['access_token']) {
accessToken = authResult['access_token'];
$(function() {
$.getScript(GOOGLE_PLUS_SCRIPT_URL);}

Javascript malfunction

can someone explain me why this script is not working?
<script type="text/javascript">
function destroy(ID) {
if (confirm("Deleting is a very bad thing! Sure?"))
{
location.href='#Url.Action("SomeAction", new { id = ID })'
}
}
The error is: The name 'ID' does not exist in the current context, and occures here new { id = ID }
If I just replace ID in this way: new { id = 3 } it works fine. What is the problem?
You mix your Server code with the client code.
ID is a javascript variable- exist only on the client.
#Url.Action("SomeAction", server code, Exist only on the server.
You can't mix them!
You can do something like this:
function destroy(ID) {
if (confirm("Deleting is a very bad thing! Sure?")){
var url ='#Url.Action("SomeAction")';
url += '/?id =' + ID;
location.href = url;
}
}
You have to remember all the # stuff in the views are compiled and executed in the server and no longer exist in the client. tricky razor...
By the way, I would have change the confirm message...

Categories

Resources