I'm attempting a make random quote machine with a tweet button to tweet the quote.
The random quote is coming up just fine.
The code..
var forismaticAPI = 'http://api.forismatic.com/api/1.0/?method=getQuote&format=jsonp&lang=en&jsonp=?';
$(document).ready(function() {
var template = function(data) {
$('#quotearea').empty();
$('#quotearea').append('<blockquote id="quote">' + data.quoteText + '</blockquote>' + '<p id="author"> — ' + data.quoteAuthor + '</p>');
$('#quotearea').show();
};
var dataAppend = function() {
$.getJSON(forismaticAPI, template);
};
}
My next task is to get the quote content to be tweeted. So once the window loads completely i want to get the innerHTML of #quote which contains the quote. So i write a window.onload function like this..
window.onload = function(){
var quote = document.getElementById('quote');
console.log(quote.innerHTML);
}
But I'm getting an error Uncaught TypeError: Cannot read property 'innerHTML' of null(…).. Since there is small delay in loading the quote, the window load function returns a null. How to get the innerHTML of a div only when the content is loaded and ready?
Your #quote element is created after the window.onload event, because it's only created on the return of your ajax call. Move the code from onload to success of the ajax call, as BlueBoy suggested in comments. In your case, the success function is the one you named template.
You can access your element immediately after creating it:
var template = function(data) {
$('#quotearea').empty();
$('#quotearea').append('<blockquote id="quote">' + data.quoteText
+ '</blockquote>' + '<p id="author"> — ' + data.quoteAuthor + '</p>');
$('#quotearea').show();
console.log(document.getElementById('quote'));
};
You can't call the innerHTML method on DOM elements that do not exist yet. So the first moment you can run your function is after the append() call, which is creating a DOM element with and id of quote.
Without testing it, my guess is that onload is firing before the document ready. So you may want to 1) set a flag when the content has been written, Then 2) check in the second function, if null schedule it to run again in 100 ms using setTimeout().
use the html function?
var code = $('#quotearea').html();
Related
For class, I'm trying to build a single page web page using jquery. One of the components of this is changing the HTML to find the correct ID to show the proper information needed.
I'm running into an issue where after the HTML is changed, the HTML is reverted to its original text. I've done some googling and I learned that it's reverting because of the page switch. Most of the questions already asked about this are dealing with form submissions so I'm not really sure how to deal with it in my case.
What I've tried already is having a global variable that keeps track of the ID but when I switch pages, the global variable also gets reset to its original value. I know that the value is getting reset because I have a console log of before and after.
function createList() {
let liArray = Array.from(document.getElementsByClassName("oneMusic"));
liArray.forEach(function (element) {
element.addEventListener("click", function () {
var parm = this.getAttribute("data-parm"); // passing in the record.Id
document.getElementById("IDparmHere").textContent = parm;
console.log(
"parm: " + document.getElementById("IDparmHere").innerHTML
);
param = parseInt(parm);
console.log("param" + param);
// now jump to our page that will use that one item
setTimeout(() => {
document.location.href = "index.html#details";
}, 1000);
});
});
}
And then the code that handles transferring pages. To note, param is the global var.
document.addEventListener("DOMContentLoaded", function (e) {
createList();
$(document).on("pagebeforeshow", "#details", function (event) {
console.log("param 2: " + param);
let localID = param;
let idx = GetArrayPointer(localID);
console.log("local id: " + localID);
console.log("arrayPointer: " + arrayPointer);
document.getElementById("oneTitle").innerHTML =
"The title is: " + songArray[idx].Song;
});
});
So the createList() does a bunch of things but at the end of it, it adds an event listener to each of the li elements. When you click on it, you pull the specific ID of that li and then you get transferred to the details page.
By the time the code reaches the details page, both the HTML and the global var revert back to their original values, which makes it useless in figuring out the ID.
For example, if #IDparmHere was changed from "blank" to "1", then after the page switch happens, #IDparmHere is changed back to "blank".
I set the global var as null initially, after it's changed from null to 1 or 2 or 3, after the page switch it goes back to null.
Also, parm is supposed to be "param" but the instructor that gave us the skeleton of this code has dyslexia so..
If I am here asking it is because we are stuck on something that we do not know how to solve. I must admit, we already searched in StackOverflow and search engines about a solution.. but we didn't manage to implement it / solve the problem.
I am trying to create a JavaScript function that:
detects in my html page all the occurrences of an html tag: <alias>
replaces its content with the result of an Ajax call (sending the
content of the tag to the Ajax.php page) + localStorage management
at the end unwraps it from <alias> tag and leaves the content returned from ajax call
the only problem is that in both cases it skips some iterations.
We have made some researches and it seems that the "problem" is that Ajax is asynchronous, so it does not wait for the response before going on with the process. We even saw that "async: false" is not a good solution.
I leave the part of my script that is interested with some brief descriptions
// includes an icon in the page to display the correct change
function multilingual(msg,i) {
// code
}
// function to make an ajax call or a "cache call" if value is in localStorage for a variable
function sendRequest(o) {
console.log(o.variab+': running sendRequest function');
// check if value for that variable is stored and if stored for more than 1 hour
if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
console.log(o.variab+': value from localStorage');
// replace <alias> content with cached value
var cached = window.localStorage.getItem(o.variab);
elements[o.counter].innerHTML = cached;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(window.localStorage.getItem(o.variab),o.counter);
} else {
console.log(o.variab+': starting ajax call');
// not stored yet or older than a month
console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
$.ajax({
type: 'POST',
url: my_ajax_url,
data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
success: function(msg){
// ajax call, storing new value and expiration + replace <alias> inner html with new value
window.localStorage.setItem(o.variab, msg);
var content = window.localStorage.getItem(o.variab);
window.localStorage.setItem(o.variab+'_exp', +new Date);
console.log(o.variab+': replacement from ajax call');
elements[o.counter].innerHTML = content;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(msg,o.counter);
},
error: function(msg){
console.warn('an error occured during ajax call');
}
});
}
};
// loop for each <alias> element found
//initial settings
var elements = document.body.getElementsByTagName('alias'),
elem_n = elements.length,
counter = 0;
var i = 0;
for(; i < elem_n;i++) {
var flag = 0;
console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
sendRequest({
variab : elements[i].innerHTML,
api_key : settings.api_key,
language : default_lang,
counter : i
});
$(elements[i]).contents().unwrap().parent();
console.log(elements[i].innerHTML+': wrap removed');
}
I hope that some of you may provide me some valid solutions and/or examples, because we are stuck on this problem :(
From our test, when the value is from cache, the 1st/3rd/5th ... values are replaced correctly
when the value is from ajax the 2nd/4th .. values are replaced
Thanks in advance for your help :)
Your elements array is a live NodeList. When you unwrap things in those <alias> tags, the element disappears from the list. So, you're looking at element 0, and you do the ajax call, and then you get rid of the <alias> tag around the contents. At that instant, element[0] becomes what used to be element[1]. However, your loop increments i, so you skip the new element[0].
There's no reason to use .getElementsByTagName() anyway; you're using jQuery, so use it consistently:
var elements = $("alias");
That'll give you a jQuery object that will (mostly) work like an array, so the rest of your code won't have to change much, if at all.
To solve issues like this in the past, I've done something like the code below, you actually send the target along with the function running the AJAX call, and don't use any global variables because those may change as the for loop runs. Try passing in everything you'll use in the parameters of the function, including the target like I've done:
function loadContent(target, info) {
//ajax call
//on success replace target with new data;
}
$('alias').each(function(){
loadContent($(this), info)
});
So basically my code checks if an HTML element has the value of not 0, if it doesn't sets a timer to change the page title to a notification type of text.
I'm really, really new to JS, so I don't know why this did not work, I tried getElementById("licon liconspan") aswell, nothing.
EDIT: Okay, so I got this to work how I want it, here's the code:
function changeTitle() {
var title = document.title;
var variable = document.querySelector('.liconspan').innerHTML;
if ((variable) !== 0) {
setTimeout(changeTitle, 3000);
document.title = 'You have ' + variable + ' unread messages!';
}
}
changeTitle();
Question though, how can I make it switch back and forth with a title, for example "You got a message" for three seconds then "Page Title" for another three seconds then "You got a message" again, etc..
Since you are using jQuery you can get the element by class using a proper selector and check its value, to change the document title you don't need jQuery.
Alternatively you can use getElementsByClassName:
The Element.getElementsByClassName() method returns a live
HTMLCollection containing all child elements which have all of the
given class names. When called on the document object, the complete
document is searched, including the root node.
Code:
function changeTitle() {
var title = document.title;
if (parseInt($('.liconspan').val()) !== 0 ) {
setTimeout(changeTitle, 3000);
document.title='>'+title;
}
}
changeTitle();
Demo: http://jsfiddle.net/c9p670ra/
I've finished off a script that runs on a page that contains a textarea where an email goes.
I'm doing a variety of things on this page, however one of these is to load an iframe, based on a selected number, then once the iframe loads grab the relevant details I need from this page.
I've written the code for this inside a function called frameLoaded and I'm setting this as the onload event, yet the script still runs in to an error where it can't find the .innerHTML of an element.
If I load the iframe and then execute this script it works fine, however if I try to load the iframe and execute the script together then it runs in to this error.
Here's the code I'm using:
//Getting text currently in the textarea
var selectedTxt = document.getElementById('txtEmailText').value;
//Converting it to a string - this is just for troubleshooting purposes that I've used two variables
var insertText = selectedTxt.toString();
//Loads in the highlighted purchase number
var purchaseNumber = window.getSelection();
purchaseNumber = purchaseNumber.toString();
//Declares global variables to hold the title and number
var purchaseTitle;
var purchaseNumber;
//Function to execute code to grab title and number once the frame has loaded
function frameLoaded() {
var iframe = document.getElementById('purchaseIframe');
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
purchaseTitle = innerDoc.getElementById('listingTitle');
purchaseNumber = innerDoc.getElementById('auctionSoldIdDisplay');
}
//Checks to see if a purchase number has been selected
if(purchaseNumber.length > 0){
var purchaseIframe = document.createElement('iframe');
purchaseIframe.src = 'http://www.mysite.co.nz/Admin/Listing/PurchaseDisplay.aspx?asid=' + purchaseNumber + '&submit1=++GO++';
purchaseIframe.setAttribute("height","1000");
purchaseIframe.setAttribute("width","100%");
purchaseIframe.setAttribute("id","purchaseIframe");
purchaseIframe.setAttribute("onload", "frameLoaded();");
void(document.body.appendChild(purchaseIframe));
}
//Converting the value in the title to readable text
purchaseTitle = purchaseTitle.innerHTML;
//Placing the values in to the format I need
var purchaseDetails = purchaseTitle + " - " + purchaseNumber;
//Placing the values in to the string to go back in to the email textarea
insertText = insertText.replace("PURCHASEDETAILS", purchaseDetails);
//Pasting the variable in to the textarea
document.getElementById('txtEmailText').value = insertText;
Am I doing something wrong here or using the wrong event as it seems to me that maybe it's trying to grab the values before the iframe has fully loaded, hence the error when I'm generating the iframe at the same time.
Please note that I cannot use JQuery
window.onload = function() is your answer.
Note in the example below, the first instance of document.getElementById('mydiv') returns null because the page (DOM) was not yet loaded and therefore neither was the div.
The second instance is fired on the windows.onload which means all the page content is present and can therefore be found.
<script type='text/javascript'>
console.log("Page not ready:" + document.getElementById('mydiv'));
window.onload = function() {
console.log("Page ready:" + document.getElementById('mydiv'));
}
</script>
<div id="mydiv">
</div>
I'm working on some legacy code in javascript and I have a problem I can't work out.
When the document first loads, a JS function named addDecisionStateDetailsFields() gets invoked. This method generates HTML which it appends to a certain div. The Ctrl C, Ctrl V version is at pastebin.
So when a document first loads, I get the required HTML. But in another case I have to call that same function via AJAX and I did something like:
function editSPDecision(decision){
$('#serviceProcedureAddDecision').css('display', 'none');
jQuery.ajax({
type:'POST',
data: { 'decisionId': decision.id, 'authorizationId': ${authorizationId} },
url:'../editDecision/${id}',
success: function(data,textStatus) {
jQuery('#serviceProcedureEditDecision').html(data);
},
complete: function(XMLHttpRequest,textStatus) {
attachDatePickerClasses();
addDecisionStateDetailsFields("spDecision_approve", "approveDiv", "Approve", "${ReviewerApproveReason.getValueCommaSeperated()}", "${ReviewerApproveReason.getNameCommaSeperated()}");
}
});
}
Here, I've invoked the method addDecisionStateDetailsFields() with the right params. But after the AJAX call completes, I can't get the generated HTML appended to the HTML of the page.
To cross check, I put an alert inside the method and after the AJAX call completes the method in fact gets invoked, only that the generated HTML is not appended to the div. Is there ssomething that I'm missing here?
Inside the addDecisionStateDetailsFields right before
$('#' + masterParentDiv).append(generatedStr);
can you do
alert($('#' + masterParentDiv).length);
That will tell you whether the masterParentDiv is found, if its found you should get back something other than 0.
Not 100% sure about that I am going to say but, change
$('#' + masterParentDiv).append(generatedStr);
to
jQuery('#' + masterParentDiv).append(generatedStr);