Combine $ and _ to pluck by data values? - javascript

I have a list of jquery elements with a data attribute.
Now I want to get a list of these data attributes.
As the data-attribute is some kind of an object property, I thought this might work with underscores pluck method.
Is this even possible?
See this short example:
var divs = $("div");
// now do something
// expected result: [1, 2, 3]
<script src="https://cdnjs.com/libraries/underscore.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
Solution
Based on #romeo-sierra this is the way I wrote it down (as I already have jquery objects). Underscores pluck is superfluous
var foos = $("div").map(function() {
return $(this).data("foo");
}).toArray();
console.log(foos);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>

Vanilla JS can accomplish this just fine, no jQuery nor any other library needed:
const foos = [...document.querySelectorAll('[data-foo]')]
.map(elm => elm.dataset.foo);
console.log(foos);
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>
ES5 version:
var foos = Array.prototype.map.call(document.querySelectorAll('[data-foo]'), function(elm) {
return elm.dataset.foo;
});
console.log(foos);
<div data-foo="1">a</div>
<div data-foo="2">b</div>
<div data-foo="3">c</div>
<div>x</div>

How about the following, that uses pure jQuery? (since you already are using it)
var arr = [];
$('div[data-foo]').each(function(){
arr.push($(this).data("foo")); // should return the value
});
console.log(arr);
Check this fiddle out.

You definitely have to lookup for a specific data attribute.
You can't just drain the whole page for elements data attribute and obtain a complete list like that.
But if you know what you look for...
See below
var attribute = "foormidable";
$("*").each(function(){
var match = $(this).attr("data-"+attribute);
if(typeof(match)!="undefined"){
console.log(match);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foorm="1">a</div>
<div data-foormidable="2">b</div>
<div data-foolahlayouuu="3">c</div>
<div>x</div>
OR using .data()
var attribute = "foormidable";
$("*").each(function(){
var match = $(this).data(attribute);
if(typeof(match)!="undefined"){
console.log(match);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-foorm="1">a</div>
<div data-foormidable="2">b</div>
<div data-foolahlayouuu="3">c</div>
<div>x</div>
That last one will get the value of THE OBJECT... Be it dynamic via JS code.
That is real different from the on load markup attribute value.
;)

Related

How to iterate through array of objects in template literals and use function for each of those objects?

please advise how to do it right. I have:
Array of Objects
Class method:
buildItem(obj){
let item = `<div class="${obj.name}">
<h1 class="main-title">${obj.title}<h1>
<img src="${obj.img}" alt="${obj.alt}">
</div>`
return item;
}
Another method of the same class:
buildMarkup(arrayOfObjects){
let markup = `<div class="container">
<div class="${title}" id="${id}">
...iterate here...
</div>
</div>`
}
Question: How to iterate in p.3 through arrayOfObjects and call buildItem(obj) using this template literals? Or maybe there is better way to do this? Something like this didn't work:
buildMarkup(arrayOfObjects){
let markup = `<div class="container">
<div class="${title}" id="${id}">
${arrayOfObjects.forEach(obj => {
this.buildItem(obj)
})}
</div>
</div>`
}
People using use map and join for that:
${arrayOfObjects.map(obj => this.buildItem(obj)).join("")}
join joins the entries of the array created by map with the given string in-between them. Since your item strings are divs I assume you don't want anything between them, but you could have a space or newline if you prefer. You will want to pass it a string of some kind, though, since its default is "," which you probably don't want.
If buildItem doesn't care what this is when it's called and only uses its first parameter (both of which are true for the one in your question), you can leave out the arrow function andpass buildItem directly to map:
${arrayOfObjects.map(this.buildItem).join("")}
In context:
buildMarkup(arrayOfObjects){
let markup = `<div class="container">
<div class="${title}" id="${id}">
${arrayOfObjects.map(this.buildItem).join("")}
</div>
</div>`
}
.forEach() does not return anything useful (in fact, it returns undefined). Try using .map():
buildMarkup(arrayOfObjects){
let markup = `<div class="container">
<div class="${title}" id="${id}">
${arrayOfObjects.map(obj => this.buildItem(obj)).join('\n')}
</div>
</div>`
}

How to build a URL Query Strings with jQuery from content in multiple items using class name

I am trying to build a URL that can be used in an iframe from content that's on a page. There are URL queries in that the paramaters can be passed into.
so I'm hoping to build a url like http://www.example.com/iframe.aspx?title=&itemnum=&
The other catch is there are multiple itemNum's that need to be comma separated like Item1,Item2 and also titles like Title1,Title2
Here is a n00bular start to this:
<div id="options">
<h2>Options</h2>
<div class="grid">
<div class="grid">
<div class="col">
<div class="box">
<span class="item-number">Item1</span>
<span class="title">Title1</span>
</div>
</div>
<div class="col">
<div class="box">
<span class="item-number">Item2</span>
<span class="title">Title2</span>
</div>
</div>
</div>
</div>
</div>
<script>
// Page Variables for iFrame URL
var itemNum = $('.item-number').html();
var itemTitle = $('.title').html();
// Build Params
var params = { itemnum:$itemNum, title:$itemTitle };
// Variable for full Query Strings
var mapQs = jQuery.param( params );
// Build Full URL root + query strings
$( "iframe" ).src ( 'http://www.blah.com/' + mapQs );
</script>
Just use the jQuery .param( JSON ) function, it will join the objects and url encode them.
EDIT: I've updated the code to meet the OP's needs, I've also built this into a function so that way the code can look a little cleaner by leaving the selector strings in the params object.
I've left comments to explain the code but basically it loops though all the properties in the params json object, then makes that property an array and adds all elements' inner html to that array
function makeIFrameURI(){
// Build Params
var params = {
"itemnum": '.item-number',
"title": '.title'
};
//loop through the properties of the params object
for(prop in params){
var selector = params[prop]; //get the selector
params[prop] = []; //equal blank array
$(selector).each(function(){
//add the individual element inner html into the
params[prop].push($(this).html());
});
}
//loop through the properties of the params object
for(prop in params){
//make comma separated list
var tmp = params[prop].join(",");
params[prop] = tmp;
}
var queryString = '?' + $.param(params);
var myURI = 'http://www.blah.com/' + queryString;
return myURI;
}
var iframeURI = makeIFrameURI();
//$( "iframe" ).src ( iframeURI );
$('#result').html(iframeURI);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="options">
<h2>Options</h2>
<div class="grid">
<div class="grid">
<div class="col">
<div class="box">
<span class="item-number">Item1</span>
<span class="title">Title1</span>
</div>
</div>
<div class="col">
<div class="box">
<span class="item-number">Item2</span>
<span class="title">Title2</span>
</div>
</div>
</div>
</div>
</div>
<pre id="result"></pre>
EDIT: I just wanted to mention that the jQuery function $.params() will urlencode the arguments, this is desired if you're using it as a URI. In almost all case you would be using the parameters server side e.g. in your PHP. So on the PHP page you were using them, you would retrieve the value using $_GET[] which would automatically decode the values. so on the page if you did this code in your php
echo var_dump($_GET);
it would show this value:
array(2) { ["itemnum"]=> string(11) "Item1,Item2" ["title"]=> string(13) "Title1,Title2" }

jQuery .size() function doesn´t work with a variable

At many points in my code I need to know how many .page classes are used.
To know this I use $(".page").size()
I want to save this information into a variable.
So I wrote this:
var vari = {
*more variables*
totalPageCount : $(".page").size()
};
The Problem is that vari.totalPageCount always gives 0 back.
With console.log() I get this:
console.log($(".page").size()); // Return 8
console.log(vari.totalPageCount); // Return 0
Edit:
Here is a example how i use it.
JS:
var vari = {
currentPage : 0,
pageAnimations : 0,
animationList : ".fade-in, .fade-out",
totalPageCount : $(".page").size(),
};
var footer = {
html : function(){
var html;
var date = this.date();
for(var i=0; i<vari.totalPageCount; i++){
html = '<span class="pageNumber" id="pageNumber">Folie:'+i+' • '+vari.custom["companyName"]+' • '+date+'</span>';
$("#normalPage"+i).append(html);
}
return;
}
};
HTML:
<body class="presWrapper">
<div class="pageWrapper">
<div class="page startPage" id="startPage">
<h2 class="mainTitle">Lorem</h2>
<h4 class="subTitle">Ipsum</h4>
</div>
</div>
<div class="pageWrapper">
<div class="page normalPage" id="normalPage1">
<div class="content">
<p class="fade-in">HELLO WORLD</p>
</div>
</div>
</div>
<div class="pageWrapper">
<div class="page endPage" id="endPage">
<div class="content">
<p class="fade-out">HELLO SATURN</p>
<p class="fade-out">HELLO WORLD</p>
<p class="fade-in">HELLO WORLD</p>
<p>pTag</p>
</div>
</div>
</div>
</body>
Any suggestions to solve this problem?
vari.totalPageCount Gets evaluated only when it is declared.
As a result it will only have the value of $(".page").size() when it is first run.
Unless you are waiting on document ready the children of .page have not yet been added and it has length 0.
When you later call the console and execute the selector again - you get the true count in the console message - but the stored value has already been calculated as 0 within vari.
length() and size() are equivalent functions in jquery but size has been deprecated so length is the appropriate function to call. But in either case - its likely you are just evaluating the length too early when the vari object is constructed for it to have a meaningful value.
Does the following give you the wrong value for the property:
$(document).ready(function () {
var vari = {totalPageCount: $('.page').length};
console.log(vari.totalPageCount);
});
Relevant documentation
The .size() method is deprecated as of jQuery 1.8.
Use length property instead:
var vari = {
*more variables*
totalPageCount : $(".page").length;
};
Also, make sure you are using this code at the bottom of the script or inside a document ready handler. You won't get accurate information if you try to get it before DOM has been fully setup.
This will increment count for every element with having the page class
var count = 0;
$('.page').each(function() {
count++;
});
var vari = {
totalPageCount: count
};
Working jsFiddle

querySelectorAll is not a function

I'm trying to find all oferts in the var articleFirst, but the return message in the console says that "querySelectorAll" is not a function. Why I do get that error?
This is my HTML:
<article class="first">
<div class="feature parts">
<div class="oferts">
<div class="heart icons"></div>
<h1>Build with passion</h1>
</div>
</div>
</article>
This is my JavaScript:
var articleFirst = document.querySelectorAll("article.first");
var oferts = articleFirst.querySelectorAll(".oferts");
Error:
Uncaught TypeError: articleFirst.querySelectorAll is not a function
Try do do this:
var articleFirst = document.querySelectorAll("article.first");
console.log(articleFirst)
var oferts = articleFirst[0].querySelectorAll(".oferts");
console.log(oferts)
With console you can see what is happening.
Or just do this:
document.querySelectorAll("article.first .oferts");
querySelectorAll is a method found on Element and Document nodes in the DOM.
You are trying to call it on the return value of a call to querySelectorAll which returns a Node List (which is an array like object). You would need to loop over the Node List and call querySelector all on each node in it in turn.
Alternatively, just use a descendant combinator in your initial call to it.
var oferts = document.querySelectorAll("article.first .oferts");
You need to use document.querySelector instead of document.querySelectorAll because the next query depends on a single HTMLElement but document.querySelectorAll returns a NodeList.
document.addEventListener('DOMContentLoaded', TestCtrl);
function TestCtrl() {
var firstArticle = document.querySelector('article.first');
console.log('oferts', firstArticle.querySelectorAll('.oferts'));
}
<article class="first">
<div class="feature parts">
<div class="oferts">
<div class="heart icons"></div>
<h1>Build with passion</h1>
</div>
</div>
</article>
A little verbose but you could try qselectorAll('article') then turn that nodeList into an array and pick the first index.. so something like:
let articleList = querySelectorAll('article'); // makes a NodeList of all article tags on the webpage
let article = Array.from(articleList);
article[0];

Filtering data in Javascript

I have a list of elements (DIVs) on my html page as below.
There is a list of hashtags on the same page.
I need that when the user clicks on the hashtag (e.g. #bacteria) only those DIVs that contain that hashtag are shown.
What would be the most lightweight and easy way to implement that?
<div class='entry'>
<p>#antibiotics destroy #e-coli and that's not good!!!!</p>
<!-- Hashtags: #antibiotics #eColi -->
<!-- UID: 755a2a60-972e-11e3-a464-872f2fc4dea2 -->
</div>
<div class='entry'>
<p>#bacteria can be #friendly, such as #e-coli for example</p>
<!-- Hashtags: #bacteria #friendly #eColi -->
<!-- UID: 6cc66d00-972e-11e3-a464-872f2fc4dea2 -->
</div>
<div class='entry'>
<p>#antibiotics can fight #bacteria</p>
<!-- Hashtags: #antibiotics #bacteria -->
<!-- UID: b37992c0-9686-11e3-8b2c-c97ae6645b3b -->
</div>
I know that Angular is powerful for this kind of stuff, but I'd like to use something lightweight and easy. Like maybe it's possible to do it with jQuery or something...
FYI the whole thing runs on Node.Js / Express.Js with EJS rendering.
Thank you!
UPDATE
Suppose now I have several hashtags I need to check for. Like as if contains variable is not a string but an array and i need to only show entries that contain ALL of this array's values. How would I change the code? Trying to do that, but can't manage... Thank you so much!
Use the :contains jquery selector
$(document).ready(function(){
$('.entry').hide();
$('.links').on('click','a',function(e){
var $ctx = $(e.target);
var contains = $ctx.text();
$('.entry').hide();
$('.entry:contains('+contains+')').show();
return false;
});
});
Sample : http://jsfiddle.net/LA3tD/
EDIT
you can use text with commas and then split, or use data attribute with some separator and split it afterwards for a concatenated filter selector
$(document).ready(function(){
$('.entry').hide();
$('.links').on('click','a',function(e){
var $ctx = $(e.target);
var contains = $ctx.text();
$('.entry').hide();
if(contains.indexOf(',')!=-1){
var tags = contains.split(',');
var filt = '';
$.each(tags,function(i,el){
filt += ':contains('+el+')';
});
// :contains can be concatenated multiple times f.e.: ":contains(foo):contains(bar)"
$('.entry'+filt).show();
}else{
$('.entry:contains('+contains+')').show();
};
return false;
});
});
Updated sample: http://jsfiddle.net/LA3tD/1/
Ideally, you'd incorporate your hash-tag data into the divs themselves...perhaps with the data-* attribute:
<div class='entry' data-hashtags='antibiotics bacteria'>
Then via jQuery you could loop through them hiding the ones that don't match:
var clickedHashtag = x //get the clicked on hashtag however you like
$('.entry').each(function(){
if($(this).data('hashtags').indexOf(clickedHashtag)>=0){
$(this).hide()
}
})
Fiddle: http://jsfiddle.net/Jz3gZ/
Untested:
$('.entry').each(function(item) { $(item).show($item.is('.' + hashtag)); });
You would have to add the hashtag as a class, of course:
<div class="entry antibiotics">

Categories