getElementById to getElementsByClassName [duplicate] - javascript

This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 8 years ago.
I have this code which is working. But it is only for one textarea because it uses ID. However i would like to use this for all textareas that on my code. I have tried getElementsByClassName but it didn't work.
HTML:
<textarea id="textarea1" class="form-control page-textarea" rows="4" style="height:92px;" name="memory" placeholder="new comment..."></textarea>
JS:
<script type="text/javascript">
var textarea = document.getElementById("textarea1");
var limit = 200;
textarea.oninput = function() {
textarea.style.height = "";
textarea.style.height = Math.min(textarea.scrollHeight, limit) + "px";
if(textarea.style.height == "92px"){
textarea.style.overflow = "hidden";
} else if(textarea.style.height < limit + "px"){
textarea.style.overflow = "hidden";
} else {
textarea.style.overflow = "auto";
}
};
</script>
How do i do this?

If you take a look at the docs you'll see that getElementsByClassName returns a HTMLCollection. You will have to loop through all the child elements to make it work.
var textareas = document.getElementsByClassName("form-control page-textarea");
var limit = 200;
for(var i=0, length= textareas.length; i < length; i++){
var textarea = textareas[i];
textarea.oninput = function() {
this.style.height = "";
this.style.height = Math.min(this.scrollHeight, limit) + "px";
if(this.style.height == "92px"){
this.style.overflow = "hidden";
} else if(this.style.height < limit + "px"){
this.style.overflow = "hidden";
} else {
this.style.overflow = "auto";
}
};
}
FIDDLE

I thing event delegation is much better approach in this situation.
Check this code.
document.addEventListener('input', function(event) {
var limit = 200;
if(event.target.getAttribute("class") == "form-control page-textarea") {
var target = event.target;
target.style.height = "";
target.style.height = Math.min(target.scrollHeight, limit) + "px";
if(target.style.height == "92px"){
target.style.overflow = "hidden";
} else if(target.style.height < limit + "px"){
target.style.overflow = "hidden";
} else {
target.style.overflow = "auto";
}
}
}, false);
Here is working jsFiddle.
http://jsfiddle.net/yg6sS/5/
In this way we save loop trought elements.

use jquery to easily solve this
$(function() {
$("textarea").css("border", "3px solid red");
(OR)
$("textarea").css('border':'3px solid red','color':'Green');
});

Related

Displaying div based on dropdown value

I have 3 divs each with a distinct id. Based off the value of a dropdown I have, I want to show one of the divs. I created my function and call it, but for some reason no change occurs. The new value of the dropdown is never recorded, when I use console.log. I am unsure what is causing the problem and would appreciate any help.
HTML
<div class="ins-left" id="fifteen">
<p>$15</p>
</div>
<div class="ins-left" id="thirty">
<p>$30</p>
</div>
<div class="ins-left" id="fourtyfive">
<p>$45</p>
</div>
CSS
#fifteen {
display: none;
}
#thirty {
display: none;
}
#fourtyfive {
display: none;
}
JS
var length = document.getElementById('length');
var chosenLength = length.options[length.selectedIndex].value;
var start = document.getElementById('start').innerHTML.split('.').join('').toLocaleLowerCase();
var end = document.getElementById('end').innerHTML.split('.').join('').toLocaleLowerCase();
var time = document.getElementById('time');
time.disabled = true;
function disabled() {
if (chosenLength.value != "") {
time.disabled = false;
}
}
var slotTimes = [];
document.getElementById("length").onchange = function (evt) {
var timeDistance = evt.target.value;
var startMoment = moment(start, "h:mm a");
var endMoment = moment(end, "h:mm a");
slotTimes = [];
while (startMoment.isSameOrBefore(endMoment)) {
slotTimes.push(startMoment.format("h:mm a"));
startMoment = startMoment.add(timeDistance, 'minutes');
}
addDropdown();
price();
};
function price(){
if (chosenLength.value === "") {
document.getElementById('fifteen').style.display = "none";
document.getElementById('thirty').style.display = "none";
document.getElementById('fourtyfive').style.display = "none";
}
if (chosenLength.value === "30") {
document.getElementById('fifteen').style.display = "block";
document.getElementById('thirty').style.display = "none";
document.getElementById('fourtyfive').style.display = "none";
}
if (chosenLength.value === "60") {
document.getElementById('fifteen').style.display = "none";
document.getElementById('thirty').style.display = "block";
document.getElementById('fourtyfive').style.display = "none";
}
if (chosenLength.value === "90") {
document.getElementById('fifteen').style.display = "none";
document.getElementById('thirty').style.display = "none";
document.getElementById('fourtyfive').style.display = "block";
}
}
function addDropdown() {
var doc = '',
times = slotTimes,
i;
for (i = 0; i < times.length; i++) {
doc += "<option value='" + times[i] + "'>" + times[i] + "</option>";
}
document.getElementById('time').innerHTML = doc;
disabled();
}
I made a simple working example for you here, so you can adjust your code based on this:
https://codepen.io/brunomont/pen/WmExvV
I had to remove a couple of broken references since your HTML didn't include everything (like the time elements). Also, make sure you have all the dependencies loading (I noticed you are using moment.js).
The changes I made were:
Adding a document.addEventListener("DOMContentLoaded", function() to make sure your HTML was loaded, before you tyr to run the JavaScript.
Change the way you bind your onChange function to be document.getElementById('length').addEventListener('change', function (evt)
Basically, the addEventListener is more flexible than onChange. You can read more about this change here:
addEventListener vs onclick
Hope it helps :)

Javascript list with clickable elements [duplicate]

This question already has an answer here:
Basic questions about javascript
(1 answer)
Closed 5 years ago.
I am working on a script that would generate random list of 100 elements where every third element would be clickable. So far I am stuck at stage below. Any ideas how to progress?
var hundred = Array(100);
hundred.toString();
for (i = 0; i < hundred.length; i++) {
document.write("Item " + (i + 1) + " of" + hundred.length + "</br>")
}
I used buttons. every third element will be clickable. remaining elements will have disabled property
var hundred = Array(100);
hundred.toString();
for (i = 0; i < hundred.length; i++) {
if(i%3===0 && i!==0){
var button = document.createElement("button");
button.innerHTML ="Click "+i ;
document.getElementsByTagName('body')[0].appendChild(button);
}else{
var button = document.createElement("button");
button.innerHTML ="Click "+i ;
button.disabled = true;
document.getElementsByTagName('body')[0].appendChild(button);
}
}
Edited: full example
var hundred = Array(100);
var node;
hundred.toString();
for (i = 0; i < hundred.length; i++) {
if(i%3===0 && i!==0){
node = document.createElement("button");
node.addEventListener('click', function() { alert('clicked'); });
node.innerHTML = 'clickablke';
} else {
node = document.createElement("div");
node.innerHTML = 'just div';
}
document.body.appendChild(node);
}
First you need create the element. Then apply the onclick with this consition i%3 == 0 to every 3 rd element
Updated
after click its a bolder using classList.add()
for (i = 1; i < 10; i++) {
var s = document.createElement('SPAN');
if (i % 3 == 0) {
s.className = 'clickable';
s.onclick = clicks;
}
s.textContent=i;
document.body.appendChild(s)
}
function clicks() {
console.log(this.innerHTML)
this.classList.add('bold')
}
.clickable {
color: red;
}
.bold{
font-weight:bolder;
}
As commented,
Instead of using document.write, use document.createElement to create an element and assign them event listener and append these elements to an element in html or document.body
var hundred = Array(100);
for (i = 0; i < hundred.length; i++) {
let el = document.createElement('span');
el.textContent = i + " ";
if((i+1) % 3 === 0){
el.classList.add('clickable')
el.addEventListener("click", notify)
}
document.body.appendChild(el)
}
function notify(){
this.classList.add('clicked')
console.log(this.textContent)
}
.clickable{
color: blue;
text-decoration: underline;
}
.clicked{
color: gray;
}
References
Why is document.write considered a "bad practice"?
Document.createElement
add onclick event to newly added element in javascript
Multiple wayst to do this, i'd make an event listener to every item reference, hence: every third clickable element goes bold:
var hundred = Array(100);
hundred.toString();
var btn = Array(100);
for (i = 0; i < hundred.length+1; i++) {
btn = document.createElement("p");
btn.innerHTML="Item " + (i-1 + 1) + " of" + hundred.length + "</br>";
if(i%3===0 && i!==0){
btn.addEventListener('click', function() {
this.style.fontWeight = 'bold'; }, false);
}
document.body.appendChild(btn);
}

firstChild of an element in JavaScript constructor class

I'm having trouble understanding why I can't properly access firstChild of an element object in a JavaScript class. I can set innerHTML without the firstChild properly, but I'd like to set it on firstChild. Using console.dir(this.waitStatus) shows that it has a firstChild. I'm not using jQuery because it may not be loaded when I want this run, since it is a loading indicator.
class LoadingIndicator{
constructor(elementID){
this.tick = 8;
this.waitStatus = document.getElementById(elementID);
setInterval(
this.animateLoader.bind(this),
10
)
}
animateLoader (){
if(this.tick == 8){
this.waitStatus.firstChild.innerHTML = ".";
}
else if(this.tick == 16){
this.waitStatus.firstChild.innerHTML = "..";
}else if(this.tick == 24){
this.waitStatus.firstChild.innerHTML = "...";
this.tick = 0;
}
this.tick += 1;
}
}
var supervisorLoadingIndicator = new LoadingIndicator('supervisorsTableLoading');
html
<p id='supervisorsTableLoading' style='width:700px; height:0px; text-align:left; padding-bottom:20px;'>
<span id='supervisorsTableLoadingInner' style='margin-left:30%'> </span>
</p>
The firstChild is a text node (the line break before the <span), so .innerHTML isn't useful. Use .firstElementChild instead, or .children[0].
class LoadingIndicator {
constructor(elementID) {
this.tick = 8;
this.waitStatus = document.getElementById(elementID);
setInterval(this.animateLoader.bind(this), 10)
}
animateLoader () {
if (this.tick == 8) {
this.waitStatus.firstElementChild.innerHTML = ".";
} else if (this.tick == 16) {
this.waitStatus.firstElementChild.innerHTML = "..";
} else if (this.tick == 24) {
this.waitStatus.firstElementChild.innerHTML = "...";
this.tick = 0;
}
this.tick += 1;
}
}
var supervisorLoadingIndicator = new LoadingIndicator('supervisorsTableLoading');
Or you could simply get rid of that whitespace text and use .firstChild.
Also, you're not really setting HTML content, so I'd personally use .textContent instead.
this.waitStatus.firstElementChild.textContent = "...";
IE8 and lower don't support either of these properties.
If you're still supporting IE8, then you can polyfill them both.
If you're supporting IE6/7, then stick with .innerHTML and get rid of that whitespace.
use this.waitStatus.children[0], firstChild will return non element node.
class LoadingIndicator{
constructor(elementID){
this.tick = 8;
this.waitStatus = document.getElementById(elementID);
console.log(this.waitStatus.firstChild);
setInterval(
this.animateLoader.bind(this),
10
)
}
animateLoader (){
if(this.tick == 8){
this.waitStatus.children[0].innerHTML = ".";
}
else if(this.tick == 16){
this.waitStatus.children[0].innerHTML = "..";
}else if(this.tick == 24){
this.waitStatus.children[0].innerHTML = "...";
this.tick = 0;
}
this.tick += 1;
}
}
var supervisorLoadingIndicator = new LoadingIndicator('supervisorsTableLoading');
<p id='supervisorsTableLoading' style='width:700px; height:0px; text-align:left; padding-bottom:20px;'>
<span id='supervisorsTableLoadingInner' style='margin-left:30%'> </span>
</p>

Fade out Using getElementsByClassName

I'm trying to use change the opacity of a class that is passed into the function parameter as element. It seems to crash as it reaches "target.style.opacity = newSetting"
I'm not sure what is causing this issue because when I use a getElementById instead it works.
here's the Javascript
var fade_out_from = 10;
function fadeOut(element)
{
moving = true;
var target = document.getElementsByClassName(element);
var newSetting = fade_out_from / 10;
target.style.opacity = newSetting;
fade_out_from--;
if(fade_out_from == 0){
target.style.opacity = 0;
target.style.display = "none";
clearTimeout(loopTimer);
fade_out_from = 10;
moving = false;
return false;
}
var loopTimer = setTimeout(fadeOut(element),10);
}
document.getElementsByClassName returns a list of elements (https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName) that is why target.style.opacity is undefined. Instead try to use target[0].style.opacity (unless you actually need to deal with more than one found element; in that case the script will become slightly more complex).
But even then the script won't fade out the element because of the way you are using setTimeout (https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout). The first parameter there is supposed to be a callback (just a name of a function). If you want to pass parameters, you need to add them as 3rd, 4th, etc. parameters (won't work in IE<9).
So your script may look the following way:
var fade_out_from = 10;
function fadeOut(element)
{
moving = true;
var target = document.getElementsByClassName(element);
var newSetting = fade_out_from / 10;
target[0].style.opacity = newSetting;
fade_out_from--;
if(fade_out_from == 0){
target[0].style.opacity = 0;
target[0].style.display = "none";
clearTimeout(loopTimer);
fade_out_from = 10;
moving = false;
return false;
}
var loopTimer = window.setTimeout(fadeOut,10, element);
}
So this is what I came out with that seemed to do the trick. You would just have to add aditional "target[2].style.opacity = setting" to account for additional elements in the same class.
var fade_out_from = 10;
var fadeTimer = setTimeout(function fadeOut(element){
var target = document.getElementsByClassName(element);
if(fade_out_from == 0){
target[0].style.opacity = 0;
target[1].style.opacity = 0;
fade_out_from = 10;
moving = false;
clearTimeout(fadeTimer);
return false;
}
moving = true;
var newSetting = fade_out_from / 10;
target[0].style.opacity = newSetting;
target[1].style.opacity = newSetting;
fade_out_from--;
return true;
},50);

Make eventlisteners unique?

So I have a problem where the eventlisteners I setup all happen to work with the same variable.
This is how it looks like:
// Prepare tooltips
for (var i = 0; i < document.getElementsByClassName("tooltip").length; i++) {
var tooltip = document.getElementsByClassName("tooltip")[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null) {
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
input.addEventListener("focus", function() { document.getElementById(tooltip.id).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(tooltip.id).style.display = "none"; });
}
In the last two lines I set the eventlisteners.
So whenever I focus an input field, no matter which one tooltip.id is always the same.
I checked the input.id before its different in every loop.
Javascript is a funny language :)
In each loop you're declaring a function which uses a reference to the variable tooltip.
Since you use the variable many times: its value changes but the reference remains the same.
When the function executes, it uses the reference (which has the last value).
Here is the solution:
(I recommend calling the method 'document.getElementsByClassName("tooltip")' only once since it causes DOM traverse.
==== CODE STARTS HERE
var toolips = document.getElementsByClassName("tooltip");
for (var i = 0; i < toolips.length; i++)
{
var tooltip = toolips[i];
var input = document.getElementsByName(tooltip.id.substr(8))[0];
var offsetTop = 0;
var tmp = input;
while (tmp != null)
{
offsetTop += tmp.offsetTop;
tmp = tmp.offsetParent;
}
offsetTop -= 130;
var offsetLeft = (input.offsetParent.offsetLeft + input.scrollWidth) + 50;
tooltip.innerHTML += "<div class='corner'></div>";
tooltip.style.top = offsetTop + "px";
tooltip.style.left = offsetLeft + "px";
// assign tooltip id to the input
input.tooltipId = tooltip.id;
// add event listeners
input.addEventListener("focus", function() { document.getElementById(this.tooltipId ).style.display = "block"; });
input.addEventListener("blur", function() { document.getElementById(this.tooltipId).style.display = "none"; });
}
==== CODE ENDS HERE

Categories

Resources