getElementsByClassNames()[0] returns undefined - javascript

I need to write a code that will toggle class of one element based of innet text of the other one or after clicking a button.
Here you can see the code
menuReactingYITH();
function menuReactingYITH(){
if (document.getElementsByClassName('raq-items-number') != null){
//declare constantses
var m = document.getElementsByClassName('yith-menu-element')[0];
var x = document.getElementsByClassName('raq-items-number')[0].innerText;
//add event listnere to "add to list" button
if(document.getElementsByClassName('add-request-quote-button') != null){
document.getElementsByClassName('add-request-quote-button')[0].addEventListener("click", function() {
m.classList.add('yith-list-full');
console.log(m.classList);
});
}
//add or remove active class from menu based on YITH widget
if(x!='0'){
m.classList.add('yith-list-full');
console.log('add active');
} else {
m.classList.remove('yith-list-full');
console.log(m.classList);
}
}
}
<li class="yith-menu-element">Element to change class</li>
<div class="raq-items-number">0 or 1</div>
<button class="add-request-quote-button">Change class</button>
I keep on getting undefine error with "yith-menu-element". The fun part is if I use console.log to check if I am actualy selecting any object it does work
Code I use to check sleecting
consol.log(document.getElementsByClassNames('yith-menu-element')[0].classList);

Related

Change class name of font-awesome when clicked

Here is the problem
This is my html code
<div id="bookmark">
<i class="far fa-bookmark"></i>
</div>
I want to change .far to .fas and vice versa in loop when clicked.
This is my updated javascript
function changeClass(elem) {
var i = elem.childNodes[1];
var c = i.classList;
console.log(i)
console.log(c)
// Change class
if (c.contains("far")) {
i.classList.remove("far");
i.classList.add("fas");
} else {
i.classList.remove("fas");
i.classList.add("far");
}
}
This is the screenshot of the console output in the browser when I click on the bookmark icon
Screenshot
When I pass the index value in the var c respectively, on i.classList[0] I get svg-inline--fa but I get undefined value in i.classList[3] instead of far. SO WHAT SHOULD I DO?
I hope this is what you are looking for (Demo: https://jsfiddle.net/hwv0oacL/8/)
HTML
<div id="bookmark" onclick="changeClass(this)">
<i class="far fa-bookmark"></i>
</div>
Javascript
changeClass(elem) {
var i = elem.childNodes[0].classList;
// Change class far to fas
if (i.includes("far")) {
i.classList.remove("far");
i.classList.add("fas");
}
// Get back to original state
if (i.includes("fas")) {
i.classList.remove("fas");
i.classList.add("far");
}
}
-------------------Updated--------------------------
Replace the above javascript with the one below. It will also work in loop like you want because we are getting element by this keyword.
JavaScript
function changeClass(elem) {
var i = elem.childNodes[1];
var c = i.classList;
// Change class
if (c.contains("far")) {
i.classList.remove("far");
i.classList.add("fas");
} else {
i.classList.remove("fas");
i.classList.add("far");
}
}
You can do it like below with jQuery:
$("#bookmark").find("i").removeClass("far");
$("#bookmark").find("i").addClass("fas");
assuming you want this to be done for single element and not for all the elements that are using .far class
add an id to the tag like id="i1" then you can add an event listener on that element. listening to the click event and once captured - toggle the class.
add the following just before the end of the body tag i.e. before </body>
<script>
document.getElementById('i1').addEventListener('click', (e) => {
e.target.classList.toggle('far');
e.target.classList.toggle('fas');
})
</script>

Click outside an element doesn't work

I have this code:
function showAll(el){
var id = el.parentNode.id;
var all= document.getElementById(id).getElementsByClassName('items')[0];
if(all.style.display === 'block'){
all.style.display = 'none';
} else{
all.style.display = 'block';
window.addEventListener('mouseup', function(e){
document.getElementById('test').innerHTML = e.target.className;
if(e.target != all){
all.style.display = 'none';
}
});
}
}
<div id="parent">
<div class="selected" onClick="showAll(this);">
</div>
<div class="items" style="display: none">
</div>
</div>
Basically what i want to achieve is: click on selected to display items which is now hidden after that if i click again on selected or if i click outside of items(a random spot on that page or even on selected) i want to be able to hide items.
The problem is that without the EventListener when i click on selected it works to display items and then if i click again on selected it works to hide items but if i click on a random spot it doesn't work to close items.
But when i add EventListener and i click on selected it works to click a random spot to close items but it doesn't work to click selected again to close items.
Can anybody help me with a full JavaScript explanation, please?
You're going to want to use highly reusable code. I use change() and id_() on my web platform all of the time and it's very direct and simple. In the below example the second parameter will make the class empty (you can also use id_('items').removeAttribute('class') for a cleaner DOM (Document Object Model)).
HTML
<input onclick="change(id_('items','');" type="button" value="Display Items" />
<div clas="hidden" id="items"><p>Items here.</p></div>
CSS
.hidden {display: none;}
JavaScript
function change(id,c)
{
if (id_(id)) {id_(id).className = c; if (id_(id).className=='') {id_(id).removeAttribute('class');}}
else if (id) {id.className = c; if (id.className=='') {id.removeAttribute('class');}}
else {alert('Error: the class id \''+id+'\' was not found or has not yet been imported to the DOM.\n\nNew class intended: '+c);}
}
function id_(id)
{
if (id == '' && window['console']) {console.log('Developer: empty id called from: '+id_.caller.toString().split('function ')[1].split('(')[0]);}
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
This code exists from years of refining the same platform instead of industry standard drama of pointlessly changing things. You are two clicks from finding more highly reusable functions on my platform's JavaScript documentation from the link in my profile.

Same button for 2 tables selection jquery

i have a page and i got 2 tables in that page. I want to pass the value from rows to one .php page but with the same button. My code is this:
JS code:
var flag;
function highlight(e) {
if (selected[0]){
selected[0].className = '';
flag='1';
}
else if (selected2[0]){
selected2[0].className = '';
flag='0';
}
e.target.parentNode.className = 'selected';
alert(flag);
}
var table = document.getElementById('data-table'),
selected = table.getElementsByClassName('selected');
var table2 = document.getElementById('data-table-aux'),
selected2 = table2.getElementsByClassName('selected');
table.onclick = highlight;
table2.onclick=highlight;
$("#tst").click(function(){
if(flag=='1'){
var value =$(".selected td:first").html();
value = value || "Nenhuma coluna selecionada";
window.open("info_detalhada.php? data2="+value,'_blank','toolbar=0,location=no,menubar=0,height=550,width=650,lef t=200, top=300'); }
else if(flag=='0'){
var value =$(".selected td:first").html();
value = value || "Nenhuma coluna selecionada";
window.open("info_detalhada2.php? data2="+value,'_blank','toolbar=0,location=no,menubar=0,height=550,width=650,lef t=200, top=300');
}
});
HTML CODE
creating 2 tables
<table style="float: left" id="data-table"></table>
<table style="float: left" id="data-table-aux"></table>
(Dynamic tables )
button:
<input type="button" id="tst" value="Detailed information" />
The problem is that first time i select a row the variable flag will have the old value and not the new value from click.
For example, first time i click a row flag = undefined , second time got the value of the table selected (0 or 1) , if i click on other row the flag wont change and will got the old value (or 0 or 1).
Any tips ?
Thanks
edited: i didnt put the html in first place because i dont think it's an html solution, I dont have a fiddle created because i'm using dynamic table's but i will try to make a fiddle with my example and i will put here when it's done ;)
Fiddle : https://jsfiddle.net/gwg639Lf/9/
Let me suggest a more generic approach
First of all wrap your tables in a div
<div class="data-tables">
<table style="float: left" id="data-table"></table>
<table style="float: left" id="data-table-aux"></table>
</div>
Then delegate the click event handlers
$('.data-tables').delegate('table', 'click', function(event) {
$this = $(this)
$this.addClass('active').removeClass('inactive')
$this.siblings().addClass('inactive').removeClass('active')
});
This function does the following:
Add class active and remove inactive (if exists) to the selected item/table
Remove the class active and add class inactive from all adjacent tables
In this way you will only have one active table at the time
Then declare your button handler
$("#tst").click(function(){
var value = $('.active').html()
// Use the value as you want
})
This code will work no matter how many tables you add to the div
You're setting the class name of the element after the condition statement. Hence, the first time, your flag variable is undefined.
Try putting it in the beginning of the highlight function.
function highlight(e) {
e.target.parentNode.className = 'selected';
if (selected[0]){
selected[0].className = '';
flag='1';
}
else if (selected2[0]){
selected2[0].className = '';
flag='0';
}
alert(flag);
}
JsFiddle: https://jsfiddle.net/gwg639Lf/10/
Edit:
Add it before and after the condition. Adding it before the condition gives you the class name to initialize the flag variable. Adding it after gives the formatting bar.
JsFiddle: https://jsfiddle.net/gwg639Lf/13/
Ok, after some tests on Kostas Pelelis functions, i found a solution that is valid for my problem.
here is the code of JS:
var flag;
$("#data-table tr").click(function(){
$("#data-table-aux tr").addClass('selected').siblings().removeClass('selected');
$(this).addClass('selected').siblings().removeClass('selected');
flag='1';
});
$("#data-table-aux tr").click(function(){
$("#data-table tr").addClass('selected').siblings().removeClass('selected');
$(this).addClass('selected').siblings().removeClass('selected');
flag='0';
});
$('#tst').on('click', function(e){
if (flag=='1')
alert($("#data-table tr.selected td:first").html());
else if (flag=='0')
alert($("#data-table-aux tr.selected td:first").html());
});
Here is the fiddle --> fiddle
Thank you all for the help ;)

Click visible button in protractor?

I have a page which looks something like this. It's a wizard with steps. Depending on the "step" scope variable, a different part of the wizard is shown:
<div ng-show="step == 'first'">
<button>Next</button>
</div>
<div ng-show="step == 'second'">
<button>Next</button>
</div>
<div ng-show="step == 'third'">
<button>Next</button>
</div>
To click the next button I run into problems though. Because there are three of them. The following code returns all of them:
var next = element(by.buttonText('Next'));
And doing:
next.click();
will click the first one. How can I find the visible button only, and click that one?
First I was confused by isDisplayed returning a promise. This function is what I came up with:
function clickButton(text) {
var buttons = element.all(by.buttonText(text));
buttons.each(function(button) {
button.isDisplayed().then(function(isVisible) {
if (isVisible) {
button.click();
}
})
});
}
Which can be used like this:
clickButton('next');
Here is a bit more cleaner version in terms of understanding that uses filter() to filter a single visible button and click it:
function clickButton(text) {
var buttons = element.all(by.buttonText(text));
var visibleButton = buttons.filter(function(button) {
return button.isDisplayed().then(function(isVisible) {
return isVisible;
});
}).first();
visibleButton.click();
}
As a bonus, you'll also get an error if there are no visible buttons found, as opposed to your current approach which would not fail in this case.
You should be able to chain the elements to specify which next button you want to click.
var firstNext = element(by.css('div[ng-show="step == \'first\'"]')).element(by.buttonText('Next'));
var secondNext = element(by.css('div[ng-show="step == \'second\'"]')).element(by.buttonText('Next'));
var thirdNext = element(by.css('div[ng-show="step == \'third\'"]')).element(by.buttonText('Next'));
// We are on the first step
firstNext.click();
// We are on the second step
secondNext.click();
// We are on the third step
thirdNext.click();

Get numerical value from parent with id like 'post-1' and use it in jQuery function

I'm trying to figure out the following.
I have following jQuery code:
var as = "";
var bPlay = 0;
audiojs.events.ready(function() {
as = audiojs.createAll();
$(".audiojs .play-pause").click(function() {
var e = $(this).parents(".audiojs").index(".audiojs");
$.each(as, function(t, n) {
if (t != e && as[t].playing) {
as[t].pause()
}
})
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar").stop();
}
})
});
In a nutshell it preforms list of things when someone clicks particular .audiojs instance on a page. 1) checks if there is any other instance playing, if there is pauses it. And if it is playing applies fluctuate function to elements on a page that have class="bar". This is the issue! I don't want to apply it to all .bar's on a page, but only to a specific group that is associated with particular .audiojs instance (the one that is being clicked and is playing).
I thought of the following solution. Each .audiojs instance is inside a div tag that has id like "post-1", "post-2" etc.. where numerical value is post id from database. I can add this numerical id to bar, so it would be like bar-1, bar-2 etc... However after this I'm having issues.
For javascript to work I need to retrieve numerical value from "post-[id]" associated with audiojs instance that is being clicked and than store it somehow, so I can use it like this afterwards
bPlay = !bPlay;
if (bPlay == 1) {
$(".bar-[value retrieved from post-...]").each(function(i) {
fluctuate($(this));
});
} else {
$(".bar-[value retrieved from post...]").stop();
}
Could someone explain to me how it can be achieved?
Honestly, the easiest way would be to stick it in a custom data-* attribute on the <div id="post-X"> element, like so:
<div id="post-1" data-bar="bar-1">...</div>
Then, you said your .audiojs element is inside that <div>, so just go from this inside the event handler to that <div> element (using .closest()) and get the value of it:
var barId = $(this).closest('[id^="post-"]').attr('data-bar');
Then when you need to use it:
$("." + barId).each(function(i) {
fluctuate($(this));
});
Instead of embedding the value in a class or ID, use a data-* attribute:
<div class="audiojs" data-fluctuate-target="bar-1">
<button type="button" class="play-pause">
<!-- ... -->
</button>
</div>
<div class="bar-1">
<!-- ... -->
</div>
In your click event handler, use the following to fluctuate or stop the correct elements:
var fluctuateClass = $(this).closest('.audiojs').attr('data-fluctuate-target');
$('.' + fluctuateClass).each(function () {
if (bPlay == 1) {
fluctuate($(this));
} else {
$(this).stop();
}
});

Categories

Resources