I am trying to replace the list of paragraphs with only one random paragraph, but for some reason the JavaScript code will not do the job.
I have tried rearranging the variables after the function has ended, but I can't figure out what's wrong.
This is how my HTML elements begin:
<body>
<div id = "quotes">
<p>“Art is the supreme task and the truly metaphysical activity in this life.”</p>
<p>“Underneath this reality in which we live and have our being, another and altogether different reality lies concealed.”</p>
<p>“We obtain the concept, as we do the form, by overlooking what is individual and actual; whereas nature is acquainted with no forms and no concepts, and likewise with no species, but only with an X which remains inaccessible and undefinable for us.”</p>
<p>“Everything which distinguishes man from the animals depends upon this ability to volatilize perceptual metaphors in a schema, and thus to dissolve an image into a concept.”</p>
<p>“Our destiny exercises its influence over us even when, as yet, we have not learned its nature: it is our future that lays down the law of our today.”</p>
And this is my attempt at DOM manipulation:
"use strict";
const quotes = document.querySelectorAll("p");
const randomize = function() {
let num = (Math.floor(Math.random() * Math.floor(quotes.length)) - 1);
let quote = quotes.item(num).innerHTML;
return quote;
}
let randomQuote = randomize();
let passage = document.getElementById('quotes').innerHTML;
passage = randomQuote;
console.log(randomQuote);
The only way to change the HTML of a node (with innerHTML) is to assign to its innerHTML property, which invokes an internal setter operation. Extracting the innerHTML of a node into a variable and then reassigning that variable won't do anything. (reassigning a variable reference to something else won't ever change anything, by itself.)
So, use
document.getElementById('quotes').innerHTML = randomQuote;
You also need to fix your num random number generator - use Math.floor(Math.random() * quotes.length); to generate a number between 0 and quotes.length - 1, otherwise num will sometimes be -1 (whose index doesn't exist, of course):
"use strict";
const quotes = document.querySelectorAll("p");
const randomize = function() {
const num = Math.floor(Math.random() * quotes.length);
return quotes.item(num).innerHTML;
}
const randomQuote = randomize();
document.getElementById('quotes').innerHTML = randomQuote;
<body>
<div id="quotes">
<p>“Art is the supreme task and the truly metaphysical activity in this life.”</p>
<p>“Underneath this reality in which we live and have our being, another and altogether different reality lies concealed.”</p>
<p>“We obtain the concept, as we do the form, by overlooking what is individual and actual; whereas nature is acquainted with no forms and no concepts, and likewise with no species, but only with an X which remains inaccessible and undefinable
for us.”</p>
<p>“Everything which distinguishes man from the animals depends upon this ability to volatilize perceptual metaphors in a schema, and thus to dissolve an image into a concept.”</p>
<p>“Our destiny exercises its influence over us even when, as yet, we have not learned its nature: it is our future that lays down the law of our today.”</p>
The problem lies here:
let passage = document.getElementById('quotes').innerHTML;
passage = randomQuote;
You should do:
let passage = document.getElementById('quotes');
passage.innerHTML = randomQuote;
Why
In this line:
let passage = document.getElementById('quotes').innerHTML;
You are actually getting the reference of a string from .innerHTML to passage, not the element itself.
Therefore, in the next line:
passage = randomQuote;
You are only replacing the string with a another string, instead of replacing the property value of an element. Because passage is not an element, it is a string.
In your example instead of assigning new quote to the innerHtml, you just change the variable with value for it that doesn't keep reference to the innerHtml anymore, just it's value
Just change this:
let passage = document.getElementById('quotes').innerHTML;
to:
document.getElementById('quotes').innerHTML= randomQuote;
The issue is that
let passage = document.getElementById('quotes').innerHTML;
Sets the value of passage to the instantaneous value of the innerHTML of quotes, it is not a reference (which is not possible in javascript btw).
passage = randomQuote;
Just overwrites the value of passage with the random quote. Instead you should write
document.getElementById('quotes').innerHTML = randomQuote;
Related
This is gonna be a bit of a weird one b/c I can't provide the actual input for the test case. On the codingGame website there is an exercise where I have to find the lowest difference between integers. I create a variable, but leave it undefined and later use it to hold the lowest difference
function shortest(horses){
let short;
horses.sort((a,b) => a - b).forEach((horse,i) => {
let dif = horse - horses[i-1];
if (dif < short || !short) short = dif;
});
return short;
};
This passes all the tests but one, and the only way to solve the failed one is to assign a value to short instead of leaving it undefined (like let short = 10000000000000);
The website, annoyingly, won't give out the input so I'm not sure why the code is behaving this way so does does anyone know why leaving it undefined instead of a value will cause problems?
I want to change the content of a div randomly by .InnerHTML. The text are saved as variables. The random number is another variable. The Problem is, that if I put text and random number together it will print text1 for example.
Can someone help me with that?
function switchText(){
var text1 = "hello";
var text2 = "there";
var text3 = "ObiWan";
var randomNumber = Math.floor(Math.random() * 3) + 1;//creates random No. from 1 - 3
document.getElementById("randomText").innerHTML = "text" + randomNumber;
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
How about storing all random strings in an array, like so:
function switchText(){
var randomWords = ["hello", "there", "ObiWan"];
var randomIndex = Math.floor(Math.random() * 3);//creates random No. from 1 - 3
document.getElementById("randomText").innerHTML = randomWords[randomIndex];
//the problem
}
Actually you can access those variables by using index notation (it's described really nicely here) so in your specific case of function you just need to change the line where you try to access the variable to
document.getElementById("randomText").innerHTML = this['text' + randomNumber];
However though such notation is not something I would recommend. Usage of array as it was suggested is much more readable in fact.
Store those texts into an array and use the random number.
Get the random number as follow: Math.floor(Math.random() * 3)
function switchText(){
var texts = ["hello", "there", "ObiWan"];
var randomNumber = Math.floor(Math.random() * 3);//creates random No. from 1 - 3
console.log(randomNumber)
document.getElementById("randomText").innerHTML = texts[randomNumber];
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
You can store those texts into an object as well.
function switchText() {
var texts = {
"text1": "hello",
"text2": "there",
"text3": "ObiWan"
};
var randomNumber = Math.floor(Math.random() * 3) + 1; //creates random No. from 1 - 3
console.log(randomNumber)
document.getElementById("randomText").innerHTML = texts[`text${randomNumber}`];
//the problem
}
<div id="randomText" onclick="switchText();">click here</div>
Your question is focused on how to dynamically construct a variable name, but usually this problem comes up because the solution you are attempting is based on a coding pattern that has boxed you into a corner. Instead of writing a potentially hazardous solution or one that is overly complex, re-think your approach.
Whenever you have several pieces of data to store that don't have key names to go with them, you should be storing those data in an Array. The advantages to storing data in an array are huge. So, you should place the strings into an array instead of individual variables that all have to have similar names. So, now you have less variables to worry about and no variable names that have to be set to certain values and the problem of dynamically creating a variable name is gone entirely.
All you need to do now is to use the random number as an index to the array. Don't adjust the random to make it 1-based, because arrays are 0-based. And, when you get the random, multiply it by the length of the array, rather than hard code a number. This way, all you have to do is add/remove strings to the array for them to become possible resulting strings.
This structure and solution make your code simpler and more flexible.
Also, don't set up your event handlers using HTML event attributes. There are many reasons why you shouldn't use this 25+ year old technique. Do it in JavaScript.
var strings = ["hello","there","ObiWan"]; // Store the possible strings in an array
var btn = document.getElementById("randomText"); // Get a reference to the trigger element
var output = document.getElementById("output"); // And the output area
// Set up the event handler in JavaScript, not HTML
btn.addEventListener("click", function(){
// Set the output to a string from the array using a random index
output.innerHTML = strings[Math.floor(Math.random() * strings.length)];
});
<button id="randomText">click here</button>
<div id="output"></div>
How do I increment the highest hexidecimal number from an array of hexidecimal numbers? My knowledge of hexidecimal is somewhat spotty so any help would be appreciated. And to be perfectly honest I don't know if the numbers are hexadecimal or not because there is a "u" in front of them but they look that way if you remove the "u". The values are from an InDesign snippet document.
Example:
var anArray = ["uf9","ufc","u111","u112","u136","u137"]; // actual values
var getUniqueID = getNextHigherNumber(anArray);
function getNextHigherNumber(anArray) {
// sort array
// create variable and add one
// return variable
return variable;
}
XML from the server (look at Self and Source):
<Hyperlink Self="ufc" Name="is a multiline hyperlink that terminates here" Source="uf9" Visible="false" Highlight="None" Width="Thin" BorderStyle="Solid" Hidden="false" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//test.com#1stMultilineLink/</Destination>
</Properties>
</Hyperlink>
<Hyperlink Self="u112" Name="hyperlink inline" Source="u111" Visible="false" Highlight="None" Width="Thin" BorderStyle="Solid" Hidden="false" DestinationUniqueKey="2">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//test.com</Destination>
</Properties>
</Hyperlink>
<Hyperlink Self="u137" Name="another multline hyperlink" Source="u136" Visible="false" Highlight="Outline" Width="Thick" BorderStyle="Solid" Hidden="false" DestinationUniqueKey="3">
<Properties>
<BorderColor type="enumeration">Purple</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//google.com#multilinehyperlink</Destination>
</Properties>
</Hyperlink>
More background:
I have an existing XML document that looks like it's using hexidecimal number system for it's IDs and I need to be able to create a unique ID for new nodes. The ID values look similar to HTML web colors like, "0xFF0000" (which is red) but the difference is that it is using 2 or 3 characters instead of 6, for example, "ufc" or "u112".
I receive an XML file from the server and it has nodes and each node has an ID with a unique value (see XML example above). If I have to create a new "item" I need to create a unique ID for it that isn't already used.
First of all, hexadecimal is just a representation of a number.
The number itself remains the same.
Adding 2, means, take the value of this number, and add the value of 2.
Hexadecimal is just another way to write the number down.
Your effort of trying to figure out what these values are is highly appreciated, but why not check the documentation to know for sure?
You have an XML which you received with/from InDesign.
Just searching for that throws "IDML" at me, which seems to be the name Adobe gave to the format you are trying to parse.
Adobe provides a document describing this format:
https://wwwimages2.adobe.com/content/dam/Adobe/en/devnet/indesign/cs55-docs/IDML/idml-specification.pdf
Section 10.1.1 is about the Self attribute:
The Self attribute contains a unique identifier for the elements that
contain it. This identifier is used elsewhere in the IDML package to
refer to the element, as discussed in the “Object Reference
Format” section of this specification. Schema Example 2.
Self attribute Self { xsd:string }
As you can see, the value is a string, and not a number.
On page 31, you can find a description of how Adobe creates the values for Self including this statement:
The only requirement of the value of the Self attribute is that it is
unique within the IDML package. If you are writing the IDML yourself,
you do not need to observe the above pattern— you can change the value
of the Self attribute to anything you want as long as it is unique
(within the IDML package) and as long as all references to the element
are also changed to match.
I think that you complicate things when thinking hexadecimal ;) You can just convert your hex values to decimal ones and then continue what you are doing, so you can do like this :
var anArray = ['u112', 'u136', 'uf9', 'u137', 'u111', 'ufc'];
var getUniqueID = getNextHigherNumber(anArray);
trace('u', getUniqueID); // gives : u138
function getNextHigherNumber(anArray:Array):String {
var max:int = 0;
for(var i:int = 0; i<anArray.length; i++){
// convert the hex value to an integer
var num:int = int('0x' + String(anArray[i]).substr(1));
// get the max value
if(num > max) max = num;
}
// return the hex value of (max value + 1)
return (max + 1).toString(16);
}
Hope that can help.
You tagged both JavaScript and ActionScript (I don't know ActionScript), but the code in your question looks like JavaScript to me, and the other answer in here looks like it is in ActionScript; so, assuming you still want to do this (looks like user null is onto something), I will post the JavaScript equivalent:
var anArray = ["uf9","ufc","u111","u112","u136","u137"];
function getNextHigherNumber(theArray) {
var maxNum = 0;
theArray.forEach(function(num) {
num = parseInt(num.substr(1), 16);
if(num > maxNum) maxNum = num;
});
return 'u' + (maxNum + 1).toString(16);
}
// Run the function to see if it works
console.log(getNextHigherNumber(anArray));
What it does inside the forEach function/loop:
Remove the "u" from each array element.
Convert the string without the "u" to its int decimal equivalent.
Store the number in maxNum if the current number is bigger than the previous stored maxNum.
And then it returns the biggest number plus one, converted back again to hex via .toString(16) (and prepending an 'u' to it).
I've searched a lot but can't find an answer...
I have a list of quotes and every time I click the button I want it to go to a new quote.
Can someone please explain what's wrong here and how I should fix it?
<script language="Javascript">
function buttonClickHandler() {
var textField = document.getElementById("textField");
var quotes = new Array();
var nextQuote = 0;
quotes[0] = "Don't be so humble - you are not that great.";
quotes[1] = "Moral indignation is jealousy with a halo.";
quotes[2] = "Glory is fleeting, but obscurity is forever.";
quotes[3] = "The fundamental cause of trouble in the world is that the stupid are cocksure while the intelligent are full of doubt.";
quotes[4] = "Victory goes to the player who makes the next-to-last mistake.";
quotes[5] = "His ignorance is encyclopedic";
quotes[6] = "If a man does his best, what else is there?";
quotes[7] = "Political correctness is tyranny with manners.";
quotes[8] = "You can avoid reality, but you cannot avoid the consequences of avoiding reality.";
quotes[9] = "When one person suffers from a delusion it is called insanity; when many people suffer from a delusion it is called religion.";
nextQuote++;
textField.value = quotes[nextQuote];
}
</script>
I found this code on the internet and when I use this code, it changes the text on every click.
var currentValue = parseInt(textField.value);
// Add one
currentValue++;
// Put it back with the new +1'd value
textField.value = currentValue;
var quotes = new Array();
The code I used for my array is nearly the same but it doesn't change the text per click. Is there something special I need to do for arrays? Help!!
It wont change it because you declare the array and the index inside your handler, so every time you click you get the quote at index 1. Define the index outside the handler (as well as the array) and increment inside the handler:
var quotes = new Array();
var nextQuote = 0;
quotes[0] = "Don't be so humble - you are not that great.";
quotes[1] = "Moral indignation is jealousy with a halo.";
quotes[2] = "Glory is fleeting, but obscurity is forever.";
quotes[3] = "The fundamental cause of trouble in the world is that the stupid are cocksure while the intelligent are full of doubt.";
quotes[4] = "Victory goes to the player who makes the next-to-last mistake.";
quotes[5] = "His ignorance is encyclopedic";
quotes[6] = "If a man does his best, what else is there?";
quotes[7] = "Political correctness is tyranny with manners.";
quotes[8] = "You can avoid reality, but you cannot avoid the consequences of avoiding reality.";
quotes[9] = "When one person suffers from a delusion it is called insanity; when many people suffer from a delusion it is called religion.";
function buttonClickHandler() {
var textField = document.getElementById("textField");
textField.value = [++nextQuote];
}
Because every time the function is called nextQuote is re-set to 0
You're assinging nextQuote to 0 every single time you call the handler.
var nextQuote = 0;
Try doing this instead:
var quotes = new Array();
quotes[0] = "Don't be so humble - you are not that great.";
quotes[1] = "Moral indignation is jealousy with a halo.";
quotes[2] = "Glory is fleeting, but obscurity is forever.";
quotes[3] = "The fundamental cause of trouble in the world is that the stupid are cocksure while the intelligent are full of doubt.";
quotes[4] = "Victory goes to the player who makes the next-to-last mistake.";
quotes[5] = "His ignorance is encyclopedic";
quotes[6] = "If a man does his best, what else is there?";
quotes[7] = "Political correctness is tyranny with manners.";
quotes[8] = "You can avoid reality, but you cannot avoid the consequences of avoiding reality.";
quotes[9] = "When one person suffers from a delusion it is called insanity; when many people suffer from a delusion it is called religion.";
var nextQuote = 0;
var textField = document.getElementById("textField");
function buttonClickHandler() {
if(nextQuote < 9) {
nextQuote++;
} else {
nextQuote = 0;
}
textField.value = quotes[nextQuote];
}
try something like
var nextQuote = Math.floor((Math.random()*9)+1);
instead of your:
var nextQuote =0;
later change the 9 to your array size, and add it after you've declared all the values into your array.
The difference is the code that works gets the value to increment from outside of buttonClickHandler
var currentValue = parseInt(textField.value);
where as you reinitialise it every time buttonClickHandler is called
var nextQuote = 0;
I think it will work if you replace this declaration with
if (window.nextQuote == null) {
window.nextQuote = 0
} else {
window.nextQuote++
}
As previously posted answers have already stated, the problem is caused because nextQuote is defined inside of buttonClickHandler and thus destroyed every time the function finishes executing and is recreated and initialized to 0 every time the function begins.
You seem to be learning JavaScript using some very old tutorials, the following code will show how this could be refactored to a more modern style.
<script language="Javascript">The language attribute of the <script> tag was deprecated a very long time ago. Don't use it. It was replaced by the type attribute, however don't use the type attribute either. Just a plain <script> tag works in all browsers, they all default to JavaScript since it was the only language to ever gain any traction as a client-side scripting language.
<script>
(function (document) { // Use a self-invoking function to keep our variables
// out of the global scope
"use strict"; // Force the browser into strict mode
var nextQuote = 0, // instead of using separate var statements you can use
// a comma to include all of your variable declarations
// in one statement.
/* Since we will be using the textField DOM element a lot, lets cache a
copy in a variable outside of the handler instead of enduring the
overhead of getElementById every time the handler runs,
querying the DOM is slow.
*/
textField = document.getElementById("textField"),
/* Instead of using new Array(), use an array literal. Literals are
shorter and behave in a more predictable way than the Array
constructor. Another benefit to using a literal is that you can
create the array and initialize it's values in one step avoiding
the tedious quotes[0] = "..."; quotes[1] = "..."; pattern of the
original code. Also, if you want to reorder the items in the list
you don't have to renumber them too.
*/
quotes = [
"Don't be so humble - you are not that great.",
"Moral indignation is jealousy with a halo.",
"Glory is fleeting, but obscurity is forever.",
"The fundamental cause of trouble in the world is that the stupid are cocksure while the intelligent are full of doubt.",
"Victory goes to the player who makes the next-to-last mistake.",
"His ignorance is encyclopedic",
"If a man does his best, what else is there?",
"Political correctness is tyranny with manners.",
"You can avoid reality, but you cannot avoid the consequences of avoiding reality.",
// The last item in the list should not have a comma after it, some
// browsers will ignore it but others will throw an error.
"When one person suffers from a delusion it is called insanity; when many people suffer from a delusion it is called religion."
];
function buttonClickHandler() {
nextQuote++;
// roll back to 0 if we reach the end
if (nextQuote >= quotes.length) {
nextQuote = 0;
}
textField.value = quotes[nextQuote];
}
document.getElementById('button').addEventListener("click", buttonClickHandler, false);
}(document)); /* This is the end of the self-invoking function. The document
object is being passed in as an argument. It will be imported
into the self-invoking function as a local variable also named
document. There are a couple of reasons to do this. Having it
aliased as a local variable will make any references to it
quicker since the browser will not have to look any further
up the scope-chain. Also, if this code is minified, the local
variable will be renamed to a shorter (often 1 character long)
name, saving download time, where references to the built-in
global document object would not.
*/
</script>
The self-invoking function that wraps the code is a very common pattern in modern JavaScript, it would be good to become familiar with it.
Using strict mode will help you avoid a number of easy to create bugs.
If you are deploying JavaScript code into the wild you should be minifying it. Having a build process can make this easy by automating it for you. I would recommend Grunt, it has lots of pre-built tasks to make minifying and other common build tasks easy. It can be a bit tricky to set up at first but there are a lot of great articles out there that can make it much easier to understand.
I'm trying to create my own JS Password Strength Meter.
It was working before but i didn't like how it worked so I tried using
{score +=10;}
Instead of just:
score++
This is my code:
http://jsfiddle.net/RSq4L/
Best Regards,
Shawn,
Hope someone can help
Multiple issues:
Your passwordStrength() function was not defined in the global scope in the jsFiddle so it wasn't getting called. This is probably an artifact of how you set up the jsFiddle, perhaps not an issue in your real code.
The method of getting the appropriate ratingMsg will not work because you don't have array values for every possible score so many scores will generate an "undefined" ratingMsg.
Your CSS classes are also sparse so there are many score values that they will not match for either and no appropriate CSS class/style will be in effect. If you want a specific class for each rating value, then perhaps you should put the classname in the ratings array so it can be fetched from there along with the ratingsMsg.
For the first issue, in your jsFiddle, you also have to make sure the password processing function is defined in the global scope. The way your jsFiddle is set up, it is not (it's in the onload handler). You can fix this in the jsFiddle by just setting the first drop-down in the upper left to "no wrap (head)".
For the second issue, you are using:
ratingMsg[score]
but, your array is a sparse array not guaranteed to have an entry for most possible scores. You simply can't do it that way because many elements you access will have undefined values which won't give you a meaningful message. For example, if score was 15, you would be accessing ratingMsg[15], but there is no value in that space in the array so you won't get a meaningful rating message.
The solution is to find a different way to select the right message. The simplest way would just be an if/else if/else if statement that would check which range the score is in and set the appropriate msg. There are more elegant table driven ways, but all will involve searching through a data structure to find which two values the current score is between and using that msg.
If you look at this jsFiddle http://jsfiddle.net/jfriend00/dA7XC/, you'll see that your code is getting called, but it only hits values in the array sometimes.
And, here's a rewritten algorithm that finds the appropriate msg no matter what the score show in this fiddle: http://jsfiddle.net/jfriend00/jYcBT/.
It uses a data structure like this:
var ratingMsg = [
0, "Unclassified",
10, "Weak",
20, "Fair",
50, "Better",
60, "Medium",
70, "Good",
90, "Strong"
];
and a for loop like this to get the appropraite ratingMsg:
for (var i = ratingMsg.length - 2 ; i >= 0; i-=2) {
if (score >= ratingMsg[i]) {
msg = ratingMsg[i+1];
break;
}
}
Here you go: http://jsfiddle.net/RSq4L/11/
The first problem is that in your fiddle you have the onLoad option set, so your passwordStrength function is not actually being declared in the global scope. It is being declared inside of the onLoad block that jsFiddle wraps your code with. This causes the page to error out when the keypress handler tries to invoke the function.
You can fix this problem in several different ways:
By explicitly declaring the function as global as per my example above.
By choosing one of jsFiddle's "no wrap" options instead of onLoad.
By dynamically binding your event-handler instead of setting it through the element's onkeydown attribute in the markup.
The second problem is how you are keying your score messages. You have:
var ratingMsg = new Array(0);
ratingMsg[0] = "Unclassified";
ratingMsg[10] = "Weak";
ratingMsg[30] = "Fair";
ratingMsg[50] = "Better";
ratingMsg[60] = "Medium";
ratingMsg[70] = "Good";
ratingMsg[90] = "Strong";
...and you lookup the message by doing ratingMsg[score]. This will only work if the score exactly matches one of your indices. And based upon your math this will not always be the case.
I would suggest doing something like:
ratingMsg = {};
ratingMsg[0] = "Unclassified";
ratingMsg[10] = "Weak";
ratingMsg[30] = "Fair";
ratingMsg[50] = "Better";
ratingMsg[60] = "Medium";
ratingMsg[70] = "Good";
ratingMsg[90] = "Strong";
function closestRating(score) {
var bestKey = 0;
var bestMatch = 100;
for (var key in ratingMsg) {
if (key <= score && score - key < bestMatch) {
bestMatch = score - key;
bestKey = key;
}
}
return ratingMsg[bestKey];
}
On an unrelated note, are you sure you want to be using onkeydown? I think onkeyup would work better.
Your fiddler script had several errors. Here's the corrected one: new script.
You were missing a semicolon here: document.getElementById("passwordDescription").innerHTML = "" + ratingMsg[score] + ""
You forgot to escape '^' on your regular expression
I just wrote this for it:
Jquery Plugin for password strength forcing