Clicking Links to Change Displayed Content - javascript

General Layout
I'm working on a tool for work to help streamline some things, but I've never been good at best practices and wanted to make sure I did this right.
I want the site to load with only column A visible. Click a link in column A, column B is generated with proper links. Click a link in column B, column C is generated. Click a different link in column A, column B is replaced with the new proper links (and if column C was already visible, get rid of it completely).
My current idea is having a clever div structure so I can add or remove a "hidden" class using jQuery on all children. Each column is a floated div with styled links. I'm not sure if the cleanest way to do this would just be having a parent for each potential section, then labeling each possibility with a class for a selector. That way I could use the jQuery children().addClass("Hidden") on the parent container for each section that I've defined to come after the one the link was clicked in.
I'm not sure I have access at work to a MySQL database, and I can't put company information on my personal sandbox website, so I think I'm stuck with javascript for the most part. Can anyone guide me in the right direction?
The code below is incomplete, just wanted to give an idea of what I was already thinking. i.e.
//This would be part of function modemBrands when Arris is passed, currently using if else statements for each option.
$('.ModemMods').children().addClass("Hidden");
$(".Arris").removeClass("Hidden");
~
<div class="NavCon">
<nav>
<!-- Brand options -->
<div class="LinkCon">
Arris
Motorola
SMC
Ubee
</div>
<div class="ModemMods">
<div class="LinkCon Arris">
DG860A
DG1670
DG860A
DG1670
</div>
<div class="LinkCon Motorola Hidden">
DG860A
DG1670
DG860A
DG1670
</div>
<div class="LinkCon SMC Hidden">
DG860A
DG1670
</div>
<div class="LinkCon Ubee Hidden">
DG860A
DG1670
</div>
</div>
<div class="ModemRegion">
</div>
</nav>
</div>
Am I on the right track? Should I just have the function tied to links in column A add the Hidden class to all of the parent containers for columns B or C each time I click it? Or is there a more elegant way to do this?

You should not use onclick. Use addEventListener (vanilla JS) or .click() (jQuery).
Why? Separation of concerns. Your HTML is for content and layout. Your CSS is for styling. Your JS is for scripting.
MySQL is not a programming language. It is a database system. You can either hard code in the values, store it in a JSON file somewhere, or use a database and a server side scripting language to load it from the DB.
Try separating data from your layout. For example:
.
var motorola = {name: "Motorola", modems: ["ABC123", "BCD123", "XYZ123"]};
var cisco = {name: "Cisco", modems: ["MEOW123", "LOL123", "STACKOVERFLOW"]};
var vendors = [motorola, cisco];
for (var i in vendors) {
$link = $("<a>").text(vendors[i].name);
$link.attr("data-name", i);
$link.click(vendorClickHandler);
}
function vendorClickHandler(e) {
var vendorName = $(this).attr("data-name");
var vendor = vendors.filter(function(t) { return t.name === vendorName })[0]; // basically, search vendors for an elem with this name
for (var i in vendor.modems) {
// ...
}
}
This would be a good jQuery-level architecture. The "best" architecture? A templating library (but that's not necessary at this level).

Related

How can I extract the text next to an image with Google Tag Manager?

Here's the challenge:
We have an image and text that describes it all nested in the same div. When somebody clicks on that image, we want Google Tag Manager to return that text.
Basically, we need to:
Go up 3 parent nodes
Go down to the child node with the class "right-section"
Go down to the child node with the class "is-title"
Go down to the child node with the tag "a"
Extract the text
Using my crude, self-taught Javascript knowledge, I came up with this monstrosity of a function:
function(){
return el.parentNode.parentNode.parentNode.getElementsByClassName("right-section")[0].getElementsByClassName("is-title")[0].getElementsByTagName("a")[0].innerText;
}
... which does not work at all.
Any suggestions?
this is an example markup basically the idea is use closest function to go up to dom tree and then use 'querySelector' with that result to go down to any element inside it
const img = document.querySelector(".item_image")
img.onclick = e=>{
const root = e.target.closest(".card") // goind back to root element
const text = root.querySelector(".text") // going down to text element
console.log(text.innerText)
}
<div class="card" style="width:400px;">
<div class="sections">
<img class="item_image" style="width:200px;" src="https://2.img-dpreview.com/files/p/E~C1000x0S4000x4000T1200x1200~articles/3925134721/0266554465.jpeg" alt="">
</div>
<div class="another-seci">
<div class="text">
Despite its modest MSRP, Fujifilm's entry-level X-A3 has dual control dials, a tilting touchscreen, and the same 24MP sensor from the company's flagship models - but with a traditional Bayer color filter array instead of X-Trans. We're pushing through our full
</div>
</div>
</div>
ok, Here is an example of what you need to do. If you need an exact answer that would work by just copy pasting it, show the block of HTML exactly how Amir did. I used Amir's HTML example to do the trick. Also, if you see that it takes the same text when you click on different images, include in your html snippet the code from other images, so that we could see how they relate to the parents and could refine the selectors.
Here's your CJS code:
function(){
return {{Click Element}}.parentElement.parentElement.querySelector(".text").innerText
}
There's completely no need to hop from node to node once you got to the bottom. From the bottom parentElement, just do the query selector once and you're in good hands.
You could also use .closest, but it seems like its complexity is way over just a few parentElements. I know it's insignificant, but hey.
Here is how I debug it right on this page (in Amir's answer):
document.querySelectorAll('.item_image').forEach(item => {
item.addEventListener('click', event => {
const root = event.target.closest(".card") // goind back to root element
const text = root.querySelector(".text") // going down to text element
console.log(text.innerText)
})
})
<div class="card" style="width:400px;">
<div class="sections">
<img class="item_image" style="width:200px;" src="https://2.img-dpreview.com/files/p/E~C1000x0S4000x4000T1200x1200~articles/3925134721/0266554465.jpeg" alt="">
</div>
<div class="another-seci">
<div class="text">
Despite its modest MSRP, Fujifilm's entry-level X-A3 has dual control dials, a tilting touchscreen, and the same 24MP sensor from the company's flagship models - but with a traditional Bayer color filter array instead of X-Trans. We're pushing through our full
</div>
</div>
</div>
<div class="card" style="width:400px;">
<div class="sections">
<img class="item_image" style="width:200px;" src="https://2.img-dpreview.com/files/p/E~C1000x0S4000x4000T1200x1200~articles/3925134721/0266554465.jpeg" alt="">
</div>
<div class="another-section">
<div class="text">
BlaDespite its modest MSRP, Fujifilm's entry-level X-A3 has dual control dials, a tilting touchscreen, and the same 24MP sensor from the company's flagship models - but with a traditional Bayer color filter array instead of X-Trans. We're pushing through our full
</div>
</div>
</div>
Here's what ultimately worked, for anyone Googling this:
function (){
el = {{Click Element}};
var item = el.parentElement.parentElement.nextElementSibling.getElementsByTagName('a')[0].innerText;
return item;
}

section id not being recognised within jquery scroll function

I have a parallax scrolling website which works via section ID's. I have animations on each of the sections but only want them to activate when the section is in the viewport. I currently have the following, which doesn't seem to be working. I'm fairly new to jquery/javascript so any help would be appreciated!
function paintLine(){
$('#3-Backup-3').lazylinepainter({
"svgData": svgData,
'ease': 'easeInOutQuad',
'strokeCap': 'square'
}).lazylinepainter('paint');
}
var element_position = $('#backup-section-3').offset().top;
$(window).scroll(function() {
var y_scroll_pos = window.pageYOffset;
var scroll_pos_test = element_position;
if(_scroll_pos > scroll_pos_test) {
paintLine();
}
});
<!-- Backup 3 -->
<div data-anchor="backup-section-3" class="section backup-section-3">
<div class="float-left">
<div id="backup-nav">
<p onclick="openSideNavGreen()" class="nav-section-title">Backup</p>
</div>
<div>
<p class="backup-text-title">Methods</p>
<p class="backup-text">No surprises here then: tape as a primary backup method remains at an all-time low of 3%. This is the first year it hasn’t fallen – possibly indicative of how stubborn some legacy systems (often populated with static compliance data) can be. I wouldn’t be surprised to see similar figures next year.<br><br>We did see a drop in the prevalence of combined disk/tape solutions, with a new option, External Hard Drive/USB, seeming the preferred choice instead.</p>
</div>
</div>
<div class="float-right">
<div id="3-Backup-3"></div>
</div>
</div>
$('#backup-section-3').offset().top; refers to an element with an ID of backup-section-3 which you don't seem to have in your HTML markup. Try giving the element that you're referring to an ID of backup-section-3 and see if that resolves your issue.
id needs the start with alpha character. put any alpha char in front of the 3 in your javascript and html and it will work.

Is there a way to add an element to the same height as another selected element dynamically?

I am new to front-end development. I was trying to code an annotation tool. A sample screen is shown on the image below. After the user select a sentence, an annotation box appears on the right side bar at the same horizontal position as the highlighted sentence. Any ideas about how I can achieve that effect?
Here is my html structure. I used the framework of Zurb Foundation:
<section id="main">
<div class="row">
<div class="small-8 large-8 columns"id="rawdata">
<p> <span class="sentence">2:22 So, last time I was here, I don't know if I told you this, but, um, we kind of did a "I like, I wish" activity on paper, about things that you like about studio, and things that you wish would change.</span><span class="sentence"> Um, do you want to share any of those thoughts now, so maybe we can talk about them? [name], I have yours if you want to look at it again.</span></p>
<p><span class="sentence">2:47 I forgot to add something.</span></p>
<p><span class="sentence">2:54 Well, I don't know, in terms of what I dislike about studio.</span></p>
<p><span class="sentence">2:57 So, some people wrote in theirs that, um, they dislike how cluttered it gets.</span></p>
<p><span class="sentence">5:09 I don't get bothered.</span>< <span class="sentence">I like the draftiness, I'm a little...</span><span class="sentence"> I'm one of the ones that opens the windows, and like—</span></p>
</div>
<div class="small-4 large-4 columns" id="annotations"><p></p>
</div>
</div>
</section>
JS for selecting sentence and adding annotations:
<script>
$('.sentence').click(function() {
$(this).toggleClass('sentenceStyle');
var y = $(this).offset().top;
var para = document.createElement("p");
$("#annotations").append(para);
para.innerHTML="this is an annotation";
para.css("position",'absolute');
para.style.top = y;
});
</script>
And here it is the fiddle: http://jsfiddle.net/yujuns/HDe6v/3/
There are some things that you want to change in your code.
First what you want is to get the offset of the selection. That can only happen if you put an html tag around the selection and then get its offset. You can then place an absolute positioned message box by setting its left and top offset to the offset you got from html element.
In the following fiddle, I have shown a basic implementation to give you the basic idea. Hope it helps.
Fiddle
EDIT:
Try this fiddle update.(In response to author's question). I have added comments to lines of code that I added to js. I also added position: relative to css for annotations
Updated Fiddle

How do I target an <a> inside a <div>?

I have this code : http://jsfiddle.net/Qchmqs/BSKrG/
<div class="step"><-- this is darned wrong
<div id="step2"><a>Darn</a></div>
<div id="step2"><a>Darn</a></div>
<div id="step2"><a>Darn</a></div>
</div>
<div class="step"><-- this works fine
<div id="step2"><a>Darn</a>
<a>Darn</a>
<a>Darn</a></div>
</div>
The first block is three links inside three separate divs inside a surrounding div
The bottom block has the links inside one parent div
I am trying to change the background of an active link, but it won't turn off in the upper block.
The script works well with the bottom links but not working as expected with the upper ones
PS : The active class should be toggled only from the Links i have a lot of other scripts in the page that uses the .active links from this list.
For starters, do what JamesJohnson said and remove the multiple IDs. They can only cause you problems down the road.
In the upper links, the a tags aren't siblings because you put each one in its own div. So you need to do this to remove classes from the other as:
$(this).parent().siblings('div').children('a').removeClass('active');
http://jsfiddle.net/mblase75/BSKrG/1/
Unfortunately, that breaks the functionality on the lower links. You can achieve success in both places by adding andSelf to the parent siblings:
$(this).parent().siblings('div').andSelf().children('a').removeClass('active');
http://jsfiddle.net/mblase75/BSKrG/2/
It's not working on the upper ones because you're assigning the same id to the divs. You should probably use the class attribute instead:
<div class="step2"><a>Damn</a></div>
<div class="step2"><a>Damn</a></div>
<div class="step2"><a>Damn</a></div>
After making the above changes, you should be able to do this:
$(".step2 a").text("Hello World!");
maybe this:
<div class="step">
<div id="step2"><a>Damn</a>
<a>Damn</a>
<a>Damn</a></div>
</div>
<div class="step">
<div id="step2"><a>Damn</a>
<a>Damn</a>
<a>Damn</a></div>
</div>
Using radio inputs you can create this effect without any JS at all, which degrades gracefully from its intended appearance (a red backgrounded "damn") to damn with radios next to it (sending the same information).
ironically, this example at JSfiddle: http://jsfiddle.net/YvQdj/
My memory is a bit fuzzy, but I'm pretty sure this doesn't work in older versions of IE without some finagling.

jQuery Toggle modification

I am using the below javascript (jQuery) to toggle open two DIVs. The DIVs open fine and open one at a time, which is what I am after. However, I also want the DIVs to close when they are clicked a second time, which doesn't happen despite my best efforts!
Javascript:
$(document).ready(function() {
$('.info_tab').click( function() {
var currentID = $(this).next().attr("id");
$('.toggle_info[id!=currentID]').hide(); /* the intention here is to hide anything that is not the current toggling DIV so as to close them as a new one is opened. I thought this would leave the currently selected DIV uninterrupted to toggle closed (below), but it doesn't */
$(this).next().toggle();
return false;
});
});
HTML:
<div class="info_tab">
<h1>Person One</h1><br />
<p>click for less info</p>
</div>
<div id="person_one_info" class="toggle_info">
<p>More information about Philip Grover</p>
</div>
<div class="info_tab">
<h1>Person Two</h1><br />
<p>click for less info</p>
</div>
<div id="person_two_info class="toggle_info">
<p>More information about Roy Lewis</p>
</div>
If any more info is needed, just ask and I'll be happy to edit the question.
Cheers,
Rich
you have the concept down, but not using the "currentID" correctly. You need to remember it's a variable, and can't be in another string if you want it evaluated.
With that said, try this:
$('.toggle_info[id!='+currentID+']').hide();
This makes the variable get evaluated in the selector, then passes it off to jQuery to find.
it looks like you're going to an accordian effect though. And jQuery UI has just such a control that you can use (if you're interested). if you're going for experience, then carry on. ;-)

Categories