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;
}
}
}
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 am trying to toggle multiple classes onclick using vanilla Javascript. What i am trying to do is when a btn is clicked two classes to toggle with another two classes. I have 5 classes in total which are: .menu_btn , .main_nav, .btn_active, .container, .container_active. When i press the .menu_btn i would like the classes .main_nav to toggle with .btn_active and at the same time i would like to have the .container to toggle with .container_active. The class .container is the only one that has 5 elements of that class, the others are single. I have done this using jQuery but i would like to know the way using vanilla Javascript. Hopefully someone can help.
One thing to point out is when i console.log the .btn_active and .container_active i get back [ ] an empty array. Those 2 css classes are not assigned to any element of my project. They are existing only in the css and their purpose is for toggle.
Thanks
jQuery Code:
$(function(){
$(".menu_btn").on("click", function(){
$(".main_nav").toggleClass("btn_active");
$(".container").toggleClass("container_active");
});
});
Vanilla Javascript Code:
var menuBtn = document.getElementsByClassName("menu_btn");
var mainNav = document.getElementsByClassName("main_nav");
var btnActive = document.getElementsByClassName("btn_active");
var container = document.getElementsByClassName("container");
var containerActive = document.getElementsByClassName("container_active");
menuBtn.onclick = function(){
mainNav.classList.toggle(btnActive);
for ( index = 0; index <= container.lenght -1; index++ ){
container[index].classList.toggle(containerActive);
}
};
I have modified your script and created a fiddle so you see how it works: https://jsfiddle.net/eyrpdsc2/
The toggle accepts a string as a parameter, not a Node. So you need to pass 'btn_active' instead of btnActive. Also keep in mind that querySelectorAll returns a NodeList (not an array) so you cannot use forEach.
var menuBtn = document.querySelectorAll(".menu_btn");
var mainNav = document.querySelectorAll(".main_nav");
var container = document.querySelectorAll(".container");
for (var i = 0; i < menuBtn.length; ++i) {
menuBtn[i].addEventListener('click', toggleClasses);
}
function toggleClasses() {
var i = 0;
for (i = 0; i < mainNav.length; ++i) {
mainNav[i].classList.toggle('btn_active');
}
for (i = 0; i < container.length; ++i) {
container[i].classList.toggle('container_active');
}
}
I have several links on a page, they are turned into an array with jQuery. Basically, when the user clicks "load more" on the page I would like to generate a <ul> with 4 images inside (or less if there aren't 4 remaining. I then need to shut the </ul>. I cannot figure out how I'd write this, does anyone know? Also, is this code ok or should it be tidied up somehow?
What I'd really like is a way to hide the 4 images while they load and then slide down the new <ul> but I don't know how as I don't know where I could write a callback function in there. Feel free to point me in the right direction if you know how!
My code so far;
var hrefs = jQuery.makeArray(jQuery('ul.js a'))
jQuery('#load_more').bind('click',function(){
jQuery('.img_gallery').append('<ul>')
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
jQuery('<li>').append(jQuery('<img>', {src:hrefs[0]})).appendTo(jQuery('.img_gallery'))
hrefs.splice(0,1)
}
}
jQuery('.img_gallery').append('<ul>')
})
Thanks : )
Try this approach .. this is lot cleaner
var hrefs = jQuery.makeArray(jQuery('ul.js a'))
jQuery('#load_more').bind('click', function() {
var html = '<ul>'
for (var c = 0; c < 4; c++) {
if ((hrefs.length) > 0) {
html += '<li><img src="' + hrefs[0] + '" /></li>' ;
hrefs.splice(0,1);
}
}
html += '</ul>'
jQuery('.img_gallery').append(html )
})
Your hrefs array contains DOM elements, not URLs. Try this instead:
var hrefs = jQuery.map(jQuery('ul.js a'), function(el,i) {
return $(el).attr('href');
});
Incidentally, you can optimize your for loop as follows:
for (var c = 0; c < 4; c++) {
if (hrefs.length) {
jQuery('<li>').append(jQuery('<img>', {
src: hrefs.shift() // removes and returns the first array element
})).appendTo(jQuery('.img_gallery'));
};
};
When you use jQuery you are not appending html tags, you are appending html elements.
When you do $('.img_gallery').append('<ul>'), and then $('.img_gallery').append('<li>'), you end up with a structure like this:
<div class="img_gallery">
<ul></ul>
<li></li>
</div>
You do not have to worry about closing tags, just creating elements. jQuery "closes" all the tags for you in a sense. You need to append your li elements to the ul, not the .img_gallery. Just append to the last ul:
var hrefs = $.makeArray(jQuery('ul.js a'))
$('#load_more').bind('click',function(){
$('.img_gallery').append('<ul>');
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
$('<li>').append($('<img>', {
src: $(hrefs[0]).attr('href'); // get the link reference from the element
})).appendTo($('.img_gallery ul').last()); // append to the last ul, not .img_gallery
hrefs.splice(0,1);
}
}
});
Or, you can keep your ul as a variable, add your li's and append the list after the loop:
var hrefs = $.makeArray(jQuery('ul.js a'))
$('#load_more').bind('click',function(){
var newul = $('<ul>'); // Makes an element, not a tag
for(var c = 0; c < 4; c++){
if((hrefs.length) > 0){
$('<li>').append($('<img>', {
src: $(hrefs[0]).attr('href'); // get the link reference from the element
})).appendTo(newul); // append to the ul you created
hrefs.splice(0,1);
}
}
$('.img_gallery').append(newul);
});
I have a tree structure as follows:
<ul id="theul275">
<li>
<div id="red"></div>
<img id="green" />
<script></script>
<div id="blue"></div>
</li>
</ul>
There are multiple UL's likes this on my page each with a different id. I am getting each UL by doing this:
var child = document.getElementById('theul' + id).getElementsByTagName('*');
the problem is, I only want to get the children of each ul which are either div's or img's.
Is there a way to get elements by multiple tag names?
I really appreciate any help because I am kind of new to JavaScript! Thanks!
Depending on what browsers you may to support, you could use the CSS selector interface.
document.getElementById('theul275').querySelectorAll('div, img');
Or use a library. There are plenty of options out there. I am familiar with two,
MooTools
$('theul275').getElements('div, img');
jQuery
$('#theul275').find('div, img');
Or get a reference to the li node, and loop through each node and check if the nodeName is DIV or IMG.
for (var i = 0, l = child.length; i < l; i++)
{
if (child[i].nodeName == 'DIV' || child[i].nodeName == 'IMG')
{
//...
}
}
You could use a iterative method for this.
var elemArray = document.getElementById('theul' + id).childNodes,
getChildByNodeName = function (elem, pattern) {
var childCollection = [],
re = new RegExp(pattern, 'g'),
getChild = function (elements) {
var childs = elements.childNodes,
i = 0;
if (childs) {
getChild(childs);
for (i = 0; i < childs.length; i += 1) {
if (childs[i].nodeName.match(pattern)) {
childCollection.push(childs[i]);
}
}
}
};
getChild(elem);
return childCollection;
}
var childs2 = getChildByNodeName(elemArray, '^(DIV|IMG)$'); // array of match elements
And just change the pattern ('^(DIV|IMG)$') to suite your needs.
If you can use jQuery, try
var child = $("#theul" + id).find("div,img");
Otherwise, see JavaScript NodeList.
How can we disable all the elements in html through javascript.The easiest way...
I suggest to do it the "Lightbox"-style way.
Add an absolute positioned, transparent, full screen div Layer above the Page.
This way, the user can't even click on a Link.
To give the user a visual feedback that the page is disabled,
you can make the div e. g. 50% transparent black.
BTW, here is also a jQuery Plugin that uses a similar technique.
The easiest way is to put all form elements you want to disable inside a <fieldset> and then disable the fieldset itself.
An example: http://jsfiddle.net/xdkf9b8j/1/
If you don't want the border around the fieldset, remove it per css.
Try this,
function disableForm(theform) {
if (document.all || document.getElementById) {
for (i = 0; i < theform.length; i++) {
var formElement = theform.elements[i];
if (true) {
formElement.disabled = true;
}
}
}
}
Or else you can try this too, as RaYell said
function disableForm() {
var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
inputs[i].disabled = true;
}
var selects = document.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++) {
selects[i].disabled = true;
}
var textareas = document.getElementsByTagName("textarea");
for (var i = 0; i < textareas.length; i++) {
textareas[i].disabled = true;
}
var buttons = document.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
}
}
To disable the whole page you can find some info here,
I don't know why you would need that but this will work:
// this will disable all input elements
var elems = document.getElementsByTagName('input');
var len = elems.length;
for (var i = 0; i < len; i++) {
elems[i].disabled = true;
}
All the form elements (inputs, selects, textareas) within a form, are accesible through the form.elements HTMLCollection, you can iterate the collection disabling each element:
function disableForm(form) {
var length = form.elements.length,
i;
for (i=0; i < length; i++) {
form.elements[i].disabled = true;
}
}
Usage examples:
disableForm(document.forms[0]);
disableForm(document.getElementById('formId'));
Once i had to create a tutorial for my website. I needed to disable all interactions on a page excluding some elements. To do so i used this method:
First make sure to remove all events bindings from your page elements. You can do this by using:
$('*').unbind();
Next disable all links on your page:
$('a').each(function(){$(this).click(function(){return false;})});
and disable all inputs:
$('input').attr('disabled', true);
The code needs to be executed at the end of your document. BTW you may exclude some elements within jquery selector to keep them active.
To lock:
var controls = document.querySelectorAll("button, input, select, textarea");
for (var c of controls) {
c.disabled = true;
}
To unlock:
var controls = document.querySelectorAll("button, input, select, textarea");
for (var c of controls) {
c.disabled = false;
}
That simple.
Just and without crutches!
/**
* Enable/disable all form controlls
* #param status Status: true - form active, false - form unactive
*/
HTMLFormElement.prototype.setStatus = function (status) {
for (var i in this.elements) {
this.elements[i].disabled = !status;
}
};
// Example:
var my_form = document.getElementById('my_form_with_many_inputs');
my_form.setStatus(false); // Disable all inputs in form
my_form.setStatus(true); // Enable all inputs in form
Depending what result you need you could also do
`document.getElementById('main_form').style.display = 'none';`
Where main_form is the id of your form. You can use the same technique to hide a div containing whatever elements you want to disable.
The best way is to add a div with highest z-index having width:100% and height:100%.It will cover your entire page and make everything not clickable means disabled virtually.It is best,because it will not use any loop and any complex code.