I have a button:
<span id="signinButton">
<span
class="g-signin"
data-callback="onSignInCallback"
data-clientid="CLIENT_ID"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login">
</span>
</span>
When pressed, this runs a function... which at the moment goes off, makes an AJAX post, and prints some text back in the console (just to test, this part works):
<script type="text/javascript">
var helper = (function() {
return {
onSignInCallback: function(data) {
var dataString = 'access_token=' + data['access_token'];
$.ajax({
type: "POST",
url: "getdetails",
data: dataString,
dataType: 'html',
timeout: 0,
statusCode: {
200: function(data){
console.log(data);
},
error: function(data){
console.log("There was an error");
}
}
});
}
};
})();
function onSignInCallback(data) {
helper.onSignInCallback(data);
}
</script>
However, the issue is that every time I refresh the page without clicking the button, my function runs and the data is posted via AJAX and the text gets printed into the console.
Any idea why this is happening? I want it (obviously) so this only happens when they click the button.
I'm working with the Google Plus API, code modified from:
https://github.com/googleplus/gplus-quickstart-javascript/blob/master/index.html#L44
Per the documentation for that directive:
data-callback - A function in the global namespace, which is called when the sign-in button is rendered and also called after a sign-in flow completes. When the button is rendered the callback occurs to check whether or not the user previously authorized the app and should be automatically signed in.
By design the callback will run when the button is rendered (i.e. page loads) and also when the button is clicked.
A workaround would be to set a global boolean on the first run.
<script type="text/javascript">
var first_run = true;
var helper = (function() {
return {
onSignInCallback: function(data) {
var dataString = 'access_token=' + data['access_token'];
$.ajax({
type: "POST",
url: "getdetails",
data: dataString,
dataType: 'html',
timeout: 0,
statusCode: {
200: function(data){
console.log(data);
},
error: function(data){
console.log("There was an error");
}
}
});
}
};
})();
function onSignInCallback(data) {
if(!first_run) {
helper.onSignInCallback(data);
}
first_run = false;
}
</script>
In the Google Plus documentation:
If the user previously agreed to allow your application access through this button, or another button representing the same application, they are automatically logged in. The callback function is called automatically as soon as the sign-in button is rendered and passed a new authorization object with an access token.
I was getting this as well. On my global onSignInCallBack(authResult) function, I enclosed the call that makes the ajax request in an if statement that checks for a value in authResult['access_token']. I'm using AngularJs and moved my Ajax call into my controller. Since you are not using AngularJS, you can replace the gplusController().onSignInCallback(..) line with your AJAX call.
function onSignInCallback(authResult){
if (authResult['access_token']) {
var afToken = document.getElementById('afToken').getAttribute('data-afToken');
gplusController().onSignInCallback(authResult, afToken);
}
}
Related
I am experiecing some issues with AJAX updating the page. The actual data in the database is updated but this is not always reflecting in real time on the web page.
For example, I have the following event:
$("#add_note").click(function(e) {
//e.preventDefault();
$("#add_note_form").validate({
rules: {
contact_note: {
required: true
}
},
submitHandler: function(form) {
contact.modal_update({
'obj' : $('#add_note_form'),
'uri' : '/contact/add_note/'
});
}
});
});
This function when a new note is created calls a callback to validate the form fields first and then if successful calls a callback inside a seperate class to conduct the update. See the modal_update class below:
// Update modal
this.modal_update = function(data)
{//
// Declare a few variables for the data object we've received
obj = data.obj // The form element to serialize
uri = data.uri;
// Get the form ID from the data-target attribute
id = obj.attr('data-target');
// URL to send to
url = this.site_url + uri + id;
// The form object
this.post_data(obj.serialize(),url);
// Hide Modal
obj.closest('.modal').modal('hide');
// Refresh
this.refresh();
}
This then figures out the correct route to ajax and calls a ajax call back inside the same class:
// AJAX post
this.post_data = function(obj,uri)
{
$.ajax({
data: obj,
dataType: 'json',
type: 'post',
url: uri,
headers: { "cache-control": "no-cache" },
cache: false,
success: function (response) {
if (response.success == true)
{
$("#alert_success .msg").html(response.message);
$("#alert_success").fadeIn(200).delay(2000).fadeOut(200);
}
else
{
$("#alert_error .msg").html(response.error);
$("#alert_error").fadeIn(200).delay(2000).fadeOut(200);
console.log(response.error);
}
}
});
}
I am then running another class callback to "refresh" the data in all the elements on the page:
this.refresh = function()
{
// Refresh the ajax requests
this.get_contact_data();
this.get_notes();
this.get_contact_log();
this.get_contact_tasks();
}
This class re loads the functions which run on page load to get the inial data into the tables/fields on the page. See "get_notes" below:
// Get notes
this.get_notes = function()
{
// Get all notes and populate table
var log_uri = this.site_url + "/contact/get_notes/" + this.contact_id;
this.get_data(log_uri,function(data) {
notes = $("#contact_notes ul");
notes.empty("");
// Populate the contact fields, assuming there is a result to play with
if (data != false) {
//alert(JSON.stringify(data));
$("#notes-tab .count").html("(" + data.length + ")");
$.each( data, function( key, value ) {
notes.append("<li class='list-group-item' modal-id='editNoteModal' data-target='" + value.ID + "'><div class='row'><div class='col-lg-3'><i class='fa fa-sticky-note mr-3'></i>" + value.timestamp + "</div><div class='col-lg-7'>" + value.note + "</div><div class='col-lg-2'><a href='#' class='edit mr-3'><i class='fa fa-edit mr-1'></i>Edit</a><a href='#' class='delete'><i class='fa fa-times mr-1'></i>Remove</a></div></div></li>");
});
console.log('Notes loaded');
} else {
notes.append("<li>There are currently no notes for this contact</li>");
}
});
}
Now the problem:
For some reason this does not update consistently in real time. The data is updated fine on the server side but on the client side the update/refresh does not always update. I might add a note and get a correct update response but the refresh method seems to be receiving the old data and always be one note behind. So the next time I add a note, the one I added before then appears and so forth.
Another problem I am experiencing is the methods seem to stack on each event so if I add one note (or one of the other methods) I will see the console say "notes loaded" but on the second note it says "notes loaded" twice, then on the 3rd note added 3 times and so forth.
I am sure there must be something fatal flaw in the design of my code here but I am not experienced enough with javascript/jquery to notice what direction I am going wrong so I can fix it.
I thought that this was an issue with ajax caching and not refreshing the result so I have adjusted the ajax request as cache none and also to send no cache headers. I am running in wamp.
In your case, your refresh code will always run before your data got updated. Because ajax is asynchronous so the code behind and below ajax will always execute nearly the time your ajax running.
At the time you run your post_data function to call the API, the refresh function got run too. So it's done before your data got updated.
You should run refresh function inside ajax callback. For example:
this.post_data = function(obj,uri, callback)
{
$.ajax({
data: obj,
dataType: 'json',
type: 'post',
url: uri,
headers: { "cache-control": "no-cache" },
cache: false,
success: function (response) {
if (response.success == true)
{
$("#alert_success .msg").html(response.message);
$("#alert_success").fadeIn(200).delay(2000).fadeOut(200);
}
else
{
$("#alert_error .msg").html(response.error);
$("#alert_error").fadeIn(200).delay(2000).fadeOut(200);
console.log(response.error);
}
callback();
}
});
}
And in modal_update, you pass refresh function to post_data as a callback:
this.modal_update = function(data)
{//
// Declare a few variables for the data object we've received
obj = data.obj // The form element to serialize
uri = data.uri;
// Get the form ID from the data-target attribute
id = obj.attr('data-target');
// URL to send to
url = this.site_url + uri + id;
// The form object
this.post_data(obj.serialize(),url, this.refresh);
// Hide Modal
obj.closest('.modal').modal('hide');
}
You should read more about asynchronous ajax. You can use other tricky solution is setTimeout to run this.refresh but I do not recommend that because you not sure when the update is done.
I think this will be a weird one for you as I am at my wits end with this. On a screen I have in a table, I have a link being clicked that is setting off a javascript/ajax request. I have similar code in another screen that works perfectly as it heads down into the success part of the ajax call and runs code in the success portion of the call. For some reason though I can't seem to get this to work and when I debug it in chrome, I lose my breakpoints and it never seems to get into the success portion of the Ajax call.
#section scripts{
<script>
// Get the bond ID Data from the row selected and return that to the program.
function getIDData(el) {
var ID = $(el).closest('tr').children('td:first').text();
var iddata = {
'ID': ID
}
console.log(iddata);
return iddata;
}
// Submit the data to a function in the .cs portion of this razor page.
$('.updatelink').click(function () {
var bondid = JSON.stringify(getIDData(this));
$.ajax({
url: '/Maintenance/Bond_Maint?handler=UpdateandReloadData',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
type: 'POST',
dataType: 'json',
data: { bondid: bondid },
success: function (result) {
if (result.pass != undefined) {
document.forms[0].submit();
}
},
});
});
</script>
}
The ASP.net code behind that is calling does an update to the database and then passes back a variable containing Success as its message.
//-------------------------------------------------------------------------------
// Try to get and insert the data from a selected row and copy it
//-------------------------------------------------------------------------------
public ActionResult OnPostUpdateandReloadData(string bondid)
{
return new JsonResult(new { pass = "Success" });
}
I'm not sure how else to describe my issue other than when I debug my other code via the browser, it appears to take a different path than this code does and I cannot fathom why. For reference my other code looks like this:
#section scripts{
<script>
// Get the offender ID Data from the row selected and return that to the program.
function getIDData(el) {
var ID = $(el).closest('tr').children('td:first').text();
var iddata = {
'ID': ID
}
console.log(iddata);
return iddata;
}
// Submit the data to a function in the .cs portion of this razor page.
$('.copybtn').click(function () {
var offenderid = JSON.stringify(getIDData(this));
$.ajax({
url: '/Copy_Old_Account?handler=CopyData',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
type: 'POST',
dataType: 'json',
data: { offenderid: offenderid },
success: function (result) {
if (result.path != undefined) {
window.location.replace(result.path);
}
},
});
});
</script>
}
Any help would be appreciated.
Okay guys so first off, thank you everyone for responding to my question. Frank Writte and Alfred pointed me into the right direction by looking for the status in the network tab for my calls. I found out that I was getting cancellations for my requests. After looking into that I found this article What does status=canceled for a resource mean in Chrome Developer Tools? that has an answer from FUCO that gave me what I needed to do. Apparently I needed to add event.preventDefault(); in front of my ajax call and all of a sudden my code worked. I'm not sure I completely understand why this works but I can't complain about the results. Again thank you everyone for trying to help. This one has been boggling my mind all morning.
I am working on a login page with some pretty animations. I would like to be able to pause the script while I run a custom animation after the user submits the login post. To simplify:
Behavior: user submits login --> load custom animation --> wait 5 seconds --> execute AJAX post --> present error or navigate to home
Here is my code in its most working form
function ValidateUser() {
var userid = $("#Username").attr('value');
var pass = $("#Password").attr('value');
var url = "/Account/ValidateUser";
var $this = $('.login'),
$state = $this.find('button > .state');
$this.addClass('loading');
$state.html('Authenticating');
setTimeout(function () {
$.ajax({
url: url,
data: { username: userid, password: pass },
cache: false,
type: "POST",
success: function (data) {
if (data == "1") {
$this.addClass('ok');
$state.html('Welcome back!');
window.location.href = "Home/Index";
} else {
$state.html('Incorrect username or password!');
$this.addClass('loginError');
$this.removeClass('ok loading');
}
$("#txtuserid").attr({ 'value': '' });
$("#txtpassword").attr({ 'value': '' });
},
error: function (reponse) {
alert(response);
$state.html('An unknown error has occurred!');
$this.addClass('loginError');
$this.removeClass('ok loading');
}
});
}, 5000);
}
After running it through firefox's javascript debugger I noticed that the ajax post is never actually run. I am developing in visual studio using C# and I place a breakpoint on the validate user method but it never hits the breakpoint.
Any help would be appreciated.
EDIT:
Here is the HTML I use to call the ValidateUser method.
<button onclick="ValidateUser()">
<i class="spinner"></i>
<span id="submit" class="state">Submit</span>
</button>
If the button is submitting the form you will have a problem.
A button without type="button" will submit - in some browsers actually submit to the page URL if no form
You likely want
$("#formID").on("submit",function (e) {
e.preventDefault();
var userid = $("#Username").attr('value');....
Below is my code..
HTML Code
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="body">
<div class="dropdown_div">
<select id="q_type" class="dropdown" onchange="getSubject(this.value)">
<option>Question1</option>
<option>Question2</option>
</select>
</div>
<div class="dropdown_div">
<select id="q_subject" class="dropdown">
<option>Subject1</option>
</select>
</div>
</div>
JS Code
function getSubject(val){
$("option", $("#q_subject")).remove();
var option = "<option>Subject</option>";
$("#q_subject").append(option);
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
alert("Hi");
$("option", $("#q_subject")).remove();
var option = "<option>Subject1</option>";
option += "<option value=1234>Subject2</option>";
$("#q_subject").append(option);
}
});
}
How do I use pushState into my code and let user can click back button to return last page and then still see the ajax data?
First of all, you should save data received from ajax request to browser local storage. Afterwards, in order to show ajax result when browser "back" button was fired, you should bind statements that you are calling in ajax.success() method to window onpopstate event. To omit code duplication, it`s better to use a declared function instead of anonymous one.
function success(response) {
alert("Hi");
$("option", $("#q_subject")).remove();
var option = "<option>Subject1</option>";
option += "<option value=1234>Subject2</option>";
$("#q_subject").append(option);
}
Save data to localstorage and call success function:
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
localStorage.setItem("response", response);
success(response);
}
});
Call success() when "back" button was fired:
window.onpopstate = function (e) {
var res = localStorage.getItem('response');
success(res);
}
I would rather suggest you to use sessionStorage which expires when the browser window is closed :)
$.ajax({
url: "api.path",
type: 'POST',
dataType: 'json',
data: {id: id},
async: true,
cache: false,
success: function(response) {
sessionStorage.setItem("DataSaved", response);
success(response);
}
});
And then
window.onpopstate = function (e) {
var res = sessionStorage.getItem('DataSaved');
success(res);
}
You can solve this using the local Storage or Session storage. You will also need to have a onload function callback, to check if there are any previous values that you stored in the local/session storage, if yes, then show that data in the select box.
I noticed this Back() issue when using Ajax to navigate an MVC-5 application from within a JavaScript generated diagram. All clicks in the diagram are handled by Ajax.
Above solutions do not replace the complete body, in the repaired cases a Back() would restore just the edit fields. In my case, I don't need that. I need to replace the entire page from the AJAX and also enable the Back button to return to my original diagram context.
I tried above solution to replace body, and I have to note, it would only trigger the window.pop event after
history.pushState({}, '')
But when the event triggered and it uses Ajax to fill the body, my Javascript would not properly re-initialize the diagram page.
I decided to use another pattern, to circumvent the the window.pop event and avoid the back-issue. Below code will not return into the Ajax code context, but instead simply replace current page, processing the Ajax return information from the server (=Controller) as a redirect link, like
var url = "/ProcessDiagram/MenuClick?command=" + idmenuparent+"_"+citem; // my Ajax
$.get(url,
function (data) {
window.location = data; // Server returns a link, go for it !
return true; // Just return true after going to the link
});
.. this will preserve the Back() context, because the browser will take care of things.
Controller side composes the redirect link, like
public ActionResult MenuClick(string command)
{
List<string> sl = command.Split(new char[] {'_'}).ToList();
var prId = int.Parse(sl[0].Substring(3));
if (sl[1] == "PU")
return Content("/ProductionUnitTypes/Details/" + UnitContextId(prId) );
if (sl[1] == "IR")
return Content("/ItemRoles/Details/" + RoleContextId(prId) );
// etcetera
}
I solved it by including the below code just before the $.get() function
$.ajaxSetup({cache: false});
It works! Try it :)
I have two buttons on the form I'm getting, this first piece of coce allow me to know which was the button clicked by getting the id of it.
var button;
var form = $('.register_ajax');
$('#vote_up, #vote_down').on("click",function(e) {
e.preventDefault();
button = $(this).attr("id");
});
and this other send the form data through AJAX using the info already obtained from the button using the script above.
form.bind('submit',function () {
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
cache: false,
dataType: 'json',
data: form.serialize() + '&' + encodeURI(button.attr('name')) + '=' + encodeURI(button.attr('value')) ,
beforeSend: function() {
//$("#validation-errors").hide().empty();
},
success: function(data) {
if(data.message == 0){
$("#fave").attr('src','interactions/favorite.png');
$("#favorite").attr('value',1);
console.log(data.errors);
}
if(data.message == 1)
{
$("#fave").attr('src','interactions/favorite_active.png');
$("#favorite").attr('value',0);
}
if(data.message == "plus")
{
$("#vote_up").attr('class','options options-hover');
$("#vote_down").attr('class','options');
console.log(data.message);
}
if(data.message == "sub")
{
$("#vote_down").attr('class','options options-hover');
$("#vote_up").attr('class','options');
console.log("sub");
}
},
error: function(xhr, textStatus, thrownError) {
console.log(data.message);
}
});
return false;
});
The problem is that the data is not being passed to the ajax function, the button info is being saved on the button var, but it's not being obtained at time on the ajax call to work with it (or at least that is what I think). I'd like to know what can I do to make this work, any help appreciated.
1st edit: If I get the button data directly like button = $('#vote_up'); it doesn't work either, it only works if I get the button directly like this but without using the function.
2nd edit: I found the solution, I posted below.
var button is in the scope of the .on('event', function(){})
You need to declare the variable in the shared scope, then you can modify the value inside the event callback, i.e.
var button,
form = $('.register_ajax');
$('#vote_up, #vote_down').on("click",function(e) {
e.preventDefault();
button = $(this).attr("id");
});
You are being victim of a clousure. Just as adam_bear said you need to declare the variable outside of the function where you are setting it, but you are going to keep hitting these kind of walls constantly unless you dedicate some hours to learn the Good Parts :D, javascript is full of these type of things, here is a good book for you and you can also learn more from the author at http://www.crockford.com/.
I Found the solution, I just changed a little bit the click function like this:
var button;
var form = $('.register_ajax');
var data = form.serializeArray();
$('#vote_up, #vote_down').on("click",function(e) {
e.preventDefault();
button = $(this).attr("id");
data.push({name: encodeURI($(this).attr('name')), value: encodeURI($(this).attr('value'))});
form.submit();
});
using e.preventDefault(); and form.submit(); to send the form. also I changed the data.serialize to serializeArray(); because it's more effective to push data into the serializeArray(). in the second script I just changed the data.serialize() and used the data variable that I already filled with the serializeArray() and the data.push():
form.bind('submit',function () {
alert(button);
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
cache: false,
dataType: 'json',
data: data,
//here goes the rest of the code
//...
});
return false;
});
it worked for me, it solved the problem between the click and submit event that wasn't allowing me to send the function through ajax.