for loop vs forEach in JavaScript -- example from book - javascript

I am currently learning JavaScript using O'Reilly's "Learning Web Application Development". In the example, we are constructing a website using HTML and CSS, which includes 3 tabs which should be able to be selected and become the "active" tab. The books claims that the following two ways of writing the tab code are equivalent:
1)
var main = function() {
"use strict";
var tabNumber;
for (tabNumber=1;tabNumber<=3;tabNumber++) {
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
$(tabSelector).on("click",function() {
$(".tabs span").removeClass("active");
$(tabSelector).addClass("active");
$("main .content").empty();
return false;
});
}
}
$(document).ready(main);
2)
var main = function() {
"use strict";
$(".tabs a span").toArray().forEach(function(element) {
$(element).on("click", function() {
console.print("this element: " + element);
$(".tabs span").removeClass("active");
$(element).addClass("active");
$("main .content").empty();
return false;
});
});
}
$(document).ready(main);
However, they do not output the same result. The version using forEach works correctly, so that when I click one of the tabs the attention moves to that tab and it becomes highlighted. However, in the version using a for loop, whenever I click any tab, the attention always moves to the last tab. To confirm what is happening, I printed out the name of the element inside the event listener with both methods, using 3 tabs total. And using the for loop, no matter which tab I click I am getting a response of
"this element: .tabs a:nth-child(3) span"
Could someone please help me explain why this is happening? Why is the output different using for or forEach? And why, using for, is it always passing the last element of tabs to the event listener?

Looks like there's a problem here:
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
$tabSelector.on("click",function(){
You've created a variable that doesn't have the $ at the beginning, then attached the event to a variable (not sure what it would refer to) with a $ at the beginning.
It should be changed to this, I believe:
$(tabSelector).on("click",function(){

In the for loop solution, you are setting tabSelector multiple times like so:
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
This selector is, in the end, going to be set to the last tabNumber, which is always going to be called when you make a reference to it:
$(tabSelector).addClass("active");
To avoid that, replace it by this, which will be different for each of them:
$(this).addClass("active");
JS Fiddle Demo

Related

Javascript Loads but does not work in Magento 1.9

Just getting into Magento. I have added a menu and need it to work as it does in the Pen
http://s.codepen.io/WallyNally/debug/dWqGEp/yoMZEQWedYdk
Magento is loading the JS and CSS files as confirmed in sourcecode. The style displays properly. As a double check, in the JS file I have included var MyVariable = "Exists!";. Going to the console in the live dev page, I can type 'MyVariable' and its value is properly returned. There are no errors thrown or displayed.
However, the hover event does not exist. Namely the two mouseenter event triggers.
Here is a working excerpt of the desired javascript:
jQuery("#categories a").mouseenter(function() {
let subcateg = "sub-" + jQuery(this).attr("id");
let active = jQuery(".subcateg-active");
let current = jQuery("#" + subcateg);
if (active.length == 1) {
jQuery(active).toggleClass("subcateg-active").fadeOut(150, function(){
jQuery(current).toggleClass("subcateg-active").fadeIn(180);
});
} else if (active.length == 0){
jQuery(current).toggleClass("subcateg-active").fadeIn(180);
}
if (active.length > 1) {
jQuery(active).css("display", "none").removeClass("option-active");
jQuery(current).toggleClass("subcateg-active").fadeIn(120);
}
});
var MyVariable = "Exists!";
Here is the dev site (link will not be permanent, so an image is attached as well):
http://atlas3.netsos.com/
Any Magento savants know what went awry?
Now I think that there can be 2 reasons:
First: I don't see any category items, so, do you sure that ""#categories a" selector works (element with ID categories holds some link tags ?)?
Second: JS script, where you trying to hung events on some html elements, should be executed after element on which this event must be hunged will be added to document. So, try to execute your script after document loaded.
Example:
jQuery( document ).ready(function() {
// Here your JS code
});

Refer to ID (as selector) that is already inside HTML link tags

I have a link that is generated by a core module (meaning I can't modify the code) as such:
<a id="my-unique-id-1" class="my-link-class" href="/switch off">Switch off</a>
Problem is, the ID and class are within the <a> tag and I do not have any useable elements wrapped around the link that I can use.
When clicked, it goes and do what it has to do server side (see code following), and then returns this:
<a id="my-unique-id-1" class="my-link-class it-is-off" href="/switch on">Switch on</a>
I want to replace or amend the complete first link.
First the jQuery script:
$(".my-link-class").click(function() {
var current_id = $(this).attr('id');
var link = $(this).attr('href');
$.ajax({url: link, success: function (result) {
//All works fine up to here. The changes are made in server side and returns the new link as the result.
//Following is my problem:
if(result){
$(current_id).replaceWith(result); //the selector is wrong, I know.
}
}
}
My problem is that the id (current_id) is already within a <a> tag.
How can I refer to the selector in the tag.
I tried:
$(current_id).replaceWith(result); //nothing happens
$('#' + current_id).replaceWith(result);
$('a#' + current_id).replaceWith(result);
But I get with the last two TypeError: Argument 1 of Node.appendChild does not implement interface Node.
(I know I can do other things than replaceWith such as changing text and href in link, but the problem here is to find the selector first).
You can just use $(this).replaceWith():
$(document).on('click', '.my-link-class', function() {
var html = '<a id="my-unique-id-1" class="my-link-class it-is-off" href="/switch on">Switch on</a>';
$(this).replaceWith(html);
return false;
});
.it-is-off {
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a id="my-unique-id-1" class="my-link-class" href="/switch off">Switch off</a>
I think there are two things happening here.
You are trying to use an ID to replace an element, when it would be easier to just keep a reference to the DOM element you want to replace rather than finding it twice.
You are binding an event to an anchor tag that you are then trying to replace. Once you replace it, the event will go away. The way to avoid this issue is bind your event to something that won't be changing. That can be the element right above the one you are going to replace, or it can be a much higher up element like the body element.
Here's a possible solution that fixes both problems. I've written a function called simulatedAjax to give an idea of what I think you're saying the backend code is doing. It follows the same idea as the jQuery $.get using the configurationObject, callback(result) signature.
function simulatedAjax(config, done){
var onOffText = (config.url === "on" ? "off" : "on");
done('Switch '+ onOffText +'');
}
And now your client code
$(function(){
// Bind the click to the body element, but with a delegate to your link class .custom-link
$('body').on('click', '.custom-link', function(e){
// Store a reference to the A tag, name is irrelevant but self is easy to understand
var self = this;
// Keep the page from actually navigating to the href
e.preventDefault();
//Replace with real jQuery $.get or $.ajax with configuration
simulatedAjax({
url: $(this).attr('href')
}, function(resultHTML){
// Since we stored a reference to the original in the self variable, we can just replace it here. Note that if we tried to use `this` here, it wouldn't refer to the right `this`
$(self).replaceWith(resultHTML);
});
});
});
You can see this code sample working in this JSFiddle http://jsfiddle.net/x83vfmuw/
Hope this helps!

Adding a class while looping to an array

I have a list composed by some divs, all of them have a info link with the class .lnkInfo. When clicked it should trigger a function that adds the class show to another div (like some sort of PopUp) so it is visible and when clicked again it should hide it.
I am quite certain this must be a very basic thing and most likely I will get some scoffs...but hey! Once I have this down that's one thing less I will ever have to ask again. Anyway I am starting to leave the safety of html and css to start learning JS, PHP and the like and I came to a bit of a problem.
When testing it before it was working, that was until I added another div, it only worked with the first one, reading a bit and with some suggestion I realized it must be something related to a array, the problem is that I am not quite certain of the syntax for accomplishing what I am visualizing.
Any help would be deeply appreciated.
This is my JS code and below I will attack a Fiddle of how the html looks just in case.
var infoLab = document.getElementsByClassName('lnkInfo'),
closeInfo = document.getElementById('btnCerrar');
infoLab.addEventListener('click', function () {
for (var i = 0 ; i < infoLab.length; i++) {
var links = infoLab[i];
displayPopUp('popUpCorrecto1', 'infoLab[i]');
};
});
function displayPopUp(pIdDiv, infoLab[i]){
var display = document.getElementById(pIdDiv),
for (var i = 0 ; i < infoLab.length; i++) {
infoLab[i]
newClass ='';
newClass = display.className.replace('hide','');
display.className = newClass + ' show';
};
}
JSFiddle.
Thanks a lot in advance and sorry for any facepalms!
EDIT:
This a jQuery function (in another file) that I need to call using the link because it fetches the data that will be inside the div, thus why I wanted to just add a hide/show.
$(".lnkInfo").click(function() {
var id = $('#txtId').val();
var request = $.ajax({
url: "includes/functionsLabs.php",
type: "post",
data: {
'call': 'displayInfoLabs',
'pId':id},
dataType: 'html',
success: function(response){
$('#info').html(response);
}
});
});
EDIT 2:
To a future reader of this question,
If you managed to find this answer throughout space and time, know that this is how the solution ended being, may it help you in your quest to stop being a noob.
SOLUTION
Here is a rudimentary working example of how to make a popup appear after clicking on a specific element given your current code. Note that I added an id to your link element.
// Select the element.
var infoLink1 = document.getElementById('infoLink1');
// Add an event listener to that element.
infoLink1.addEventListener('click', function () {
displayPopUp('popUpCorrecto1');
});
// Display a the popup by removing it's default "hide"
// class and adding a "show" class.
function displayPopUp(pIdDiv) {
var display = document.getElementById(pIdDiv);
var newClass = display.className.replace('hide', '');
display.className = newClass + ' show';
}
Fiddle.
There are various ways to generalize this to work for all links/popups. You could add a data-link-number=1, data-link-number=2, etc to each link element (more on data-). Select an element containing all of your links. Bind to that element an event listener that, when clicked, detects the link element that was clicked (see event delegation / "bubbling"). You can determine which link was clicked based on the value of your data-link-number attribute. Then show the appropriate popup.
You may also want to use jQuery for this. Changing an element's class by setting it's className property makes for brittle DOM code. There is an addClass and a removeClass method available. jQuery's events also work cross-browser; element.addEventListener() will not work in IE8 which still has a significant market share.

casperjs click not selector but variable

Is it possible to click page element in casper js without passing selector? I mean I can't do that:
casperjs.thenClick('#test');
But I have
var testV = document.querySelector('#test');
And I want do something like this:
casperjs.thenClick(testV);
For now it doesn't work
You are using thenClick improperly. Make sure the then.click is not contained within a casper.evaluate block and note there is not the js on the end of casper. It should be implemented as:
casper.thenClick('a', function() {
this.echo("I clicked on first link found, the page is now loaded.");
});
If you want to just perform a regular click on selector you can do the following:
casper.then(function() {
// Click on 1st result link
this.click('h3.r a');
});
If you would like to use javascript, make sure you are within a casper.evaluate statement. You can use the following:
casper.then(function() {
casper.evaluate(function() {
var testV = document.getElementById("test");
testV.click();
});
});

.removeClass not functioning within .replaceWith

I'm trying to make a button that will hide a specific -- and then replace it with another hidden . However, when I test the code, everything fires correctly except for the .removeClass which contains the "display: none."
Here is the code:
<script type="text/javascript">
$(document).ready(function(){
var webform = document.getElementById('block-webform-client-block-18');
var unmarriedbutton = document.getElementById('unmarried');
var buyingblock = document.getElementById('block-block-10');
$(unmarriedbutton).click(function () {
$(buyingblock).fadeOut('slow', function() {
$(this).replaceWith(function () {
$(webform).removeClass('hiddenbox')
});
});
});
});
</script>
The CSS on 'hiddenbox' is nothing more than "display: none.'
There is a with the id of unmarried, which when clicked fades out a div and replaces it with a hidden div that removes the class to reveal it. However, the last part doesn't fire -- everything else does and functions properly. When I look at in the console too, it shows no errors.
Can someone please tell me where the error is? Thanks!
Edit: I may be using the wrong function to replace the div with, so here's the site: http://drjohncurtis.com/happily-un-married. If you click the "download the book" button, the the div disappears and is replaced correctly with the div#block-webform-client-block-18. However, it remains hidden.
The function you pass to replaceWith has to return the content you want to replace it with. You have to actually return the content.
I don't know exactly what you're trying to accomplish, but you could use this if the goal is to replace it with the webform object:
$(this).replaceWith(function () {
return($(webform).removeClass('hiddenbox'));
});
NB, use jquery !
var webform = $('#block-webform-client-block-18');
var unmarriedbutton = $('#unmarried');
var buyingblock =$('#block-block-10');
unmarriedbutton.click(function () {
buyingblock.fadeOut('slow', function() {
$(this).replaceWith( webform.removeClass('hiddenbox'));
});
});
Was too fast, i believe it's the way you select your object (getelementbyid) then you create a jquery object from it... -> use jquery API

Categories