Rewriting content of an HTML element using JavaScript - javascript

I'm new to JS, can't understand how to make this code work. I'm trying to overwrite the whole html source text.
var oldSource = document.documentElement.innerHTML;
alert(oldSource); //this works, it gets the whole html
document.write(Change(oldSource)); //doesn't work, writes undefined
function Change(source){
for (i = 0; i <= source.length; i++){
source[i] = "S"; // doesn't change the source[i]
}
}

You are changing the value of the variable oldSource, not the value of the documentElement.innerHTML.
.innerHTML just returns a string that contains the serialised content of that element. It doesn't return a reference to the content in the DOM.
Furthermore, document.write(Change(oldSource)) is saying write the return value of Change(oldSource) to the document... but your Change() function doesn't return anything, hence it is undefined.
Lastly, strings are immutable, meaning you can't change their contents after they have been created. Instead, you need to build up a new string in your function, like so:
function Change(source){
new_source = ""
for (i=0; i < source.length; i++){
new_source = new_source + "S"; //doesn't change the source[i]
}
return new_source
}
You can check all of this out in this jfiddle.

You need to return( source ); after your for loop

JavaScript strings are immutable. You can't use
source[i]="S";
to modify a string. You need to build a new string and return it.
It should be < source.length as well.

In JavaScript, this line: var oldSource = document.documentElement.innerHTML; copies the innerHTML into the oldSource variable. It does not save a reference to the innerHTML.
You are modifying the value stored in oldSource, but never applying it to the document.
In your Change function, you do not return any value - that is why you are getting an undefined. Add a 'return source;in yourChange` function to return a value.
The other problem is that you can't change the string in JavaScript. You should make a new variable for this. You can't edit source[i] - you can only retrieve the value that is there.

You need to return the new source string like below;
var oldSource = document.documentElement.innerHTML;
alert(oldSource); //this works, it gets the whole html
document.write(Change(oldSource)); //doesn't work, writes undefined
function Change(source){
for (i=0; i<=source.length; i++){
source[i]="S"
}
return source;
}

your function must return something, not just change
you cannot change strings this way, use .replace() method instead
if you specify what you really need to do, our help could be more effective
EDIT As far as I didn't find correct working code here, I want to suggest my one
function Change(source){
var str = source.split("");
for (var i=0; i<source.length; i++){
str[i] = "S";
}
return str.join("");
}
Maybe it's not the fastest way (though, why not) but it lets you to operate with indexes as you tried in your question.
working fiddle for Lego Stormtroopr
EDIT2 and this example shows how to do it in one line inside the loop (without creating extra variables)
for (var i=0; i<source.length; i++){
source = source.replace(new RegExp(source[i]), "S");
}

Related

how to remove HTML tags from a string in JavaScript without using regexp?

I am new to programming and I was solving this exercise.
I have tried 3 loops with string.slice() but for some reason it prints an empty string.
Would you please explain what happens inside my code and why it prints the wrong output and how I can correct, rather than giving me your version of the correct answer, so that I can learn from my mistakes.
the test input is
<p><strong><em>PHP Exercises</em></strong></p>
and output should be PHP Exercises
p.s this is not a PHP exercise, I'm not confused
here is my code :
function remove(answer){
var sen = answer.split("");
var arr = [];
for (var i = 0; i<answer.length; i++){
if (answer[i] == "<"){
for (var j = i; j<answer.length; j++){
if (answer[j] == ">"){
for (var k = j; k<answer.length; k++){
if (answer[k] == "<"){
return answer.slice(j+1, k);
}
}
}
}
}
}
}
Try this:
function stripTags(data)
{
var tmpElement = document.createElement("div");
tmpElement.innerHTML = data;
return tmpElement.textContent || tmpElement.innerText || "";
}
var something = '<p><strong><em>PHP Exercises</em></strong></p>';
alert(stripTags(something));
or You can use string.js (string.js link):
var S = window.S;
var something = '<p><strong><em>PHP Exercises</em></strong></p>';
something = S(something).stripTags().s;
alert(something);
<script src="https://raw.githubusercontent.com/jprichardson/string.js/master/dist/string.min.js"></script>
if You're trying nodejs so:
var S = require('string');
var something = '<p><strong><em>PHP Exercises</em></strong></p>';
something = S(something).stripTags().s;
console.log(something);
As to why the provided code isn't working, the code returns when j = 2 and k = 3. I discovered this by writing console.log(j, k); immediately before the return. This insight made it clear that the code is identifying the first set of open tags, when actually you seem to want to identify the open and closed "em" tags. The answers provided by others are more robust, but a quick fix to your code is:
change
if (answer[i] == "<"){
to
if (answer.slice(i, i+3) == "<em"){
Hope this helps!
Your code does not account for ... nothing. It simply stops at the first encounter of what's between ">" and "<", which is, in the first case, is nothing! You should check if a character is present, and move on if not.
Honestly, this is one of those useless exercises that text books use to try to get you to think outside the box. But you will never want to loop through a string to find text between tags. There are so many methods built in to JavaScript, it's literally reinventing the wheel to do this... that is if a wheel were really a for-loop.
If you really want to avoid Regex and other built in functions so that you can learn to problem solve the long way, well try slicing by brackets first!

For loop and getElementById

Hopefully an easy one, but I am having trouble printing out a number series from a for loop, back to the HTML. See below for my code, when I hit the button, it only returns 10, but not the rest of the numbers - where am I going wrong?
<!DOCTYPE html>
<html>
<body>
<button onclick="myFunction()">Try It</button>
<p id="number"></p>
<script>
function myFunction() {
for (i=0; i<11; i++) {
document.getElementById("number").innerHTML=i+"</br>";
}
}
</script>
</body>
</html>
You're replacing the element's contents on each loop. If you want to add to the contents, use += rather than = (as a minimal change):
document.getElementById("number").innerHTML+=i+"</br>";
// here -----------------------------------^
That said, I wouldn't do that, because it's making the browser do a lot of unnecessary work under the covers. Every time you read the value of innerHTML, the browser has to spin through the element and build up a string representing its contents; and every time you write to innerHTML, it has to parse the HTML, wipe out previous elements, and build new ones.
Instead, consider building up a string and doing one assignment:
function myFunction() {
var i, s = "";
for (i=0; i<11; i++) {
s += i + "<br>";
}
document.getElementById("number").innerHTML = s;
}
Side note 1: Your code is falling prey to The Horror of Implicit Globals because you're not declaring i. I've fixed that above by declaring it.
Side note 2: </br> is an invalid tag. In HTML, it's <br> (or <br/>; the ending / is entirely optional). In XHTML, it's <br/>.
document.getElementById("number").innerHTML=i+"</br>";
will replace the HTML of number, change it to
document.getElementById("number").innerHTML+=i+"</br>";// see the `+`
Setting .innerHTML with = completely changes its content.
Use += to append content.
document.getElementById("number").innerHTML += i + "</br>";
Since most of the other answers have shown you the error, here's an edit of your code that shows how you can get the result you want but without hitting the DOM with each iteration of the loop:
function myFunction() {
// create an array
var arr = [];
for (var i = 0; i < 11; i++) {
// push the data to the array
arr.push(i + '<br/>');
}
// grab the element and then add the joined array to the html
document.getElementById("number").innerHTML = arr.join('');
}
DEMO

Get array values and put them into different divs with a for loop?

I'm trying hard to learn javascrip+jquery on my own, and also trying to learn it right. Thus trying to enforce the DRY rule.
I find myself stuck with a problem where I have an array,
var animals = [4];
a function,
var legs = function(amount){
this.amount = amount;
this.body = Math.floor(Math.random()*amount)+1;
}
and an evil for loop. I also have 5 div's called printAnimal1, printAnimal2 and so on.. In which I wish to print out each value in the array into.
for(i = 0; i < animals.length; i++){
animals[i] = new legs(6);
$(".printAnimal"+i).append("animals[i]");
}
I feel as if I'm close to the right thing, but I cant seem to figure it out. I also tried something like this:
for(i = 0; i < animals.length; i++){
animals[i] = new legs(6);
$this = $(".printAnimal");
$(this+i).append("animals[i]");
}
But one of the problems seem to be the "+i" and I cant make heads or tails out of it.
I also know that I can simply do:
$(".printAnimal1").append("animals[i]");
$(".printAnimal2").append("animals[i]");
$(".printAnimal3").append("animals[i]");
...
But that would break the DRY rule. Is it all wrong trying to do this with a for loop, or can it be done? Or is there simply a better way to do it! Could anyone clarify?
Your first attempt should be fine, as long as you take "animals[i]" out of quotes in your append() call ($(".printAnimal"+i).append(animals[i]))
Also, I assume you declared var i; outside your for loop? If not, you'll want to declare it in your for loop (for(var i=0....)
EDIT: problems with your fiddle
you never call startGame()
you didn't include jQuery
you can't (as far as I know) append anything that isn't html-- in your case, you're trying to append a js object. What do you want the end result to look like?
http://jsfiddle.net/SjHgh/1/ is a working fiddle showing that append() works as you think it should.
edit: forgot to update the fiddle. Correct link now.
EDIT: reread your response to the other answer about what you want. http://jsfiddle.net/SjHgh/3/ is a working fiddle with what you want. More notes:
You didn't declare new when you called DICE
you have to reference the field you want, (hence dices[i].roll), not just the object
Just a few comments:
This is declaring an array with only one item and that item is the number 4
var animals = [4];
In case you still need that array, you should be doing something like:
var animals = []; // A shiny new and empty array
and then add items to it inside a for loop like this:
animals.push(new legs(6)); //This will add a new legs object to the end of the array
Also, what is the content that you are expecting to appear after adding it to the div?
If you want the number of legs, you should append that to the element (and not the legs object directly).
for(i = 0; i < animals.length; i++){
animals.push(new legs(6));
$(".printAnimal"+i).append(animals[i].body);
}
Adding another answer as per your comment
var i, dicesThrown = [];
function throwDice(){
return Math.ceil(Math.random() * 6);
}
//Throw 5 dices
for (i=0 ; i<5 ; i++){
dicesThrown.push( throwDice() );
}
//Show the results
for (i=0 ; i<5 ; i++){
$("body").append("<div>Dice " + (i+1) + ": " + dicesThrown[i] +"</div>");
}

How do I correctly use an iteration value in JavaScript?

I am creating a 'simple' javaScript function which basically displays new information on the page when a user clicks next or previous.
The information is taken from an array and I want to use either i++ or i-- to call an element of the array.
Heres my JavaScript:
var titles = ["Dundalk", "Navan", "Drogheda", "Dublin"];
var i = 0;
function next()
{
i++;
if (i == titles.length)
{
i = 0;
}
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
function prev()
{
if (i == 0)
{
i = titles.length;
}
i--;
var object = document.getElementById('tname');
object.innerHTML = titles[i];
}
The problem is, when I run this code in my HTML page, I get an 'UNDEFINED' result. The JavaScript is not recognizing that i has been initialized as 0 in the beginning.
If i change titles[i] to titles[2], for example, the correct text is displayed in HTML.
What am I forgetting or how can I overcome this?
Thanks
The fact that you're seeing undefined indicates that you're accessing an array index which hasn't been set. Your code looks fine at a glance, so I would guess that there's some more code you're not showing which also uses i as a loop variable and leaves it set to a value > titles.length after the code above has run.

How to turn this JavaScript string "myArray[0].myPrice" in to a reference to myPrice?

If I have a string of "myArray[0].myPrice", how do I turn this in to a reference to myPrice?
This is the code context:
binding.value = convert(binding.data[binding.field],
binding.converter, binding.data, elem);
binding.field is what contains "myArray[0].myPrice".
binding.data has a reference to the hierarchical object which has an Array property of myArray, and the first element is an object with a property of myPrice.
EDIT: based on the answers, this worked:
binding.value = convert(eval('(binding.data.' + binding.field + ')'),
binding.converter, binding.data, elem);
Is it good to use eval like this? I thought eval was going away in newer JavaScript?
You can use eval, but here is a better solution:
// The following code results in the same as that scary eval(...)
var data = binding.data,
chain = binding.field.split(/[\.\[\]]+/);
for (var i = 0; data[chain[i]]; i++) {
data = data[chain[i]];
}
// Embrace JavaScript Awesomeness!
A breakdown of what I'm doing here:
In JS any property can be called as object[propertyName].
That includes arrays, i.e. a[3] is the same as a['3'].
Therefore, we split the string using one of the characters: ., [, ]. The + is there because without it if you have a[3].b[3] the ]. will give you an empty
string.
We might get an empty string in the end, but that's not a problem since "" is like false in JS.
You could go further and filter out all the invalid variable names, which in javascript is a name that does not conform to [a-zA-Z_$][0-9a-zA-Z_$]*. But I am not quite sure as to why one would do that...
Well, it ain't exactly pretty, but it doesn't use eval:
var str = 'myArray[0].myPrice';
var parts = str.split(/[\[\].]+/);
doSomething(window[parts[0]][parts[1]][parts[2]]);
where window[parts[0]][parts[1]][parts[2]] is the actual reference. Not sure why you'd have a string version and one loaded into memory, though.
Depending on the current context, this might work:
eval("myArray[0].myPrice")
try
var a = eval("myArray[0].myPrice".split('.')[1]);
However this will probably not work in the context you run it in since myPrice will be referring to window.myPrice which I doubt would be defined as anything.
Your best bet here is to define myArray in a scope that can be accessed from anywhere (such as window.AppNS.Data.myArray) and then use the eval() function to access this.
var a = eval("window.AppNS.Data." + "myArray[0].myPrice")
alert(a) // the contents of myPrice are revealed
Here is something similar to the logic we use in the template engine pure.js
var obj = {
myArr:[
{price:15}
],
anObj:{
prop:'ABC'
}
};
function getRef(o, path){
var props = path.split(/\./),
prop,
isArr = /([^\[]+)(\[(\d+)\])*/,
i = 0, ii = props.length;
while(i < ii){
prop = props[i].match(isArr);
o = o[prop[1]];
if(prop[2]){
o = o[+prop[3]];
}
i++;
}
return o;
}
console.log(getRef(obj, 'myArr[0].price')); // --> 15
console.log(getRef(obj, 'anObj.prop')); // --> ABC

Categories