Target all the specific elements except the on clicked on - javascript

Inside the loop in the function thirdNavFunction, I need to target all the .third-nav classes except the one clicked on and it needs to be done without jQuery, how do I do this?
var thirdNav = document.getElementsByClassName("third-nav");
for (var i = 0; i < thirdNav.length; i++){
thirdNav[i].addEventListener("click", thirdNavFuntion);
}
function thirdNavFuntion() {
for (i = 0; i < thirdNav.length; i++) {
thirdNav[i].parentElement.className = "";
}
if (this.parentElement.className === "") {
this.parentElement.className = "nav-sub-li-active";
} else {
this.parentElement.className = "";
}
}
In the code here, I target all the .third-nav divs, but that doesn't work as intended, I need to exclude the one that is clicked. I hope it makes sense.

Convert thirdNav to array using Array.from().
Filter out the clicked element using the filter() method.
Call the forEach method to change the class name of all parent elements.
function thirdNavFuntion() {
const elements = Array.from(thirdNav).filter(el => el !== this)
elements.forEach(el => el.parentElement.className = "")
}

Related

JavaScript append multiple in for loop

Does anyone know what I'm doing wrong with the append?
function filterPosts(){
let filterValue = document.getElementById('search-filter').value.toUpperCase();
let posts = document.getElementById('posts');
let post = posts.querySelectorAll('div.post');
for (let i = 0; i < post.length; i++) {
let filterItem = post[i].getElementsByTagName('h5')[0];
if (filterItem.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
post[i].append();
} else {
post[i].remove();
}
}
}
I've tried a few different things to no avail. I'm trying to remove elements based on type and then readd them if they exist based on heading.
for (let i = 0; i < post.length; i++) {
let filterItem = post[i].getElementsByTagName('h5')[0];
if (filterItem.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
posts.appendChild(post[i]);
} else {
post[i].remove();
}
}
This ended up working for the filtering, but it doesnt bring back posts if textbox is backspaced or empty.
you could use https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild (has better browser support than append) and https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild - in your case this would looks like posts.appendChild(post[i]) and posts.removeChild(post[i])
you could also just change the visibility of the elements - this should be faster and simpler for your case.
another way would be to have an array with the all the posts data and work with it primarily. this way you can also "bring back the data".
each time the filter changes: create a new array by filtering the posts data, remove all post elements, then append only those that match the filtered data e.g.
let postsData = ["content1", "content2"];
for (let i = 0; i < post.length; i++) {
post[i].remove();
}
postsData.filter(function (post) {
return post.toUpperCase().indexOf(filterValue) > -1;
}).forEach(function () {
var postElem = document.createElement("div");
posts.appendChild(postElem);
});

how to create more than one element in the DOM with js using a for loop?

Well, the result I want to get is my div element should have the same numbers of p elements as the array.
In order to do this, I tried using a for loop but it just create one p element, so I didn't work.
Anyone have idea how to do this? (I'm just learning js).
const diccionario = () => {
var dama = ["bird:pajaro", "car:carro", "house:csa", "camis"];
document.getElementById("dic").addEventListener("click", () => {
var pes = document.createElement("p");
for(var i = 0; i < dama.length; i++){
pes.innerHTML = dama[i];
document.getElementById("cuadro").appendChild(pes);
}
})
}
You need to create the element inside the loop. If you create it outside the loop, then when you call appendChild, it will get removed from wherever it was previously in the DOM:
const diccionario = () => {
var dama = ["bird:pajaro", "car:carro", "house:csa", "camis"];
document.getElementById("dic").addEventListener("click", () => {
for(var i = 0; i < dama.length; i++){
var pes = document.createElement("p"); // <----------------
pes.innerHTML = dama[i];
document.getElementById("cuadro").appendChild(pes);
}
})
}
appendChild doesn't create a copy of the existing element - rather, it just appends the existing element.

Trying to create an array to target objects for animation

I have maps of districts named mc_1, mc_2, mc_3 etc...
I'm triggering an event when mouse hovers over them. Instead of writing code for each mc_n I thought I could use arrays. But I havent done that before.
Currently I have
var district = [];
for (var i = 0; i <= 20; ++i) {
district[i] = "mc_" + i;
}
stage.enableMouseOver(3);
this.district[i].on('mouseover', function(){
this.district[i].gotoAndPlay(2);
});
After the for loop, there is no more i variable, instead you can use forEach:
var district = [];
for (var i = 0; i <= 20; ++i) {
district[i] = document.getElementById("mc_" + i); // get the DOM elements by ID
}
stage.enableMouseOver(3);
this.district.forEach( (el) => { // loop through the DOM elements
el.on('mouseover', function(){ // add the muoseover event to the current element
el.gotoAndPlay(2);
});
});
But if you want to apply the same behavior to all of those elements, i would suggest to use CSS classes in order to identify them.

Listen to element - call function when another element is appended to it

Intro
I have a search bar I implemented into my website which searches through member cards to find matching cards. I also used Twitter's typeahead.js for this. The results are updated as you type, so I set an event listener on the input box - $('#members-search .typeahead').on("input", changeFunction); I also needed to set a click event listener on the suggestions, as I did - $('.tt-suggestion').on("click", changeFunction);
Problem
It seems like the suggestion boxes are created on the fly, so you can't set an event listener for all (or even any!) of them at the beginning. My first idea was to fire a function when an element was appended in the containing div. However, you would need an event listener for that, and I couldn't find one. Is there any way to implement this?
Code
The JavaScript:
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
var children = document.getElementById("members-list").children;
var names = [];
var whoIsWho = [];
var selected = [];
var listOfAttributeNames = ["data-member-name", "data-member-username", "data-member-nickname"];
for(var i = 0; i < children.length; i++){
for(var j = 0; j < listOfAttributeNames.length; j++){
var a;
if(a = children[i].getAttribute(listOfAttributeNames[j])){
names.push(a);
whoIsWho.push(children[i]);
}
}
}
$('#members-search .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'names',
source: substringMatcher(names)
});
var previousValue = "";
function changeFunction(e){
var v;
if($("#members-search .typeahead").val() === ""){
previousValue = "";
}
else if(((v = $('#members-search .typeahead+pre').text())) !== previousValue){
previousValue = v;
}
else if(v !== $("#members-search .typeahead").val()){
previousValue = $("#members-search .typeahead").val();
}
selected = [];
v = $('#members-search .typeahead+pre').text();
for(var i = 0; i < names.length; i++){;
if(!(new RegExp(v, "i").test(names[i])) && !(selected.includes(whoIsWho[i]))){
whoIsWho[i].style.display = "none";
}
else{
selected.push(whoIsWho[i]);
whoIsWho[i].style.display = "block";
}
}
}
$('#members-search .typeahead').on("input", changeFunction);
$('.tt-suggestion').on("click", changeFunction);
The (important) HTML:
<div id="members-search">
<input class="typeahead" type="text" placeholder="Search">
</div>
Alternate, Backup Solutions
I could copy the bloodhound script over to my code and modify where the elements are appended, but I'd rather not, as it uses this weird format of IIFE that I won't take the time to understand. Or is there another solution and this question is part of the X/Y problem?
It turns out I had the wrong approach. I just added an event listener to the current suggestions every time the input value was changed.
$('#members-search .typeahead').on("input", function(){
$('.tt-suggestion').on("click", changeFunction);
});

Is there a way to loop through all fields in a fieldset?

I would like to change the class for all the fields in a specific fieldset.
Is there a way to loop through the fields in a fieldset?
You can use getElementsByTagName.
var fieldset= document.getElementById('something');
var fieldtags= ['input', 'textarea', 'select', 'button'];
for (var tagi= fieldtags.length; tagi-->0) {
var fields= fieldset.getElementsByTagName(fieldtags[tagi]);
for (var fieldi= fields.length; fieldi-->0;) {
fields[fieldi].className= 'hello';
}
}
(If you only care about input fields, you could lose the outer tag loop.)
If you needed them in document order (rather than grouped by tag) you'd have to walk over the elements manually, which will be a pain and a bit slow. You could use fieldset.querySelectorAll('input, textarea, select, button'), but not all browsers support that yet. (In particular, IE6-7 predate it.)
Using jQuery (yay!):
$('#fieldset-id :input').each(function(index,element) {
//element is the specific field:
$(element).doSomething();
});
Note the solution below is for NON-JQUERY Implementations.
Implement a getElementsByClassName Method like this:
After you implement the code below you can then use document.getElementsByClassName("elementsInFieldSetClass") it will return an array of the elements with that class.
function initializeGetElementsByClassName ()
{
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
window.onload = function () {
initializeGetElementsByClassName();
};
Another jQuery solution here.
If you are simply adding a class(es) to the elements, it's this simple:
$('fieldset :input').addClass('newClass');
.addClass() (like many other jQuery functions) will work on all of the elements that match the selector.
Example: http://jsfiddle.net/HANSG/8/
Permanently? Find & replace in your editor of choice.
When the user clicks something? jQuery way:
$('fieldset <selector>').each(function() {
$(this).removeClass('old').addClass('new');
});

Categories