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>
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 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>
I am looping through elements using jQuery like this:
$(".myelement").each(function() {
$element = $(this).closest(".panel").attr("id");
console.log($element);
});
This is working correctly and I am seeing each of the elements it finds in my console log. I am now trying to get a string containing each element that looks like this:
#element1, #element2, #element3
What is the easiest way to do this? Does anybody have an example they can point me at?
You could use map() to build an array of the id then join() it, something like this:
var ids = $(".myelement").map(function() {
return '#' + $(this).closest(".panel").prop("id");
}).get().join(', ');
console.log(ids);
You could use an array to store them by adding the # in every iteration, then after the loop end join them using join() method like :
var ids = [];
$(".myelement").each(function() {
ids.push('#' + $(this).closest(".panel").attr("id"));
});
console.log(ids.join(', '));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="element1" class="panel">
<span class="myelement">My element 1</span>
</div>
<div id="element2" class="panel">
<span class="myelement">My element 2</span>
</div>
<div id="element3" class="panel">
<span class="myelement">My element 3</span>
</div>
Try with map()
The .map() method is particularly useful for getting or setting the value of a collection of elements.
As the return value is a jQuery object, which contains an array, it's very common to call .get() on the result to work with a basic array.
You can use map(), get() and join()
in the following way:
var $element = $(".myelement").map(function(){
return $(this).closest(".panel").attr("id");
}).get().join(', ');
console.log($element);
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 have the following HTML code where onclick of .spot-info I want to get the value of data-test.
<div class="spot" id="spot-1" data-test="12345">
<div class="spot-main">
<span>Test</span>
view
</div>
</div>
<div class="spot" id="spot-2" data-test="67891">
<div class="spot-main">
<span>Test</span>
view
</div>
</div>
Please see my js attempt below:
$('.spot-info').click(function ( e ) {
e.preventDefault();
var test = $(this).parent().parent().data('data-test');
console.log(test);
});
This test is logging undefined in the console. I thought this would work checking the parent of the parent of .spot-info.
Also, is there way chaining a lot of parent(0) methods together rather than using jQuery.
try attr instead. Also, try 'closest' instead of referring to the parent twice:
$('.spot-info').click(function ( e ) {
e.preventDefault();
var test = $(this).closest('.spot').attr('data-test');
console.log(test);
});
Better if you could use closest() or parents() ,so instead of :
$(this).parent().parent().data('test');
Use :
$(this).closest('.spot').data('test');
$(this).parents('.spot').data('test');
NOTE : The main problem come from .data('data-test'); When you use data() function you shouldn't add the string data- at the start.
Hopet his helps.
Working snippet
$('.spot-info').click(function ( e ) {
e.preventDefault();
var test = $(this).closest('.spot').data('test');
console.log(test);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="spot" id="spot-1" data-test="12345">
<div class="spot-main">
<span>Test</span>
view
</div>
</div>
<div class="spot" id="spot-2" data-test="67891">
<div class="spot-main">
<span>Test</span>
view
</div>
</div>
Not sure - but I think it's this:
$('.spot-info').click(function ( e ) {
e.preventDefault();
var test = $(this).parent().parent().data('test');
console.log(test);
});
You don't need the data- prefix when fetching the data with .data()