So my issue is, whenever I run this loop, it only grabs the changes to the element on the first flip through. Is there a way to make it make those changes every time?
<script>
for ( i=0; i<5; i++){
document.write('<div id=\"blah\" >text</div>');
var b = document.getElementById("blah");
b.style.width ="200px";
b.style.backgroundColor="yellow";
}
</script>
id has to be unique in a document. hence the issue. The DOM would return only 1 node even if there are multiple matches.
You can do something like this:
for (var i=0; i<5; i++){
var div = '<div class="blah" >text</div>';
div.style.width ="200px";
div.style.backgroundColor="yellow";
document.write(div);
}
I have two ideas to overcome this. The first is to create the element, change its style, and append it.
<script type="text/javascript">
for (var i = 0; i < 5; i++) {
var div = document.createElement("div");
div.style.width = "200px";
div.style.backgroundColor = "yellow";
document.appendChild(div);
}
</script>
The other idea is that you don't need a reference to the DOM element, because you're only changing style, so you can apply the style with CSS. For example:
<style type="text/css">
div.something {
width: 200px;
background-color: yellow;
}
</style>
<script type="text/javascript">
for (var i = 0; i < 5; i++) {
document.write("<div class='something'>text</div>");
// Or use the createElement/appendChild approach from above,
// where you'd need to set the div.className property as "something"
}
</script>
You need to add the element to the DOM to be able to access it later.
for(var i=0;i<5;i++)
{
//I'm not sure if you are just trying to make these changes each iteration
//or create a new element each time. If you are trying to create a new element
//each time. I'd def consider going a diff route i.e. use classes.
var b;
if( i==0 ){
b = document.createElement("DIV");
b.id = "blah";}
else{
b = document.getElementById("blah");}
b.style.width ="200px";
b.style.backgroundColor="yellow";
}
Related
I'm trying to apply the onclick event with JavaScript to the following elements:
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
If I click on the first element (with index [0]) then this works, but I
need this event applicable for all classes:
document.getElementsByClassName('abc')[0].onclick="function(){fun1();}";
function fun1(){
document.getElementsByClassName('abc').style.color="red";
}
.onclick does not expect to receive a string, and in fact you don't need an extra function at all.
However, to assign it to each element, use a loop, like I'm sure you must have learned about in a beginner tutorial.
var els = document.getElementsByClassName('abc');
for (var i = 0; i < els.length; i++) {
els[i].onclick = fun1;
}
function fun1() {
this.style.color = "red";
}
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
To expand on the solution provided by #rock star I added two small additions to the function. First it is better to add / reemove a class (with an associated style rule) to an element than directly applying the stylerule to the element.
Secondly - on the click event - this will now remove the red class (and therefore style) from the previously selected element and add it to the new element. This will allow only one element to be red at a time (in the original solution any element that was clicked would become red).
var els = document.getElementsByClassName('abc');
for (var i = 0; i < els.length; i++) {
els[i].onclick = fun1;
}
function fun1() {
var oldLink = document.getElementsByClassName('red')[0];
if(oldLink) {oldLink.classList.remove('red')};
this.classList.add('red');
}
.red {
color:red;
}
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
This works:
<body>
<div class="abc">first</div>
<div class="abc">second</div>
<div class="abc">third</div>
<script>
var elements = document.getElementsByClassName('abc');
for(var i = 0, max = elements.length; i < max; i += 1) {
var clickedElement = elements[i];
clickedElement.onclick=function (){
fun1(this);
};
}
function fun1(element){
element.style.color="red";
}
</script>
</body>
I'm attempting to add data-webpart attributes to all the anchors within a document, but populate their values with the data attributes of their containing divs.
However the code I wrote appears to be populating all of the anchors with only one of the data attributes (or rather, adding the first one to all, then adding the second).
Any help would be much appreciated!
HTML
<body>
<div data-webpart="form">
Test Link
Test Link
Test Link
</div>
<div data-webpart="icon-grid">
Test Link
Test Link
Test Link
</div>
</body>
JavaScript
// data attributer
var webParts = document.querySelectorAll("[data-webpart]");
var webPartAnchors = document.querySelectorAll("[data-webpart] > a");
function addDataAttr() {
var closestWebPartAttr;
for (i = 0; i < webPartAnchors.length; i++) {
for (e = 0; e < webParts.length; e++) {
closestWebPartAttr = webParts[e].getAttribute("data-webpart");
webPartAnchors[i].setAttribute("data-web-part", closestWebPartAttr);
}
}
}
window.onload = function() {
if (webParts !== null) { addDataAttr(); }
};
Your nested loops are copying the data attribute from every DIV to every anchor, because there's nothing that relates each anchor to just their parent. At the end they all have the last data attribute.
Since the anchors are direct children of the DIV, you don't need to use querySelectorAll() to get them, you can just use .children() within the loop.
function addDataAttr() {
for (var i = 0; i < webParts.length; i++) {
var webpart = webParts[i].dataset.webpart;
var children = webParts[i].children;
for (var j = 0; j < children.length; j++) {
children[j].dataset.webpart = webpart;
}
}
}
I am making a gallery. All images are named 1.jpg, 2.jpg, 3.jpg etc - it extends all the way up to 200.jpg.
Copy and paste will be OK, but very time consuming.
<div class="slideshow-container">
<div class="slideshowDisplay fade">
<img src="/images/media/1.jpg" width="100%">
</div>
<div class="slideshowDisplay fade">
<img src="/images/media/2.jpg" width="100%">
</div>
<div class="slideshowDisplay fade">
<img src="/images/media/3.jpg" width="100%">
</div>
Can I use a for-loop or similar to create all the elements for me? My only problem is that, a for loop is used to repeat a code block multiple times is it not, so this for me wouldn't work.
Is there another way that I can create elements without having to spend a long time simply incrementing numbers by hand?
So far I have:
for(var i=0; i < 200; i++){
var newDiv = document.createElement('div');
newDiv.className = 'slideshowDisplay fade';
}
Nothing else...
Any guidance much appreciated.
Basic DOM creation and appending
You're only missing appending the new element to the slideshow-container and adding its content. You can use the i variable to create the increment image src.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
var newDiv = sc.appendChild(document.createElement('div'));
newDiv.className = 'slideshowDisplay fade';
var img = newDiv.appendChild(document.createElement("img"));
img.width="100%";
img.src = "/images/media/" + (i + 1) + ".jpg";
}
String concatenation
The means of creating the src is called "string concatenation". In other words, we create a new string from multiple parts. First the "/images/media/" string, then the value of i, but adjusted up by one, and finally the ".jpg" part.
Making helper functions
FWIW, it's nice to have a personal micro-library that you use to handle certain repetitive tasks. One such inclusion can be a function for creating new Elements.
function create(elem, props, par) {
var el = document.createElement(elem)
for (var p in props) {
el[p] = props[p]
}
return par ? par.appendChild(el) : el
}
This takes a little verbosity out of creating and appending the new elements.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
var newDiv = create("div", {className: "slideshowDisplay fade"}, sc);
create("img", {width: "100%", src: "/images/media/"+(i+1)+".jpg"}, newDiv);
}
Different approach to a helper function
Or instead of having the function receive the parent to which it is appended, you could allow it to receive an arbitrary number of child elements that it will append to itself.
function create(elem, props, ...children) {
var el = document.createElement(elem)
for (var p in props) {
el[p] = props[p]
}
children.forEach(ch => el.appendChild(ch))
return el
}
Then you can nest calls to create in a way that mirrors the new DOM structure.
var sc = document.querySelector(".slideshow-container")
for(var i=0; i < 200; i++){
sc.appendChild(
create("div", {className: "slideshowDisplay fade"},
create("img", {width: "100%", src: "/images/media/"+(i+1)+".jpg"})
)
);
}
Actually you need just one parent div in your DOM. Then just use functions like document.createElement and appendChild to store the newly created divs with pictures inside the parent element.
var source = "/images/media/";
var parent = document.getElementById('parent');
for (var i = 0; i < 10; i++) {
var newDiv = document.createElement('div');
newDiv.className = 'slideshowDisplay fade';
var img = document.createElement('img');
img.src = source + i + '.jpg';
img.width = '100%';
newDiv.appendChild(img);
parent.appendChild(newDiv);
}
<div class="slideshow-container" id='parent'>
</div>
I'm having a strange issue with replaceWith (or more likely with object referencing).
I am trying to create a kind of table of rows that either have empty slots or full slots. As a demonstration I made this simple fiddle. http://jsfiddle.net/Ltxtvyn3/3/ In this fiddle 4 empty slots are initialized. Then one is filled. Then the same one should be emptied. But instead it is remaining filled. It is as if I can only use replaceWith once, or I am not understanding something about my object references.
HTML
<div class = "slot empty">Empty</div>
<div class = "slot full">Full</div>
<div class = "wrapper"></div>
CSS
.slot{
width:50px;
height:50px;
display:none;
}
.empty{
background-color:red;
}
.full{
background-color:blue;
}
Javascript
var wrapper = $('.wrapper');
var empty = $('.slot.empty');
var full = $('.slot.full');
var slots = {};
for(var i = 0; i < 4; i++){
slots[i] = empty.clone().show();
wrapper.append(slots[i]);
}
function fillSlot(id){
slots[id].replaceWith(full.clone().show());
}
function emptySlot(id){
slots[id].replaceWith(empty.clone().show());
}
fillSlot(1);
emptySlot(1);
I am hoping that the object var slots maintains a reference to the divs and I'm not sure if it is doing that or not.
No, it's not keeping a reference, but you can fix this pretty easily.
Here's some running code:
var wrapper = $('.wrapper');
var empty = $('.slot.empty');
var full = $('.slot.full');
for(var i = 0; i < 4; i++){
wrapper.append(empty.clone().show());
}
function fillSlot(id){
$(".wrapper .slot").eq(id).replaceWith(full.clone().show());
}
function emptySlot(id){
$(".wrapper .slot").eq(id).replaceWith(empty.clone().show());
}
fillSlot(1);
setTimeout(function() {
emptySlot(1);
}, 2000);
.slot{
width:50px;
height:50px;
display:none;
}
.empty{
background-color:red;
}
.full{
background-color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class = "slot empty">Empty</div>
<div class = "slot full">Full</div>
<div class = "wrapper"></div>
Thanks for the answers. I know understand why the object doesn't keep a reference, and I really wanted that to be the case. I simply added a wrapper slot and then I will affect the contents of the wrapper. That way I always have a reference to the slot.
HTML
<div class="slot-content empty">Empty</div>
<div class="slot-content full">Full</div>
<div class = "slot"></div>
<div id="wrapper"></div>
Javascript
var wrapper = $('#wrapper');
var slot = $('.slot');
var empty = $('.slot-content.empty');
var full = $('.slot-content.full');
var slots = {};
for(var i = 0; i < 4; i++){
slots[i] = slot.clone().show();
slots[i].html(empty.clone().show());
wrapper.append(slots[i]);
}
function fillSlot(id){
slots[id].html(full.clone().show());
slots[id].find('.slot-content').html('hello');
}
function emptySlot(id){
slots[id].html(empty.clone().show());
}
fillSlot(1);
emptySlot(1);
fillSlot(2);
UPDATED
Your code work fine just if you change the selection method and you don't want slots list no more.
Replace :
function fillSlot(id){
slots[id].replaceWith(full.clone().show());
}
function emptySlot(id){
slots[id].replaceWith(empty.clone().show());
}
BY :
function fillSlot(id){
wrapper.children().eq(id).replaceWith(full.clone().show());
}
function emptySlot(id){
wrapper.children().eq(id).replaceWith(empty.clone().show());
}
Selecting directly from wrapper what means selecting from fresh DOM. that will fix the problem, take a look at updated fiddle bellow.
Updated JSFiddle
The problem is slots[i] isn't pointing to the div - so replaceWith won't pick the right item. Update the loop as follows (adding slots[i] = wrapper.find(':last-child') ):
for(var i = 0; i < 4; i++){
slots[i] = empty.clone().show();
wrapper.append(slots[i]);
slots[i] = wrapper.find(':last-child')
}
Actually this may make the code a little easier to understand (replace loop with this instead)
for(var i = 0; i < 4; i++){
wrapper.append(empty.clone().show());
slots[i] = wrapper.find(':last-child')
}
Tested and works on FF..
It's not keeping a reference to the DOM element. If you still want to use the array, then you can just repopulate the list every time you update one of its elements. Not terribly efficient, but I suppose it saves you from keeping state in the DOM.
function redraw() {
$('.wrapper').empty();
for(var i = 0; i < 4; i++){
wrapper.append(slots[i]);
}
}
JSFiddle
I have the following:
<style>
.el {color: blue;}
</style>
<div class="el">bla bla</div>
<div class="el">bla bla 123</div>
And i need to use JavaScript to change the color in .el.
I know about document.styleSheets but that seems kind of crude, having to loop search for the class i want to change it that way. Isn't there some better (lighter) way to do this nowadays? Something like
document.stylesheets.getclass('.el').color = 'red';
Thanks.
You're on the right track. The method you're looking for is getElementsByClassName, not getClass. It returns an array, and then you simply loop through the array and assign the new color.
var el = document.getElementsByClassName('el'),
i;
for (i = 0; i < el.length; i += 1) {
el[i].style.color = 'red';
}
Demo
P.S., obviously, this changes the style, not the stylesheet.
Try this:
var elem = document.getElementsByClassName('el');
for (var i = 0; i < elem.length; i++) {
elem[i].style.color = '#aaaaaa';
}