Global variable keeps being reset to null after ajax call - javascript

what i have is an interesting set of code, whats happening here is that during this signup form once the user gets to this point, it will serialize the data into an array and then use an ajax call to post the information to the database, I have a setup with a payment API that i have to call through an iframe to use correctly, (this is the second set of code below the first). these JQuery statements are defined apart from each other, but within the same <script> tag inside the code. The thing is i need the uriEncodedLink variable from this function to be defined in the global scope so it can be accessed later to be useable from the iframe i call for the payment page.
the problem is, no matter what I do, no matter how i define it in the global scope it seemingly always gets reset after the ajax call posts information to the database. i tried using a var = uriEncodedLink and then setting the string to be called equal to that variable which is defined in the global scope, ive used window.uriEncodedLink = "uri to be called" and tried calling it from the window object. however, to no avail, ive console.logged the data all the way up to the ajax call and it seemingly works appropriately, as you can see from my placed console log of the variable right before the ajax call, in the console. the variable has the correct information which is what i want. however when i call on that variable later, (where the iframe to the payment system is) it becomes null, its as if the ajax call is erasing all data and not just the form data. which is not what i want.
is there anyway to get this variable to work appropriately?
**Note: ** it should be noted that i am unable to move the iframe to the same location as the ajax call, doing so results in weird behavior with the form itself. And yes, i have to use an iframe as i have to pass a certain amount of the form data through the iframe to the payment system.
$(document).bind('next.wizard', function () {
if (wizard.current == wizard.total) {
if ($('form').valid() && $('.username-addon').hasClass('available')) {
//submit form
$(document).trigger('modalloading');
var formdata = {};
$($('form').serializeArray()).each(function (i, a) {
formdata[a.name] = a.value;
});
let str = formdata.inputAdminContactName;
const name = str.split(" ", 2);
uriEncodedLink = "Link to be encoded"
window.uriEncodedLink = uriEncodedLink
console.log(window.uriEncodedLink)
$.ajax('submit.ashx?cp='+wizard.current+'&key=<%=xssToken %>', {
dataType: 'json', type: 'POST'
, data: formdata
, success: function(d) {
$('form').submit();
}
, error: function (xhr) {
window.location.reload(true);
}
});
} else {
$(window).trigger('modal.alert', ['The form has not been filled out correctly, please correct the fields on this page.']);
}
} else {
wizard.next(1);
var formdata = {};
$($('form').serializeArray()).each(function (i, a) {
formdata[a.name] = a.value;
});
$.ajax('submit.ashx?cp='+wizard.current+'&key=<%=xssToken %>', {
dataType: 'json', type: 'POST'
, data: formdata
, error: function (xhr) {
window.location.reload(true);
}
});
}
});
$(document).bind('finished.wizard', function () {
$('.progress-bar').css({ width: '100%' });
$('.innerform').html('<div class="finished"><div class="row clearfix">'+
'<div class="col-md-12 column"><div class="panel panel-default">'+
'<div class="panel-heading"><h2 class="panel-title"><span class="step-title">Almost Finished!</h2></div>'+
'<div style="width: 100%; height: 1100px;">'+
'<iframe id="cps-embed" src="'+window.uriEncodedLink+'"' +
'style="margin:0; width:100%; border:none;" scrolling="no" width="100%" height="1100px"></iframe>'+
'</div></div></div></div></div></div>'
).css({opacity:'0',visibility:'visible'}).animate({opacity:'1'});
});

Related

AJAX query not always updating information consistently

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.

Insert data into MySQL Databse with PHP/AJAX, execute success option AFTER it's inserted (Callback)

I've been trying to make a simple site, and I can't quite wrap my head around some of the things said here, some of which are also unrelated to my situation.
The site has a form with 3 input boxes, a button, and a list. The info is submitted through a separate PHP file to a MySQL database, once the submit button is clicked. I'm supposed to make the list (it's inside a div) update once the info is successfully sent and updated in the database. So far I've made it work with async:false but I'm not supposed to, because of society.
Without this (bad) option, the list doesn't load after submitting the info, because (I assume) the method is executed past it, since it doesn't wait for it to finish.
What do I exactly have to do in "success:" to make it work? (Or, I've read something about .done() within the $.ajax clause, but I'm not sure how to make it work.)
What's the callback supposed to be like? I've never done it before and I can get really disoriented with the results here because each case is slightly different.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
url: "save.php",
method: "POST",
data: { name: name.value, email: email.value, telephone: telephone.value },
success: $("List").load(" List")
});
}
Thank you in advanced and if I need include further info don't hesitate to ask.
From this comment
as far as i know the success function will be called on success you should use complete, A function to be called when the request finishes (after success and error callbacks are executed). isnt that what you want ? – Muhammad Omer Aslam
I managed to solve the issue simply moving the $.load clause from the success: option to a complete: option. (I think they're called options)
I haven't managed error handling yet, even inside my head but at least it works as it should if everything is entered properly.
Thanks!
(Won't let me mark as answered until 2 days)
I would first create an AJAX call inside a function which runs when the page loads to populate the list.
window.onload = populatelist();
function populatelist() {
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'populate'},
success: function(data) { $("#list").html("data"); }
});
}
Note: #list refers to <div id="list> and your list should be inside this.
I would then have another AJAX call inside a different function which updates the database when the form is submitted. Upon success, it will run the populatelist function.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'update', name: name.value, email: email.value, telephone: telephone.value },
success: function() { populatelist(); }
});
}
list.php should look like this:
<?php
if($_POST['function'] == "populate") {
// your code to get the content from the database and put it in a list
}
if($_POST['function'] == "update") {
// your code to update the database
}
?>
I will show you piece of solution that I use in my project. I cannot say it is optimal or best practices, but it works for me and can work for you:
PHP:
function doLoadMails(){
//initialize empty variable
$mails;
$conn = new mysqli($_POST['ip'], $_POST['login'], $_POST['pass'], $_POST['db']);
// Check connection
if ($conn->connect_error) {
die("");
}
//some select, insert, whatever
$sql = "SELECT ... ... ... ";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row, j is counter for rows
$j =0;
while($row_a = $result->fetch_assoc()) {
//for each row, fill array
$mails[$j][0] = $row_a["name"] ;
$mails[$j][1] = $row_a["mail"] ;
$mails[$j][2] = $row_a["language"] ;
$j++;
}
}
//if $mails has results (we added something into it)
if(isset($mails)){
echo json_encode($mails);/return json*/ }
else{
//some error message you can handle in JS
echo"[null]";}
}
and then in JS
function doLoadMails() {
$.ajax({
data: { /*pass parameters*/ },
type: "post",
url: "dataFunnel.php",
success: function(data) { /*data is a dummy variable for everything your PHP echoes/returns*/
console.log(data); //you can check what you get
if (data != "[null]") { /*some error handling ..., in my case if it matches what I have declared as error state in PHP - !(isset($mails))*/ }
}
});
Keep in mind, that you can echo/return directly the result of your SQL request and put it into JS in some more raw format, and handle further processing here.
In your solution, you will probably need to echo the return code of the INSERT request.

Javascript get current page html (after editing)

I have a page that I have edited after load and what I want to do is get the pages current HTML and pass that off to a PHP script.
I first passed document.documentElement.innerHTML but that ended up including a bunch of computed style garbage at the top which I did not want. After googling around I found I could use ajax to get a copy of the current file on the server and then replace the edited part afterwards.
I can get the copy of the file using this:
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
$.ajax({
url: filename,
async: false, // asynchronous request? (synchronous requests are discouraged...)
cache: false, // with this, you can force the browser to not make cache of the retrieved data
dataType: "text", // jQuery will infer this, but you can set explicitly
success: function( data, textStatus, jqXHR ) {
origPage = data; // can be a global variable too...
// process the content...
}
});
Which works fine and gets me the html I expected and see when viewing the page in notepad.
The next step is what I cannot figure out. All I want to do is swap out the innerHTML of a div with an id of 'editor' with what the current value is, so I have tried this:
origPage.getElementById('editor').innerHTML = e.html;
But I get the error "TypeError: undefined is not a function". I must be doing something simple wrong I feel but I don't know the proper formatting to do this. I have tried the following variations:
alert($(origPage).getElementById('editor').innerHTML);
//Different attempt
var newHtml = $.parseHTML( origPage );
alert($(newHtml).getElementById('editor').innerHTML);
//Different attempt
alert($(origPage).html().getElementById('editor').innerHTML);
But I always get "TypeError: undefined is not a function" or "TypeError: Cannot read property 'getElementById' of undefined". How can I do this properly?
EDIT:
Complete page html below:
<!DOCTYPE html>
<html>
<body>
<div id="editor">
<h1>This is editable.</h1>
<p>Click me to start editing.</p>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="snapeditor.js"></script>
<script type="text/javascript">
var editor = new SnapEditor.InPlace("editor", {onSave: function (e) {
var isSuccess = true;
//var origPage = e.html;
var origPage;
var url = window.location.pathname;
var filename = url.substring(url.lastIndexOf('/')+1);
// Actually perform the save and update isSuccess.
// Javascript:
$.ajax({
url: filename,
async: false, // asynchronous request? (synchronous requests are discouraged...)
cache: false, // with this, you can force the browser to not make cache of the retrieved data
dataType: "text", // jQuery will infer this, but you can set explicitly
success: function( data, textStatus, jqXHR ) {
origPage = data; // can be a global variable too...
// process the content...
}
});
//origPage shows expected html as this point
//alert($(origPage).getElementById('editor').innerHTML);
//alert($(origPage).html().getElementById('editor').innerHTML);
$(origPage).getElementById('editor').innerHTML = e.html;//fails here
alert(origPage);
//alert(newHtml.getElementById('editor').innerHTML);
$.ajax({
data: {html: origPage, docName: 'example1.html'},
url: 'savePage.php',
method: 'POST', // or GET
success: function(msg) {
alert(msg);
isSuccess = true;
}
});
return isSuccess || "Error";
},
onUnsavedChanges: function (e) {
if(confirm("Save changes?")) {
if(e.api.execAction("save")){
//location.reload();
}
} else {
e.api.execAction("discard");
}
}});
</script>
</body>
</html>
It seems that you get the user's changes in a variable - you called the var e.html. That is not a good variable name, BTW. If you can, change it to something like htmlEdited
Question: If you add the command alert(e.html); what do you get? Do you see the HTML after user edits?
If yes, then what you need to do is send that variable to a PHP file, which will receive the data and stick it into the database.
Code to send the data:
javascript/jQuery:
alert(e.html); //you should see the user-edited HTML
$.ajax({
type: 'post',
url: 'another_php_file.php',
data: 'userStuff=' + e.html, //var_name = var_contents
success: function(d){
window.location.href = ''; //redisplay this page
}
});
another_php_file.php:
<?php
$user_edits = $_POST['userStuff']; //note exact same name as data statement above
mysql_query("UPDATE `your_table_name` SET `your_col_name` = '$user_edits' ") or die(mysql_error());
echo 'All donarino';
The AJAX javascript code will send the var contents to a PHP file called another_php_file.php.
The data is received as $user_edits, and then inserted into your MySQL db
Finally, I presume that if you redisplay that page it will once again grab the contents of the #editor div from the database?
This is where you haven't provided enough information, and why I wanted to see all your code.
ARE you populating that div from the database? If not, then how do you expect the page to be updated after refreshing the page?
You would benefit from doing some tutorials at phpacademy.org or a thenewboston.com. Do these two (free) courses and you'll be an expert:
https://phpacademy.org/videos/php-and-mysql-with-mysqli
https://phpacademy.org/videos/oop-loginregister-system
If all you need to do is insert the contents of e.html to replace the #editor div, then try this:
$('#editor').html(e.html);
HOWEVER, you need an event to trigger that code. Are you able to do this?
alert(e.html);
If so, then put the first bit of code at that same spot. If not, we need more information about when your code receives that variable -- that is where you put the $('#editor').html(e.html); statement.

How to request a web page in JavaScript

In my site, there's a pervasive search bar that is a typeahead widget. The widget has a 'selected' callback that I am currently trying to implement.
In the callback, it determines whether or not it needs to make an AJAX request on the existing page or whether it needs to go to another page. My problem is that I cannot find anywhere a way to do a redirect with POSTed variables, like in a jQuery AJAX request. Is there any way to attain a page request with posted variables that will totally refresh the page, like clicking on a normal hyperlink?
Here is my code:
function getData(event, datum, dataset) {
event.preventDefault();
// get controller action portion of current url
var Controller = '<?= preg_replace('/\/.*/', '', preg_replace('/\/.*\/web\//', '', Yii::$app->request->url)) ?>';
var Key;
// get key out of key-value pair - will either be 'game', 'developer' or 'publisher'
for (var k in datum) {
Key = k;
}
// if the controller action is the same as key, then the request is ajax
// this works fine
if (Key === Controller) {
var req = $.ajax( {
type: 'POST',
url: 'getchilddata',
data: { data: datum[Key] },
})
.done(function(data) {
$('#display-div').html(data);
})
.fail(function() {
console.log("Failed");
})
} else { // else we need to go to a page on a different controller action according to Key
// this is the best i've got so far but want it to be better
window.location.href = Key + '/datastream?q=' + datum[Key];
}
}
The only way to achieve this is creating a form with hidden inputs, because you can't send post variables via Javascript, fortunately there is a Jquery plugin who will save you some code, but at the end the plugin just create a hidden form and simulate the redirect sending the form via POST, this is how to use it:
if (Key === Controller) {
$.ajax( {...})
} else {
$().redirect(Key + '/datastream, {'q': 'datum[Key]'});
}
Note: You can pass the method (GET or POST) as an optional third parameter, POST is the default

Button callback function running every page load

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);
}
}

Categories

Resources