This is a little complicated, but let me try to sum-up. I have two sets of Javascript code that use AJAX and JSON (and PHP and ...) to get specific data and load a set of controls. In one case, called from a click event handler all the controls are loaded properly with the correct data, all is well. In the second, when the page first loads (called properly, the code does execute when the page loads and it does return values), unless I add an alert() dialog in the code, several controls do not actually get loaded. If the alert() is in the function, the controls are loaded. This is, to put it mildly, confusing.
The code that doesn't work is identical to the code that does. Here's the code called when the form loads:
function getFirstAward()
{
// this has to go get the first award at the top of the list
// (sort order) by rank and date, and return that to the entryfields:
var namecode = document.getElementById("namecode").value;
// now we need to set up the Ajax code to return just this specific
// award, and stuff it into the fields above ..
$.ajax
({
type: "POST",
url: "<?php echo $admin_html_RootPath; ?>lookups/returnFirstAward.php",
data: { 'namecode' : namecode },
dataType: "json", // return value is json array
//cache: false,
success: function(data)
{
// why is this necessary?
//alert( "First Award in List loaded" );
// first get the data array and break it up ...
document.getElementById("awardcode").value = data[0];
document.getElementById("currentaward").value = data[1];
getAwards();
document.getElementById("awardnumber").value = data[2];
document.getElementById("awarddate").value = data[3];
document.getElementById("eventname").value = data[4];
document.getElementById("region").value = data[5];
// Barony ... is it empty? If not, enable it, and set the value
if ( data[6] != "" )
{
document.getElementById("barony").disabled = false;
document.getElementById("barony").value = data[6];
}
else
{
// empty, enable, set value to empty, and disable it
document.getElementById("barony").disabled = false;
document.getElementById("barony").value = "";
document.getElementById("barony").disabled = true;
}
document.getElementById("royalcode").value = data[7];
// this one is necessary because of the way the code for getRoyals works:
document.getElementById("currentroyalcode").value = data[7];
getRoyals();
document.getElementById("notes").value = data[8];
tinymce.get('notes').setContent(data[8]);
document.getElementById("laurelprimary").value = data[9];
tinymce.get('laurelprimary').setContent(data[9]);
document.getElementById("laurelsecondary").value = data[10];
tinymce.get('laurelsecondary').setContent(data[10]);
// set focus on the currentaward entry:
document.getElementById("currentaward").focus();
}, // end success
error: function( xhr, textStatus, err )
{
//alert( data );
alert( xhr + "\n" + textStatus + "\n" + err );
} // end error
}); // end ajax call
} // end of function: getFirstAward
If I uncomment the alert() dialog, all the controls appear correctly. If not, the last four do not. I have tried reiterating that code to see if that helped (setting the value for the different controls, etc.) and it didn't make a difference. I tried using location.reload() and it didn't do any good (whether with the parameter or not: location.reload(true), makes no difference).
I think your code get executed before page loads completely and missed out few details/value needed for proper code execution. Try the following
setTimeout(function() {
getFirstAward();
}, 0); // try changing the duration from 0 to 100/500 whichever works for u.
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.
How can I pass data from a query in php and set it's result using an ajax method.
Here is what I have so far in a file called file1.php:
<script type = "text/javascript">
function myAjax () {
$.ajax( { type : 'POST',
data : { },
url : 'query.php',
success: function ( data ) {
$doc = new DomDocument();
$doc->Load('file2.php');
$element = $doc->getElementById('resultFromFile1');
},
error: function ( xhr ) {
alert( "error" );
}
});
}
</script>
I wanna put the contents in this html element in the php file file2.php:
<p id ="resultFromFile1" name = "results">No Results</p>
Many stack overflow posts haven't been any help. Could someone point me in the right direction?
It's wrong approach.
You should rather create php script which will save your ajax request data in let's say database and then in file2.php load this data from DB, not directly update file
First of all what kind of content is query.php returning? Is it a JSON Object or are you just "echoing" the output as a string?
Next Question: Are you using jQuery, AngularJS or something in that direction?
Usually what you want to do is get the information from the "query.php" and pass it as a JSON formatted ajax result...
Now to your actual Problem: You want to get the element called "resultFromFile1" that's inside file2.php but you aren't adding anything to the "visible scope" yet since Load only loads the content but it doesn't add the content to any element you have to define an element holding your "file2.php". If i were you to avoid all these Problems i would use AngularJS for displaying your data in to a view and just include your "result" template via ng-include and let the ajax fill the document..
To solve your Problem:
<script type = "text/javascript">
// Your Solution
function myAjax () {
$.ajax( { type : 'POST',
data : { },
url : 'query.php',
success: function ( data ) {
$doc = new DomDocument();
$doc->Load('file2.php');
$element = $doc->getElementById('resultFromFile1');
},
error: function ( xhr ) {
alert( "error" );
}
});
}
// My Solution for this problem using native js
// Load the "file2" contents in to the file2Holder element
LoadUrlToElement('file2.php','file2Holder',function(data){
/* When the first loading of file2.php is done, load the results from the query.php and put it in to the element called "resultFromFile1" which we just loaded and placed in to the dom before. But i would recommend you to use AngularJS to avoid this Callback hell and get many cool features that webdevelopers don't want to miss these days.... */
LoadUrlToElement('query.php','resultFromFile1',function(){
alert('Content of resultFromFile1 is => '+document.getElementById('resultFromFile1'));
});
});
function LoadUrlToElement(url,elementID,done) {
$.ajax( { type : 'POST',
data : { },
url : url,
success: function ( data ) {
if(document.getElementById(elementID) === undefined){
alert("Can't proceed cause the content holder"+elementID+" is not found");
return; // Abort here cause there is no container with this id...
}
document.getElementById(elementID).html = data;
if(done !== undefined && typeof done === 'function') done(data);
},
error: function ( xhr ) {
alert( "error" );
}
});
}
</script>
<div id="file2Holder"></div>
I have this laravel code in my controller detach function.
$input = Input::all();
$product= Products::findOrFail($input['product_id']);
$product->tags()->detach($input['tag_id']);
$product= Products::where('customer_id', Auth::user()->customers_id)->get();
return view('products.tagsdelete', [
'products' => $product,
]);
This works fine, it deletes the tag realation from my pivot table. The only thing that bugs me it that I don't want to reload the page everytime I press the delete button on my view.
( Of course I could make a selection of all tags the user want to delete, but I want to to this live with Ajax )
My problem is, I couldn't find anything that helps me with detachment from laravel + Ajax. I'm quite okay with Javascript and Jquery but Ajax is still a new thing for me..
So can anybody help me there? I'm really stuck.
Thanks for taking your time :)
#Wiriya Rungruang
current controller code:
public function detach()
{
$input = Input::all();
$product= Products::findOrFail($input['product_id']);
$product->tags()->detach($input['tag_id']);
$product= Products::where('customer_id', Auth::user()->customers_id)->get();
}
my button:
<button type="submit" class="delete-tag-btn" data-product_id="{{ $product->id }}" data-tag_id="{{ $tag->id }}"><i class="glyphicon glyphicon-trash"></i></button>
at the bottom of the code the JS:
<script>
$(".delete-tag-btn").on('click', function(){
var url = "{{ route('detach') }}"; // Url to deleteTag function
url += "product_id=" + $(this).data('product_id');
url += "&tag_id=" + $(this).data('tag_id');
// Now url should look like this 'http://localhost/deletetag?product_id=2&tag_id=5
// Send get request with url to your server
$.get(url, function(response){
alert("success");
});
});
</script>
First : You should create function detach tag from product in your controller and return status success or failure(or nothing)
In your controller
function detachTag(){
$input = Input::all();
$product= Products::findOrFail($input['product_id']);
$product->tags()->detach($input['tag_id']);
$product= Products::where('customer_id', Auth::user()->customers_id)->get();
return "Some state for checking it a success or not";
}
Second : Create javascript function for checking when you click on delete button send request with parameter to function that we created in the first step and rerender or remove that tag from your HTML page
**Parameter is mean product_id and tag_id that your want to detach it
In your js
$(".delete-tag-btn").on('click', function(){
var url = "localhost/deletetag?"; // Url to deleteTag function
url += "product_id=" + $(this).data('product_id');
url += "&tag_id=" + $(this).data('tag_id');
// Now url should look like this 'http://localhost/deletetag?product_id=2&tag_id=5
// Send get request with url to your server
$.get(url, function(response){
// Do what you want
});
});
So when you click on .delete-tag-btn It will send request for detach it
While you can right a simple ajax call, send data and return html and replace it with the old html
lets begin :)
first step is to write ajax, and send it when form is submit or any button is clicked (as per your code)
this one is sample ajax, just fill in your data in it.
var BASEURL = window.location.origin + "/your_domain_name/";
$.ajax({
url: BASEURL + "your_route",
type: "POST/GET", //any_one
data: {
// Your data comes here (object)
},
beforeSend: function () {
},
success: function (response) {
console.log(response); // your html in return
},
complete: function (response) {
}
});
now a call will be send with your data to controller respective to specified route you mentioned, processing will be normal.
It will return only html. You can do whatever you want with this html.
One important problem you might face if considering these instructions is, right now the view you are returning is probably of whole page (because the page is been refresh every time), but if you are thinking to replace it with new html, your will only have to return that part of the page may be a single row or something like that. So break your view in many sub views. Php #include(//path) (blade) might come handy. Thats how I use to work. :)
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.
Use Case: I want to represent some text with ellipsis (e.g. My name is ...) in a HTML LINK/ anchor, where the text is fetched by an ajax call.
Whenever the user clicks the link, I load the text completely in a modal dialog box) by making the same ajax call used to fetch the text.
Here is the code:
"aoColumns": [
<Some code for columns>
{"mData": "id", sWidth:"180px","mRender": function ( data, type, full ) {
var obj = JSON.parse(JSON.stringify(full));
JSRoutes.com.app.controllers.File.getContent(obj["fileId"]).ajax({
data: {},
success: function(data) {
console.log("This is the data I want to represent in ellipsis: " + data);
}
});
return "<a>" + <HOW TO PUT CONTENT (data) HERE> +"</a>";
]
Problem: How to make the ajax call to fetch file content and provide the anchor element's text at the same time. Because by the time we 'return', the ajax call might not have finished.
I might not have been successful in explaining the question clearly, so comments and questions are welcome to improve the question.
Finally, I went with using the element id to modify the text later in the ajax function success callback.
As the file Ids are unique, I can provide unique HTML anchor ids.
"aoColumns": [
<Some code for columns>
{"mData": "id", sWidth:"180px","mRender": function ( data, type, full ) {
var obj = JSON.parse(JSON.stringify(full));
JSRoutes.com.app.controllers.File.getContent(obj["fileId"]).ajax({
data: {},
success: function(data) {
var linkText = "";
var n = 70;
if (data.length > n) {
linkText = data.substr(0,n) + " ...";
} else {
linkText = data;
}
$( '#file_'+obj["fileId"]).text(linkText);
}
});
return "<a> id=file_" + obj["fileId"] + ">" + "This will be loaded soon" +"</a>";
}
]
The first letter 'a' in 'ajax' stands for async, means you cannot get the result directly, but the result will be provided to your callback function later.
In your example:
JSRoutes....ajax({
success: function(data){
// async callback
}
});
This success function is which will be executed after the ajax returns.
So that you should return an empty <a> element first, and fill the content later in the callback.
example:
var a = document.createElement('a');
JSRoutes......ajax({
success: function(data){
a.textContent = data;
}
});
return a;
AJAX are asynchronous. so if you want to finish the some task first and calling the second function only after the completion of the first one than you have to write it in Javascript function instead of calling it in jQuery.