$('.tabLabel').click(function() {
if (!$(this).hasClass('activeTab')) {
$('.tabLabel').removeClass('activeTab');
$(this).addClass('activeTab');
$('.tab').toggleClass('activeTabContent');
}
});
var tabLabels = document.querySelectorAll('.tabLabel');
Array.from(tabLabels).forEach(function(tabLabel) {
tabLabel.addEventListener('click', function(e) {
var activeTabLabel = e.target.classList.contains("activeTab");
if (!activeTabLabel) {
tabLabel.classList.remove('activeTab');
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="tabLabel activeTab">
<p>Tab One</p>
</div>
<div class="tabLabel">
<p>Tab Two</p>
</div>
</div>
I have this click function that I'm getting a bit lost in converting to "Vanilla" Js (plain js). Any help would be appreciated. I've tried so far what I can but the lexical this is what is confusing me.
UPDATE: I'm still having troubles but I can at least console.log the elements that I want to target.
// Working Code in jQuery
$('.tabLabel').click(function() {
if (!$(this).hasClass('activeTab')) {
$('.tabLabel').removeClass('activeTab');
$(this).addClass('activeTab');
$('.tab').toggleClass('activeTabContent');
}
});
// My attempt at converting
// Does not work. returns err => Cannot read property 'remove' of undefined || Cannot read property 'toggle' of undefined
var tabLabels = document.querySelectorAll('.tabLabel');
var tab = docuement.querySelectorAll('.tab');
Array.from(tabLabels).forEach(function(tabLabel) {
tabLabel.addEventListener('click', function(e) {
if (!this.classList.contains('activeTab')) {
tabLabel.classList.remove('activeTab');
this.classList.add('activeTab');
tab.classList.toggle('activeTabContent');
}
});
});
The Problem:
Your code tabLabel.classList.remove('activeTab'); doesn't work because you define your tabLabel in a different scope. It is defined when you create your click listener, however the click listener event is in a completely different scope when it's fired, so it ends up being 'undefined'. This was the root of your problem.
The 'this' keyword can be tricky, especially in embedded callback functions because it's really easy to lose track of what scope you're currently in. I always find it is helpful to console.log(this) just to make sure it is targeting what I want.
Edit- For more information on the 'this' keyword, I suggest checking out all the resources here:
How does the "this" keyword work?
The Solution:
Below is a modified version of your vanilla JS code that toggles the activeTab class between the two on click.
var tabLabels = document.querySelectorAll('.tabLabel');
var tabs = document.querySelectorAll('.tab');
tabLabels.forEach(function(tabLabel) {
tabLabel.addEventListener('click', function(e) {
if (!this.classList.contains('activeTab')) {
tabLabels.forEach(function(tl){
tl.classList.remove('activeTab');
});
this.classList.add('activeTab');
tabs.forEach(function(tab) {
tab.classList.toggle('activeTabContent');
}
}
});
});
A couple things to note:
You had a typo in the definition of your tab variable, 'docuement' should be 'document'.
You don't need to do Array.from(tabLabels).forEach(), querySelectorAll already created an array. You'll see that I modified that.
Edit- As frederickf clarified, querySelectorAll doesn't create an array, but a NodeList. https://developer.mozilla.org/en-US/docs/Web/API/NodeList
We have to iterate over your tabLabels array again to remove the 'activeTab' class for each item before we apply it to the clicked control.
Hope that helps!
Related
I am trying to detect the CSS property changes in an element. I searched online and found MutationObserver javascript API. but in my test script it is not working as expected( it's not alerting the property name and property value).
var foo = document.getElementById("hideit");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
alert('mutation.type = ' + mutation.type);
});
});
observer.observe(foo);
observer.disconnect();
$(function() {
$("#clickhere").on("click", function() {
$("#hideit").slideToggle('fase');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<body>
<div id="clickhere">click to toggel</div>
<div id="hideit" style="display:none;">this is the content of the hide/show toggle</div>
</body>
and it shows a javascript error
TypeError: Argument 1 of MutationObserver.observe is not an object.
Thanks is advance
There're 2 problems in your code:
usage of observer.observe is incorrect. It should take 2 params: Node and MutationObserverInit. See the correct API here.
Do not call observer.disconnect(); immediately after observe. Disconnect stops observing.
Working example
Your code is being executed before the DOM is actually being loaded... For that reason, you're passing a null/undefined value to the observe method.
Wrap your code inside:
$( document ).ready(function() {
....
})
Also calling disconnect will prevent it from receiving any event. So you shouldn't call disconnect right after calling observe. And you're missing a parameter to the observe call.
Check here for a working exemple:
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#Example_usage
I've Googled my face off with no luck including searching this site. I just want a simple clear answer.
Here is my HTML:
<div id="main-navigation">
<ul>
<li>
home
</li>
</ul>
</div>
Here is the css method I'm using which I've tested and works:
// Layout 1
$('#default').click(function() {
if('true' == 'true') {
// General Values
$(hmnavUL).css({ backgroundColor: bgDefault });
});
Here is the variable I've created:
var bgSet = $(hmnavUL).css({ backgroundColor: bgDefault });
Here is what I'm trying to achieve:
// Layout 1
$('#default').click(function() {
if('true' == 'true') {
// General Values
bgSet
});
The result:
The Browser completely ignores my "bgSet" variable, but it acknowledges the style when I don't use a variable. It's not giving me any errors either with my preferred version. Anything you can tell me about my syntax would be appreciated. I'm assuming it's my syntax.
I've linked a photo example to demonstrate the my desired end product (note: I can't attach images yet).
(Default Layout, Second Layout, Remove All Styles)
Desired result: Result
The variable doesn't contain what you expect it to do. The code isn't kept in the variable, it's executed right away and the return value from the css method (which is the jQuery object) is stored in the variable.
You can't put a "macro" in a variable and have it executed by referencing the variable. The closest thing to what you are trying to do would be to put the code in a function, so that it can be executed later:
var bgSet = function() {
$(hmnavUL).css({ backgroundColor: bgDefault });
});
// Layout 1
$('#default').click(function() {
if('true' == 'true') {
// General Values
bgSet();
}
});
It looks like you want to toggle and element's css properties based on click eventHandler. You've got the right idea, but you're javascript is slightly off. Here's an example that should perform the function you want:
// Function to change the css of an element
function makeRed(elem){
elem.css({ "background-color" : "red" });
};
// Attach an event handler..
$("#clickMe").click(function(){
// Store the object as a variable
var obj = $("#foo"); // <-- The element you want to change the bg of
// Run your function.
makeRed(obj);
});
#foo{
width: 50px;
height: 50px;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div id="foo"></div><br />
<button id="clickMe">Click Me!</button>
This is really about learning how javascript selectors, functions and variables work.. Although your question is phrased in a sort-of obtuse way for StackOverflow, I appreciate that you posted your code and that you're trying to learn. :)
Can someone explain to me what i am doing wrong in this code?
http://jsfiddle.net/14njfqef/
var isLoggedIn = function(state){
if(state == true) {
$("#content-container").show();
$("#account2").show();
$("#account").hide();
}
else(state == false){
$("#content-container").hide();
$("#account2").hide();
$("#account").show();
}
}
onload=function() {
isLoggedIn(false);
}
On load i want the divs to hide but then when i click the button i want the divs to show?
Is the boolean function set out in the correct way?
Piece below tries to re-arrange piece at OP. onload not appear clearly defined , not addressed , though could be attached to an event , i.e.g., window.onload = onload . Wrapped blocks in jquery .ready() event . Removed js onclick markup from html , included at script element , or loaded from file at jquery .on("click") event . Added strict comparison operator === (an added =) to if / else if statements. Changed input type to button. Added if to else portion of composition (see link posted at comments by Felix Kling).
Try
$(function() {
var isLoggedIn = function(state){
if(state === true) {
$("#content-container").show();
$("#account2").show();
$("#account").hide();
}
else if(state === false){
$("#content-container").hide();
$("#account2").hide();
$("#account").show();
}
};
isLoggedIn(false);
$("input[type=button]").click(function() {
isLoggedIn(true)
})
});
jsfiddle http://jsfiddle.net/guest271314/14njfqef/3/
changed your html to
<input type="submit" value="Boolean" id="toggle"/>
rewrote your js as
// JQuery run at start effectivly
$(document).ready(function() {
function isLoggedIn(state) {
if(state == true) {
$("#content-container").show();
$("#account2").show();
$("#account").hide();
}
else {
$("#content-container").hide();
$("#account2").hide();
$("#account").show();
}
}
// JQuery attaching a click event using an anonymous function
// and hard coding your isLoggedIn to true, passing variables is a bit more complicated.
$('#toggle').click(function() {isLoggedIn(true)});
isLoggedIn(false);
})
Well there's a few things I am not sure if you are aware of so I feel there's some responsibility on my end to make sure they are mentioned. They are a number of syntactical errors in your post that are stopping this from working so instead of addressing them I feel its necessary to update your view on what JQuery you are using as well as your selector choice.
First I would add a class structure to all of the div's to target them all at once so you can save on some lines of code. In production it's always better to have less code for all of your visitors to download because even a little bit of code can get out of control after enough hits on a webpage. Having to serve it kills speed and so does having to process three separate jquery selections as opposed to one.
I would change the HTML to...
<body>
<div id='content-container' class='boxes'>
Content Container
</div>
<div id='account' class='boxes'>
account
</div>
<div id='account2' class='boxes'>
account2
</div>
<input id="validateButton" type="submit" value="Boolean">
</body>
This way you can simply target all divs with $(".boxes"); ... I wouldn't recommend getting into the habbit of using $("div");
Next I would change the JQuery to being more JQuery friendly code. Its not always useful to use an onload event from pure Javascript to handle JQuery driven functions in correct time to the loading of DOM objects. Therefore you should use $( document ).ready( handler ) to handle this load event properly just in case it causes you problems down the road. The more common shorthand of this ready event is a simple $(function() { }); wrapper.
The rest of the code can be re-arranged to this....
var isLoggedIn = false; //<--Instantiate to false, make global to window level scope
//Load event Corrected For JQuery
$(function() {
$(".boxes").hide(); //<--Hide on load
//Add A Proper Updated Click Event To Button
$("#validateButton").click(function() {
isLoggedIn = true; //<--Should include real functionality not hand coded to true
checkLoginAndRespond(); //<--Validate Login Status
});
});
function checkLoginAndRespond() {
//If Logged, Show
if(isLoggedIn) {
$(".boxes").show();
//Else Don't
} else { $(".boxes").hide(); }
} //end function
Lastly, the version. New versions of JQuery have not been released for some time and seem to not be in the making so its a safe bet to use their most recent versions as it has thousands of pages of help for its syntax and it's very stable. I would recommend anything in the 2.0 or higher series JQuery.
I am assuming you have JQuery library loaded. Try
if (state) {
$("#content-container").show();
$("#account2").show();
$("#account").hide();
}
else{
$("#content-container").hide();
$("#account2").hide();
$("#account").show();
}
to solve your problem.
As of right now, I am able to get this javascript function to work with one link.
However, I would like to use the function with multiple links. I have changed obj to different values and have also tried using more than one function specified with different values for each to get a working prototype, but nothing seems to work. Below is the javascript function from scratch, no changes.
<script type="text/javascript">
function gObj(obj) {
var theObj;
if(document.all){
if(typeof obj=="string") {
return document.all(obj);
}
else {
return obj.style;
}
}
if(document.getElementById) {
if(typeof obj=="string") {
return document.getElementById(obj);
}
else {
return obj.style;
}
}
return null;
}
</script>
And the link code:
<div id="axphsh">
<b>Phone:</b><a href="#" onClick="
gObj('axphsh').style.display='none';
gObj('axphhd').style.display='block';
return false;">Click for Phone Number</a></div>
<div id="axphhd" style="display:none">
<b>Phone:</b> 555-555-5555</div>
Ultimately what I want is to use the link code for multiple numbers on the same page, all hidden by default, then unhidden onClick. But like I said, this only works for one phone number link, then if there are more specified on the same page, the onClick event doesn't work at all. I am thinking it has to do with getElementById since div ids for links can be specified in that manner, but I am not completely sure.
You should learn some basic JS DOM manipulation.
Why do you even use document.all which is not a part of the standard? Use document.getElementyById or document.querySelector.
If all of your boxes with phone numbers were similar you could go with a more general function:
HTML:
<div class="phone-link-container">
Click for phone number
</div>
<div class="phone-number-container">555-555-555</div>
JS:
function showNumber (e) {
var link = e.target,
link_container = e.target.parentNode,
phone_number = link_container.nextElementSibling;
link_container.style.display = 'none';
phone_number.style.display = 'block';
}
var numbers = document.querySelectorAll('.show-phone-number');
Array.prototype.forEach.call(numbers, function (el, i) {
el.addEventListener('click', showNumber);
});
It selects all elements with a class show-phone-number and binds a function showNumber to the click event for each of them. This function hides parent of the link (which would be phone-link-container in my example) and shows next sibling of the parent (which is phone-link-container).
http://jsfiddle.net/9ZF9q/2/
In case your JavaScript code is in head you need to wrap all DOM manipulations inside window load callback:
window.addEventListener("load", function () {
var numbers = document.querySelectorAll('.show-phone-number')
Array.prototype.forEach.call(numbers, function (el, i) {
el.addEventListener('click', showNumber);
});
});
You can read more on functions used there on https://developer.mozilla.org/en-US/docs/DOM/Element.nextElementSibling
When it comes to DOM manipulation if you want to keep the compatibility with all older browsers it's easier to use jQuery library - especially if you're a beginner.
I have different container that get reloaded on different events. I have plenty of them, so I gave each container the class load.
This is how all of them look like:
<div class="load" data-href="facebook">
</div>
I also have a function, that is triggered by various actions:
function get_timing(time)
{
$(".load").load("myfolder/mod_"+$(this).attr("data-href")+".php?action="+time, function() {
alert('Here I could use this:' + $(this).attr("data-href"));
}
}
I know that I cannot use this in the example above, I could only use it in the callback. My question is: How can I use attributes of the object to define the path of the load function.
This is how it could work:
function get_timing(time)
{
$(".load").fadeIn(10, function()
{
$(this).load("myfolder/mod_"+$(this).attr("data-href")+".php?action="+time, function() {
alert('loaded');
}
}
}
Is there a way to do this without the asynchronus function (in this case .fadIn) around)
Hope I could explain my problem - thank you in advance!
If you want to go along with classes you can reference them via an index:
var element = $(".load").get(0);
console.log($(element).attr("data-href"));
Note that you have to re-jQueryfy element via $(element) in order to access attr()
If you want to read out all elements with a given class I recommend $.each()
//$.each($(".load"), function(index, value){
$(".load").each(function(index, value){
console.log( $(value).attr("data-href"));
});
Try to give your container an id:
<div class="load" data-href="facebook" id="facebookcontainer">
</div>
Then instead of using this, you can use $("#facebookcontainer") in your javascript.