I would like to change the style, if there is a specific class on the page,
but it doesn't work. what is wrong with below code snippet?
https://jsfiddle.net/1wc0xdor/
<html>
<body>
<div id='category'>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
</body>
</html>
<script>
var elementExists = document.getElementById('category').getElementsByClassName('st_banner_row');
if (typeof(elementExists) != 'undefined' && elementExists != null)
{
$("#search_filters_wrapper").css({
margin-top: 40,
});
}
</script>
document.getElementsByClassName returns a NodeList. If the class isn't found, it will return an empty list, not null.
Check the length rather than whether it's null.
Also, margin-top is not a valid identifier, you need to quote it to use it as an object key (or you can change to camelCase marginTop:)
if (elementExists.length != 0) {
$("#search_filters_wrapper").css({
"margin-top": 40,
});
}
getElementsByClassName always returns a NodeList (think, array), so elementExists always... exists. So you really only need to check if the array isn't empty to be sure that your target class exists. Further, rather than calling getElementById first, you really only need to call getElementsByClassName, unless you're specifically looking for this class within the scope of the parent element with that id.
If you do need to search within the scope of the parent element with that id, consider using querySelectorAll with an appropriate CSS selector
const elements = document.querySelectorAll('#category .st_banner_row');
if (elements.length) {
$('#search_filters_wrapper').css({
'margin-top': 40
});
}
Also, consider setting a CSS class here rather than programmatically setting the css attribute directly, as the latter is bad practice unless it can't be helped.
Answer:
When you check if the element exists you are actually looking at an Array. To determine if the Array is not empty, and therefore, the class exists within the category element, you just need to test the length property.
If the Array length is 0 and nothing is in it, it will return false. If the Array length is greater than 0, something is in it, and it will return true.
Secondly when you utilize properties that have a hyphen( - ) you need to pass that property as a String within the object you're passing to the css method of JQuery's element wrapper.
var elementExists = document.getElementById('category')
.getElementsByClassName('st_banner_row')
.length;
if (elementExists)
{
$("#search_filters_wrapper").css({"margin-top": 40});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='category'>
<span>Below is 40px</span>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
Aside:
It's odd that you're using JQuery for this one aspect of code. It would be easier and more maintainable to use either all Vanilla JavaScript or all JQuery.
JQuery:
var elementExists = $("#category").find(".st_banner_row").length;
if (elementExists)
{
$("#search_filters_wrapper").css({"margin-top": 40});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='category'>
<span>Below is 40px</span>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
JavaScript:
var elementExists = document.getElementById('category')
.getElementsByClassName('st_banner_row')
.length;
if (elementExists)
{
document.getElementById("search_filters_wrapper").style.marginTop = "40px";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='category'>
<span>Below is 40px</span>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
Alternative Vanilla JS using querySelector:
var elementExists = document.querySelector('#category .st_banner_row');
if (elementExists)
{
document.querySelector("#search_filters_wrapper").style.marginTop = "40px";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='category'>
<span>Below is 40px</span>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
Note In this version we don't need to check the length because if category does not have a child with a class of st_banner_row the selector will return undefined.
Alternative Vanilla JavaScript Functional example:
// helper functions
const el = ( query, context = document ) => context.querySelector( query ),
elementExists = query => Boolean( el( query ) ),
ifElementExists = ( query, fn = () => undefined ) => elementExists( query ) && fn(),
elStyle = query => ( prop, value ) => el( query ).style[ prop ] = value,
changeStyle = query => ( prop, value ) => () => elStyle( query )( prop, value );
// execution
ifElementExists( "#category .st_banner_row",
changeStyle( "#search_filters_wrapper" )( "margin-top", "40px" )
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='category'>
<span>Below is 40px</span>
<div id="search_filters_wrapper">
Filter
</div>
<div class="st_banner_row" style="">
There is Banner
</div>
</div>
Related
This question already has answers here:
Easiest way to sort DOM nodes?
(9 answers)
Closed last month.
I have list and this list must be sort to a => b throught like btn (example click SORT and we have list to a -> b)
<div class = "list">
<div id = "products"> Sugar </div>
<div id = "products"> Banana </div>
<div id = "products"> Apple </div>
</div>
sorted to for button =>
<div class = "list">
<div id = "products"> Apple </div>
<div id = "products"> Banana </div>
<div id = "products"> Sugar </div>
</div>
Idk how did that with like btn :(
I tried something like that =>
// For the HTML //
<button class = 'sortBtn' onclick = 'sort()'>Sort</button>
<script>
const sort = document.quertSelector('.sortBtn');
sort.addEventListenet('click', function sort(a, b){
$parent.sort();
})
</script>
I would be grateful for help :) <3
There's a few issues in your code.
Typo: quertSelector -> querySelector
Typo: addEventListenet -> addEventListener
The repeated id in your HTML are invalid, convert them to class instead.
The function you provide to addEventListener should be anonymous in this case. Giving it a name here serves no purpose other than to waste bytes.
Avoid using inline event handlers, such as onclick, in your HTML code. It's outdated and no longer good practice. Use unobtrusive event handlers instead, such as addEventListener(), which you already use elsewhere in your code.
sort() should compare the a and b arguments and return an integer depending on which way to sort them. In this case, as you're comparing strings you can use localeCompare() on the textContent property of the elements.
After the sort() has completed you need to update the DOM to respect the new order of the elements. To do this you can call append() on the parent element, supplying the children as the argument.
Here's a working example with these issues addressed:
const sortButton = document.querySelector('.sortBtn');
const list = document.querySelector('.list');
const products = list.querySelectorAll('.products');
sortButton.addEventListener('click', () => {
const sortedElements = Array.from(products).sort((a, b) => a.textContent.localeCompare(b.textContent));
list.append(...sortedElements);
})
<div class="list">
<div class="products">Sugar</div>
<div class="products">Banana</div>
<div class="products">Apple</div>
</div>
<button type="button" class="sortBtn">Sort</button>
Convert the children of the parent element to an array. Then you can use the array sort() method to sort it, then append the children back to the parent in that order.
document.querySelector(".sortBtn").addEventListener("click", () => sortDiv(document.querySelector(".list")));
function sortDiv(parent) {
let children = [...parent.children];
children.sort((a, b) => a.innerText.localeCompare(b.innerText));
parent.innerHTML = '';
children.forEach(child => parent.appendChild(child));
}
<div class="list">
<div class="products"> Sugar </div>
<div class="products"> Banana </div>
<div class="products"> Apple </div>
</div>
<button class='sortBtn'>Sort</button>
I'm trying to convert following working function into an arrow function but I'm failing. I don't know what I'm doing wrong.
This is my starting situation:
let abc = Math.max.apply( null, $( "#wrapper .item" ).map( function () {
return parseInt( $( this ).prop( "id" ).match( /\d+/g ), 10 );
} ) );
And this is what I've tried. Maybe I misunderstood something?:
let abc = Math.max.apply( null, $( "#wrapper .item" ).map( item => parseInt( item.prop( "id" ).match( /\d+/g ), 10 ) ) );
The given error is:
issue.prop is not a function.
So I've tried a different one:
let abc = Math.max.apply( null, jQuery( "#wrapper .item" ).map( issue => parseInt( jQuery(issue).prop( "id" ).match( /\d+/g ), 10 ) ) );
Bit this gives me this error:
Cannot read property 'match' of undefined
What I'm doing wrong here?
jQuery's map() function passes Integer index and Element domElement to the callback respectively.
$(function() {
let abc = Math.max.apply(null, $('#wrapper .item').map( (index, item) => parseInt( $(item).prop('id').match( /\d+/g ), 10 ) ) );
console.log(abc);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
<div id="item1" class="item">Item 1</div>
<div id="item2" class="item">Item 2</div>
<div id="item3" class="item">Item 3</div>
</div>
Based on the looks of it, it seems that you are trying to find the largest id value (assuming they are all numeric) given a specific selector. I'll provide examples (and a breakdown of what's happening) for both native Javascript as well as jQuery.
Native Javascript Approach (will work with jQuery as well)
// Get your items
let items = [...document.querySelectorAll('#wrapper .item')];
// Parse your ids
let ids = items.map(i => parseInt(i.id.match(/\d+/g), 10));
// Get the max
let max = Math.max.apply(null, ids);
// Output it
console.log(max);
<div id='wrapper'>
<div id='item-123' class='item'>123</div>
<div id='item-456' class='item'>456</div>
<div id='item-789' class='item'>789</div>
<div id='item-101112' class='item'>101112</div>
<div id='item-131415' class='item'>131415</div>
</div>
Then you can just put it all together in a single, albeit bit, statement if you prefer:
let max = Math.max.apply(null, [...document.querySelectorAll('#wrapper .item')].map(i => parseInt(i.id.match(/\d+/g), 10)));
console.log(max);
<div id='wrapper'>
<div id='item-123' class='item'>123</div>
<div id='item-456' class='item'>456</div>
<div id='item-789' class='item'>789</div>
<div id='item-101112' class='item'>101112</div>
<div id='item-131415' class='item'>131415</div>
</div>
jQuery Specific Approach
If you are using jQuery specifically and want to take advantage of it as much as possible, then you'll just need to make a few changes:
let max = Math.max.apply(null, [...$('#wrapper .item')].map(i => parseInt($(i).prop('id').match(/\d+/g), 10)));
console.log(max);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='wrapper'>
<div id='item-123' class='item'>123</div>
<div id='item-456' class='item'>456</div>
<div id='item-789' class='item'>789</div>
<div id='item-101112' class='item'>101112</div>
<div id='item-131415' class='item'>131415</div>
</div>
The only differences being the syntaxes for:
Selection - using jQuery's $(selector) vs Javascript's querySelector(selector)
Property Access - using jQuery's .prop(id) vs Javascript's id property
jQuery .map() is not Array.prototype.map. jQuery passes first the index and then the element to the callback while Array.prototype.map passes first the element then the index.
So do:
let abc = Math.max.apply( null, $("#wrapper .item")
.map((idx, item) => parseInt($(item).prop('id').match( /\d+/g ), 10)))
;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
<div class="item" id="item1"></div>
<div class="item" id="item2"></div>
</div>
(also you replaced $(item).prop by item.prop which will not work)
Suggested changes:
Instead of jQuery's $( ) selector you can use document.querySelectorAll
Instead of jQuery's .map() you can use Array.from with its callback argument
Don't use g on the .match regular expression, as you want only one match (if ever there would be multiple matches, using g would give NaN)
You can use the unary + on the result instead of parseInt(***, 10).
You can access the id property with simple .id syntax.
Instead of apply you can use the spread syntax.
let abc = Math.max(...Array.from(
document.querySelectorAll('#wrapper .item'), item => +item.id.match(/\d+/)
));
console.log(abc);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
<div id="id439" class="item"></div>
<div id="id20" class="item"></div>
<div id="id392" class="item"></div>
</div>
I have this template:
<template id="a">
<div class="b">
<h1 class="placeholder1"></h1>
<div class="info hide">
<p class="p1"></p>
</div>
</div>
I am cloning it with:
fetch("json/countries.json").then(res => res.json()).then(list => show(list));
function show(list) {
list.forEach(function (list) {
const clone = template.cloneNode(true);
clone.querySelector(".placeholder1").textContent = list.country;
})}
I am trying to add an event listener to each cloned object, but the result is that it only adds it to the first cloned element, not the rest.
clone.querySelector(".placeholder1").addEventListener('click', fx_button1);
function fx_button1(){
document.querySelector(".info").classList.toggle("hide");
}
querySelector MDN only selects the first match found from the given selector. You need to use querySelectorAll MDN and then iterate the results.
var cloneSet = clone.querySelectorAll(".placeholder1");
for(var i = 0; i < cloneSet.length; i++){
cloneSet[i].addEventListener('click', fx_button1);
}
So, I have created an array of all instances of certain classes.
anchors = [];
$('.a-all').each(function() {
anchors.push($(this));
});
if ( viewport().width > 1366 ) {
sub_anchors = $('.a-lg');
} else if ( viewport().width > 1024 ) {
sub_anchors = $('.a-md');
} else if ( viewport().width > 768 ) {
sub_anchors = $('.a-sm');
} else {
sub_anchors = $('.a-xs');
}
sub_anchors.each(function() {
anchors.push($(this));
});
Then I set a variable 'current' and made it the object with the class '.active'.
current = $('.active');
Now, with jQuery, I want to be able to find the next and previous DOM object relative to .active that exists inside the array I have created.
The array is not in order, and will change at different widths.
Is this possible, or is there a better logic to use here?
EDIT: Adding markup for context.
<div class="website-wrapper w-d-100 h-d-100">
<div class="page-wrapper">
<section id="landing-slider" class="a-all active">
<div class="w-d-100 h-d-100">
This is the homepage landing slider... thing.
</div>
</section>
<section id="about" class="a-all">
<div class="w-d-100 h-d-50 w-sm-75 h-sm-100 dark">
About Panel 1 (75)
</div>
<div class="w-d-100 h-d-50 w-sm-25 h-sm-100">
About Panel 2 (25)
</div>
</section>
<section id="clients" class="a-all">
<div class="w-d-100 h-d-50 w-sm-50 h-sm-100">
Clients Panel 1 (50)
</div>
<div class="w-d-100 h-d-50 w-sm-50 h-sm-100 dark">
Clients Panel 2 (50)
</div>
</section>
<section id="services" class="a-md">
<section class="a-sm">
<div class="w-d-100 h-d-100 w-sm-50 h-sm-100 dark">
Services Panel 1 (50)
</div>
</section>
<section class="a-sm">
<div class="w-d-100 h-d-100 w-sm-50 h-sm-100">
Services Panel 2 (50)
</div>
</section>
</section>
<section id="lets-work" class="a-all">
<div class="w-d-100 h-d-100 dark">
Lets work together! (100)
</div>
</section>
</div>
</div>
Updated answer (now you've shown your HTML)
Since your .a-all elements are siblings (sometimes non-adjacent), you can use prevAll and nextAll, no need for the anchors array at all:
var next = $(".active")..nextAll(".a-all").first();
// or
var previous = $(".active").prevAll(".a-all").first();
If you want to find a .a-md or .a-sm, just use that as the prevAll/nextAll selector.
Original answer
Now, with jQuery, I want to be able to find the next and previous DOM object relative to .active that exists inside the array I have created.
It would be easier if you didn't make an array out of your initial jQuery object. Instead, just remember the object:
var anchors = $(".a-all");
Later, if you want to know where an element is in that array, you can use index(element):
var index = anchors.index($(".active")[0]);
Then you can get the previous like this:
var prev = index > 0 ? anchors.eq(index - 1) : $();
...or the next like this:
var next = index < anchors.length - 1 ? anchors.eq(index + 1) : $();
But if you want to use an array of jQuery instances (like the one you built) instead, you can use findIndex:
var anchors = $(".a-all").map(function() { return $(this); }).get();
// ...
var active = $(".active")[0]; // Note the [0] to get raw element
var index = anchors.findIndex(function(entry) {
return entry[0] === active;
});
// ...
var prev = index > 0 ? anchors[index - 1] : $();
// ...
var next = index < anchors.length - 1 ? anchors[index + 1] : $();
I tried it with getElementById and it worked. But now I want the same with multiple div's so I have to use classes. So I changed the method to getElementsByClassName and now it says undefined.
(The function is called when a option in a select changes. This works correctly)
HTML:
<div class="item_content">
<h3 class="filmnaam">22 jump street</h3>
</div>
<div class="item_content">
<h3 class="filmnaam">rio 2</h3>
</div>
Javascript:
function sorting(sortingway) {
alert(sortingway.value);
var titelfilms = document.getElementsByClassName("filmnaam");
var titels = titelfilms.innerHTML;
console.log(titels[0]);
}
Is there a way to do this without jQuery?
getElementsByClassName returns a collection, so loop that!
var titelfilms = document.getElementsByClassName("filmnaam");
for (var i = 0; i < titelfilms.length; i++) {
var titels = titelfilms[i].innerHTML;
console.log(titels);
}
titelfilms is a node list, you can't get the innerHTML of a node list as a whole, it contains multiple references to elements which each have their own individual property.
You could loop through and concatenate each innerHTML onto a variable, or you could map() the innerHTML of your returned elements to an array and then join() them up:
function sorting(sortingway) {
var titelfilms = document.getElementsByClassName("filmnaam");
var titels = Array.prototype.map.call(titelfilms, function (el) {
return el.innerHTML;
}).join(' ');
console.log(titels);
}
sorting();
<div class="item_content">
<h3 class="filmnaam">22 jump street</h3>
</div>
<div class="item_content">
<h3 class="filmnaam">rio 2</h3>
</div>