I would like to fetch all contents from a specific WordPress page but cannot manage to understand how to make it work. I am fetching the link to the WP page (https://mauriciolondono.be/wp/wp-json/wp/v2/pages) with a "GET" request in JS, which is working so far. However, I am not sure how to display the contents of the page (accessible by; content.rendered in the JSON I believe).
The only way I have every displayed content on the web page is by populating an HTML template, but it seems to not be working (maybe the wrong approach in this case?), since I only want the WP content to appear on my site.
function fetchHome() {
let response = fetch(
"https://mauriciolondono.be/wp/wp-json/wp/v2/pages/146",
{
method: "GET",
headers: {
"Content-Type": "application/json;charset=utf-8",
},
body: getHome(),
}
);
}
function getHome() {
const homepageTemplate =
document.querySelector("#homepageTemplate").content;
const homepageTemplateCopy = homepageTemplate.cloneNode(true);
const homepageContainer = document.querySelector("#homepage");
homepageTemplateCopy.querySelector("h2.title").textContent =
"Title: " + `${title.rendered}`;
homepageTemplateCopy.querySelector(
"p.paragraph"
).textContent = `${content.rendered}`;
homepageContainer.appendChild(homepageTemplateCopy);
}
When replacing the .textContent within the template through object notation, I get an error saying that "title" or "content" is not defined.
The GET request does not have a body, so it should be something like this:
function fetchHome() {
// Notice that we are now returning the result from the fetch function
// and we no longer have the body property.
return fetch(
"https://mauriciolondono.be/wp/wp-json/wp/v2/pages/146", {
method: "GET",
headers: {
"Content-Type": "application/json;charset=utf-8",
}
}
);
}
function getHome(response) {
const homepageTemplate = document.querySelector("#homepageTemplate");
const homepageTemplateCopy = homepageTemplate.cloneNode(true);
const homepageContainer = document.querySelector("#homepage");
homepageTemplateCopy.querySelector("h2.title").innerHTML = "Title: " + `${response.title.rendered}`;
homepageTemplateCopy.querySelector("p.paragraph").innerHTML = `${response.content.rendered}`;
homepageContainer.appendChild(homepageTemplateCopy);
}
fetchHome()
.then(response => response.json()) // Converts the HTTP request stream into a JSON object
.then(response => getHome(response)); // You will need to adjust the getHome function accordingly, but now that function receives the request response as a JSON object.
<div id="homepageTemplate">
<h2 class="title"></h2>
<p class="paragraph"></p>
</div>
<div id="homepage">
<h2 class="title"></h2>
<p class="paragraph"></p>
</div>
The fetchHome function now returns a promise, so you will have to attach your callback to it. More on promises can be found on the MDN documentation. I did my best to infer the HTML from your JS but sharing your HTML would be helpful.
As a side note, be careful when injecting content directly into your code, like we are doing with the innerHTML property, if malicious code is present on the JSON response and you attach it to the DOM, you can get an undesired result. So you either trust the content provider or if you cannot, you need to serialize your data before injecting into the DOM.
Related
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'});
});
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'm getting a list of user's data using ajax. But after this ajax call, I have to render a html structure (like a datasheet) with many user's data to each user. My doubt is about how to "store" the HTML code in a functional and elegant way to keep my code readable and allow me insert the users data.
Creating a file with the component template and include it throught javascript is the best idea? If yes, how could I do this? If not, what's the best?
What I have:
Ajax call:
`
$("#list-users").click(function(ev){
ev.preventDefault();
$.ajax({
url : '/ajax/Users.php',
type : 'POST',
dataType: 'json',
data : data,
success : function(users){
users.forEach((user, index) => {
//The problem is here. I'm looking for a way to
//"store" the html component code to dont need put
//the code inside a variable.
var complexHtml = '...<p>' + user.name + '</p>...';
$('.list').append(complexHtml);
})
})
})
`
because it will make the success function very big and unreadable.
... are you looking for this ?
`
var myUSERS = {};
var myUsersLoaded = false;
$("#list-users").click(function(ev){
ev.preventDefault();
$.ajax({
url : '/ajax/Users.php',
type : 'POST',
dataType: 'json',
data : data,
success : fctDo_Stuff_User
})
})
//...
function fctDo_Stuff_User(users) {
users.forEach((user, index) => {
var complexHtml = '...<p>' + user.name + '</p>...';
$('.list').append(complexHtml);
})
`
Using Vue/React/Angular can be a simple solution, because they do the rending job automatically for you.
Without using these frameworks, I usually do the following:
create a html template structure and style it invisible
use jquery clone to create
use jquery to set data
use jquery appendTo to display it.
Example codes are as below:
<div id="target"></div>
<div class="template-code" style="display:none">
<div class="container">
<div class="cls1"></div>
<div class="cls2"></div>
</div>
</div>
<script>
.... ajax success function (){
var div = $(".template-code .container").clone();
$(div).find(".cls1").html("data from ajax result");
$(div).find(".cls2").html("data from ajax result");
.... bind event as well if required ...
$("#target").empty();
$(div).appendTo("#target");
}
</script>
Hope this is helpful.
I use the Jquery .sortable() function to let the site admin re-order some list elements on the start page on a Drupal 7 site. Then I want the admin to be able to save the node to keep this new sort order. In order to do this I added a Save button with js on the client side. When clicked on I have this so far:
$('a.save').on('click', function () {
// get the current nid
var nid = Drupal.settings.mymodule.currentNid;
var data = [];
// copy the re-ordered html list
data['body'] = $('.field-name-body').clone()
$.ajax({
// after reading the ajax api documentation I am more than confused about the url to use
url: '??',
type: 'post',
dataType: "html",
data: {
nid: nid,
body: data['body'].html()
},
success: function(data) {
if (data == false) {
alert('Not saved, access denied.');
} else {
alert('Changes saved');
}
}
});
So in the normal world I would write a php script that saves the data in the node with the specified node id. And the url should point to that script... But I am stuck in the Drupal 7 documentation on how to do this... All examples i can find describes how to pull html from the server side to the client side, but I want to copy html from the client side and save it in the specfied node on the server side. Should I write a function to recieve the ajax request in a custom module? Can anyone point me in the right direction?
PARTIALLY SOLVED:
I finally found the solution about the url which became like this:
url: Drupal.settings.mymodule.ajaxUrl + "/" + nid,
I have now written a custom module where I successfully can save content in a certain node field with this code:
function save_node_init() {
drupal_add_js(array('save_node' => array('ajaxUrl' => url('save_node/ajax'))), 'setting');
drupal_add_js(drupal_get_path('module', 'save_node') . '/save_node.js');
}
function save_nod_menu() {
$items['save_node/ajax/%'] = array(
'page callback' => 'save_node_ajax_callback',
'access callback' => 'user_access',
'access arguments' => array('administer users'),
);
return $items;
}
function save_node_ajax_callback() {
$html = isset($_POST['body']) ? $_POST['body'] : null;
$nid = isset($_POST['nid']) ? $_POST['nid'] : null;
$node = node_load($nid);
$node->body['und'][0]['value'] = $html;
node_save($node);
//ajax_deliver($html);
drupal_exit();
}
As you can see I put the html in the body of the node and then saves it. My final problem is now that I don't want to replace the whole content in the body field. Just the ul and its list elements. Any suggestions would be much appreciated!
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.