getElementsByName which name? - javascript

I'm creating a bunch of divs in javascript, and at a certain time I wish to delete all the divs.
My code is like this:
function CreateDiv(width, height, row, col){
var thisTile = document.createElement("div");
thisTile.style.position = "absolute";
thisTile.style.width = width + "px";
thisTile.style.height = height + "px";
thisTile.style.top = row*TileH + topMargin + "px";
thisTile.style.left = col*TileW + leftMargin +"px";
thisTile.style.backgroundImage = "url(" + imagePath + ")";
thisTile.style.backgroundSize = imageWidth + "px " + imageHeight +"px";
thisTile.style.backgroundRepeat = "noRepeat";
thisTile.style.backgroundPosition = "-" + col*TileW + "px -" + row*TileH + "px";
thisTile.onclick = TileClicked;
thisTile.name = "tiles";
document.body.appendChild(thisTile);
return thisTile;
}
...
var tmp = document.getElementsByName("tiles");
alert("tmp length: " + tmp.length);
for (var i = 0; i < tmp.length; i++)
document.body.removeChild(tmp[i]);
but every time tmp is an empty array, so I can't actually remove the divs I want to,
I tried to change
tile.name = "tiles"
to
tile.nodeName = "tiles"
or
tile.className = "tiles"
but none of them worked, I just wonder which name attribute or property of an element exactly is the one in getElementsByName?

The getElementsByName method returns a list of elements with an attribute called name, with the given value, but only for those elements in which such an attribute is allowed by HTML specifications. And div is not among them.
In reality, it’s a bit more complicated. Modern browsers (including IE 10) actually implement it so that all elements with the name attribute in HTML markup are considered, even if the markup is invalid by HTML specs, like <div name=tiles>foo</div>. But not elements that just have the name property assigned to them in JavaScript. The difference is that the markup attribute also causes the information to be added into the attributes object.
So if you really, really wanted to use name here (you shouldn’t), you could replace
tile.name = "tiles"
by
thisTile.setAttribute("name", "tiles");
And it still wouldn’t work on IE 9 and older.
From the description of the purpose in the question, it seems that you should just collect an array of elements that you have added, if you later need to remove them. That is, in addition to adding an element in the document, you would append it to an array that you create, and then, when you need to delete them all, you just traverse the array.

Actually DIV tag does not have name attribute.
check the following reference:
http://www.w3schools.com/tags/tag_div.asp
give your divs a specific class and access then using :
elements = document.getElementsByClassName(className)

Here in your code you have used the following codes including tiles-
thisTile.name = "tiles";
and
var tmp = document.getElementsByName("tiles");
But you have to use tiles[] in place of tiles to make tiles an array of elements.
That is the only mistake in your code. your code will run fine if you change these two statements.

Related

Trying to setAttribute to a button Element in a Class dynamically but returns "is not defined"

I have this problem. I'm creating in Javascript a game similar to minefield - i decided to use a Class to generate the game levels. The Class is also in charge to generate the DOM code, including the buttons and the layout, according with the level size defined when creating the level.
Now the issue i have is that when i generate the code for each button:
box.setAttribute('onclick', this.levelName + '.checkResult(this.id)');
In the generate HTML it seems to be correct:
<button id="00" class="box" onclick="LevelOne.checkResult(this.id)">test</button>
But when i press the relative button i get this message:
Uncaught ReferenceError: LevelOne is not defined
at HTMLButtonElement.onclick (findTheSpot.html:16)
And if i do this, inserting the variable name directly in the second parameter:
box.setAttribute('onclick', 'levelOne.checkResult(this.id)');
It works perfectly.
I will paste the entire code below just to help you to visualize the entire flow - i'm totally new to javascript and i'm trying to learn as much as i can, creating different coding exercises by my own, apologies in advance for any coding horrors or rookie mistakes :D
/// creating a class to generate an array map of 0s and a single random 1
class Level {
constructor(wL, hL) {
this.widhtLevel = wL;
this.lenghtLevel = hL;
this.levelName;
this.level = [];
}
populateLevel() {
var idNumber = 0;
//Creating the main div container
var div = document.createElement('div');
div.style.width = this.widhtLevel + (this.widhtLevel * 50) + 'px';
div.style.height = this.lenghtLevel + (this.lenghtLevel * 50) + 'px';
div.setAttribute('id', 'mainContainer');
div.setAttribute('class', 'boxContainer');
document.body.appendChild(div);
for(var i = 0; i < this.lenghtLevel; i++) {
var arrayPopulation = []
for(var j = 0; j < this.widhtLevel; j++) {
arrayPopulation.push(0)
//Creating the boxes
var box = document.createElement('button');
box.textContent = "test";
box.setAttribute('id', idNumber + '' + (arrayPopulation.length - 1));
box.setAttribute('class', 'box');
box.setAttribute('onclick', this.levelName + '.checkResult(this.id)');
div.appendChild(box);
}
this.level.push(arrayPopulation);
idNumber++;
}
}
randomizeKey() {
var randomX = Math.floor(Math.random() * (this.widhtLevel - 0));
var randomY = Math.floor(Math.random() * (this.lenghtLevel - 0));
this.level[randomY][randomX] = 1;
//console.log(this.level[randomY][randomX]);
}
createLevel(name) {
this.levelName = name;
this.populateLevel()
this.randomizeKey()
for (var i = 0; i < this.level.length; i++) {
console.log(this.level[i])
}
}
var levelOne = new Level(5,5);
levelOne.createLevel("LevelOne");
The problem comes down to a common programming nightmare - capitalization. It can be incredibly frustrating trying to debug a problem caused by inconsistent capitalization because your brain often skips that detail when comparing variable names. In your case your generated code capitalizes "LevelOne" but your hardcoded value is "levelOne". You may have to read the previous sentence twice to notice the difference even though it was explicitly called out.
So the short-term answer to your problem is that you need to make sure that the variable name and the "levelName" property have the same capitalization. Without taking the time to review the rest of your code that should at least fix the immediate issue.
While you are reviewing this, it would not hurt to think about your variable capitalization conventions. You do not have to rename all of your variables immediately but you may find that defining personal standards will make future code far more maintainable. If you work with other developers then this is an exercise that you should undertake together or you may find yourselves unintentionally working against each other. If you already have naming conventions then feel free to ignore this advice - maybe it will help someone else viewing this answer later.

How do I remove variable randomly using jquery?

I'm trying to find a way to remove variable from certain div on the web using jquery. This does not involve using array. If I can do so with using fadeIn() or search() and remove(), that's even better.
var something = '#img' + count;
on the web, images will be added to div as time passes (using setTimeout). Those images have been assigned to variable (something) and I need to find a way to remove it from certain div on the web. It can be hide, remove, whatever, it has to disappear from user's view randomly (both time and which image will disappear).
Thanks for help and your time in advance.
my function code:
var count = 0;
function foo() {
var xPos = xPosition();
var yPos = yPosition();
var someTime;
$("div").append('<img id="Img" ' + count + ' src = "img.png" style="top:' + yPos + 'px; left: ' + xPos + 'px; " />');
var something = "#Img" + count;
someTime = setTimeout('foo()', randInterval());
$(something).hide();
count++;
if (timeRemaining == 0) {
clearTimeout(someTime);
return;
}
Give all the images a class. You can then use $(".class").length() to get the number of images, pick a random number in this range, and delete that element with .eq().
function addImage() {
var xPos = xPosition();
var yPos = yPosition();
$("div").append($("<img>", {
src: "img.png",
"class": "imageclass",
style: {
top: yPos+"px",
left: xPos+"px"
}
}));
setTimeout(addImage, randInterval());
}
setTimeout(addImage, randInterval());
function removeImage() {
var images = $(".imageclass");
if (images.length) {
var rand = Math.floor(Math.random() * images.length);
images.eq(rand).remove();
}
setTimeout(removeImage, randInterval());
}
setTimeout(removeImage, randInterval());
In my code I'm using separate timers for adding and removing images. If you prefer, you could remove the setTimeout from removeImage(), and just call it from addImage so it will always remove an image whenever it's adding a new one.
Please, never ever append a number to an id and piece together numbered names of things. It is unmaintainable and bad. Use class.
Assign a purpose or functionality to an element or elements by adding a class name to them. If you want to add information to an element, that is great, use data- prefix on the attribute name and it is all legal. data-itemid is an example.
You can query for matching elements with var those = $('.that-class-name'), stored for reuse. From there you can access individual elements using those.eq(0) through those.eq(x.length - 1). For example, if you somehow knew that the 3rd one needs to be removed, then those.eq(3).remove();. If you want to pick through them and only select ones that match a condition, use those.filter(callback).remove(), where callback returns true if the element referred to by this should be removed. If you want to filter those with another selector, .filter will accept a selector too.
Is that what you meant?

Using JavaScript to increment top/left/bottom/right values

I am trying to increment the position of an element by, say, x pixels. Here is what I've tried so far:
var top = document.getElementById("something").style.top;
top = top + "300px"
I know that this is not going to work, but I was wondering if it was possible to increment a position value like this.
Because style.top is a string with units on the end of it like "300px" you can only do math with it when you convert just the numeric part to an actual number.
Assuming you have a positioned element (so setting the top value will do something) and you already have a top style set directly on the element and not set via CSS (so getting obj.style.top will actually get you something), you can do it by parsing the number out of the style value like this:
var obj = document.getElementById("something");
var topVal = parseInt(obj.style.top, 10);
obj.style.top = (topVal + 300) + "px";
Working example: http://jsfiddle.net/jfriend00/pt46X/
That won't work fine because, for example, if top had a value of 200px, it would become "200px300px". Try this:
var elem = document.getElementById("something");
elem.style.top = parseInt(elem.style.top, 10) + 300 + "px"
Demo WEEEE!!!!
let top = 0;
let left = 0;
let text = document.getElementById("TextToTranslate");
text.setAttribute("style","top:"+top+"px; "+left+":px;");
use this in a while loop and it works fine, i'm just figuring out how to slow it down so i can see the transition

Javascript style.left is empty string

next.onclick = function() {
move('left', li_items[0]);
};
var move = function(direction, el) {
pos = el.style[direction].split('px')[0];
pos = parseInt(pos, 10) + 10;
el.style[direction] = pos + 'px';
};
I'm using the simple code above to try and move an element. Now when I breakpoint on this, the value of el.style[direction] is: " ". So then when i try to do anything with it, it breaks. Why would this be? Isn't style.left supposed to return an integer?
Why would this be?
Presumably because it hasn't been set to anything.
Isn't style.left supposed to return an integer?
No. It is supposed to return a string containing the value of the CSS left property as set directly on the element (either by setting the JS property itself or by using a style attribute). It does not get a value from the cascade and it should only be an integer if the value is 0 (since all other lengths require units).
See How to get computed style of a HTMLElement if you want to get the computed value for the property rather than what I described in the previous paragraph.
style provides the original style as calculated from the CSS, not the updated and possibly dynamic style. You probably want currentStyle instead.
next.onclick = function() {
move('left', li_items[0]);
};
var move = function(direction, el) {
var lft = document.defaultView.getComputedStyle(el)[direction];
pos = parseFloat(lft);
pos = parseInt(pos, 10) + 10;
el.style[direction] = pos + 'px';
};
Note: like Elliot said you'll have to get the currentStyle/computedStyle. Here's a way to make it cross-browser, however when applying styles via JS, this is one good case where some sort of framework (eg Prototype [Scriptaculous], jQuery) would be useful.
Just a comment.
In your code:
> pos = el.style[direction].split('px')[0];
> pos = parseInt(pos, 10) + 10;
The split in the first line is superfluous, in the second line parseInt will convert (say) 10px to the number 10 just as effectively (and more efficiently) than what you have.
pos = parseInt(el.style[direction], 10);

Can this JavaScript be optimized?

This JS will be executed on pages with a lot of fields. Can you see anyway to improve the speed of this code? If so, can you explain what you found?
var _TextInputs = null;
function GetTextInputs()
{
if (_TextInputs == null)
{
_TextInputs = jq('input[type=text]');
}
return _TextInputs;
}
var _Spans = null;
function GetSpans()
{
if (_Spans == null)
{
_Spans = jq('span');
}
return _Spans;
}
function UpdateRate(ratefield, name)
{
GetTextInputs().filter('[' + name + ']').each(function()
{
this.value = FormatCurrencyAsString(FormatCurrencyAsFloat(ratefield.value));
CalculateCharge(name.replace('Rate', ''), jq(this).attr(name));
});
}
function CalculateCharge(name, activity_id)
{
var inputs = GetTextInputs();
var bill_field = inputs.filter('[' + name + 'Bill=' + activity_id + ']');
var rate_field = inputs.filter('[' + name + 'Rate=' + activity_id + ']');
var charge_field = GetSpans().filter('[' + name + 'Charge=' + activity_id + ']');
charge_field.text(FormatCurrencyAsString(FormatCurrencyAsFloat(bill_field.val()) * FormatCurrencyAsFloat(rate_field.val())));
}
You can:
Replace each with while
Replace val() with .value (should be fine as long as those fields are plain text ones)
Access elements by class instead of by name/type
Replace attr() with plain property access; e.g.: this.attr(name) --> this.name
These are all rather unobtrusive changes which should speed things up mainly due to cutting down on function calls.
Don't query elements on every function call if those elements are static (i.e. are not modified during your app life-cycle). Instead, store them outside the loop.
I can see that you're using attribute filters everywhere, e.g.:
_TextInputs = jq('input[type=text]');
inputs.filter('[' + name + 'Bill=' + activity_id + ']');
Attribute filters are useful, but not especially 'snappy' when compared to more direct class or ID selectors. I can't see any markup so the best I can do is suggest that you use more IDs and classes, e.g.:
jq('input.textInput');
instead of:
jq('input[type=text]');
A little off-topic, but I use and recommend Javascript Rocks. This books contains a TON of awesome JS optimisation advice by the creator of Scriptaculous. Also comes with a tool called DOM Monster which helps track down performance bottlenecks - it's an awesome compliment to Firebug as it actually tracks through the DOM looking for inefficiencies based on heuristics and DOM complexity.

Categories

Resources