I recently found a code snippet that I would really like to understand:
var buttons = $('#fruit,#vegetable,#meat').click(function() {
$(this).toggleClass('active');
var classes = buttons.filter('.active').map(function() {
return this.id;
}).get().join(',.');
$('div.fruit,div.vegetable,div.meat').hide().
filter('.' + (classes || 'none')).show();
});
The HTML code :
<div style="float:right; padding:25px;">
<button id="fruit" class="active"><span>fruit</span></button>
<button id="vegetable" class="active">vegetable</button>
<button id="meat" class="active">meat</button>
</div>
<div>
<p>Trying to use buttons as an "or" case rather than "and." When choosing fuit or vegetable, I want to see tomato as part of each list, <em>not just</em> when both are selected.</p>
<div class="fruit">
<p>apple</p>
</div>
<div class="vegetable">
<p>pumpkin</p>
</div>
<div class="vegetable">
<p>okra</p>
</div>
<div class="fruit">
<p>orange</p>
</div>
<div class="meat">
<p>beef</p>
</div>
<div class="fruit vegetable">
<p>tomato</p>
</div>
</div>
The fiddle is here.
I do understand how all the methods work in jQuery like toggleclass, filter and map, I also understand how join works in JS, but in this particular example, I am not able to figure out how get() is working or rather what is it's usage in the script is.
I went through the jQuery documentation for get() and I came across this method for the first time; to me, it seems it's very much similar to eq() in jQuery, but I am still not able to figure out why exactly get is being used in my example.
Can somebody explain this to me ?
.get is used here, because .map returns a jquery style object which contains some functions and information about the contained data. But in this scenario only the values stored within the object (the class names of the active buttons) are wanted. .get is used to get an array containing the raw values and with .join(",.") the values from the array get concatenated to a string. This string then get's used to show all div's that should be active according to the selected buttons.
Related
I have a page* with several .article divs with the following markup:
<div class="article">
<div class="featured-img">
<a href="https://www.johornow.com/english/things-to-do-at-kota-tinggi/" style="background: none;">
</a>
</div>
<div class="featured-info">
<h3 class="article-title">
Fun Things to Do and Amazing Places to Visit at Kota Tinggi
</h3>
</div>
</div>
Now I want to get all the anchor links:
$('.article').each( e => $(this).find('article-title').find('a').attr("href") )
Surprisingly I failed to do so, I got DOM node. What's wrong with my code?!
*https://www.johornow.com/english/travel/
There are couple of errors in your code:
1) JQuery is all about chaining, that's why functions like each return the initial set and not the elements you return in the function (or a collection of your return values?). What you want/need here is .map.
2) your find was missing the . for addressing a class. Also, you can write it in a single statement find(".article-title a").
3) Fat arrow functions don't establish their own context, thus $(this) won't work. Instead you have to use the "old-school" way of writing functions, to actually have this refer to the single elements.
The following jquery solution
$('.article .article-title a').map( function(){return console.log($(this).attr("href"))} )
creates an array with all the link hrefs.
So does the following vanilla JS (which I actually always prefer):
[].map.call(document.querySelectorAll('.article .article-title a'), e=>e.href )
There you have your fancy fat arrow again - also, it's shorter, (possibly faster) and does not rely on third-party;)
You can get all the links in an array
var m =[];
$('.article').each(function(e,v){
m.push($(this).find('h3 > a').attr("href"))
})
console.log(m)
I have a questionnaire page and some div have a data-answered attribute added to them like this:
<div class="question" data-answered="False">
... rest of the html
</div>
now I have several of those and at some point, through js (you can read JQuery) I do:
myDiv.data("answered", "True")
please assume I have a way to get the actual div that's not the issue here. Now I can see that the actual data-answered attribute is set to "True" when I check the js locals, the DOM explorer however shows nothing. The issue comes however when I need the answered questions count like this:
var answeredCount = $('[data-answered=True]').length
then no matter how many changes I've made, I always the same elements/results/count as when the page first loaded. However if I do the following:
var answeredCount = $('[data-answered]')
.filter(function () { return $(this).data('answered') == 'True' })
.length
then I get the results I expected. I will be adding an image with some data on an actual browser as prove to I have just said to support my claim:
Note: This behavior seems to occur on Opera and Edge, since I tried it on Chrome and it worked as I expected, haven't tried Firefox.
Is this the intended behavior?
Have I misunderstood something about how JQuery works with the DOM and it changes?
Is it something of only these 2 browsers that makes them special?
To handle data- attributes, you should set it whith the .attr method. Like this:
myDiv.attr("data-answered", "True")
Now, $('[data-answered=True]') should work.
That's because .data() stores the data into a internal jQuery place, and doesn't add data- attribute to the DOM.
To retrieve data, in the other hand, .data(key) both returns data assigned with .data(key,value) or the data- attributes. From the docs:
Return the value at the named data store for the first element in the
jQuery collection, as set by data(name, value) or by an HTML5 data-*
attribute.
Seems every thing goes well.
You could check the document about jQuery .data()
Briefly, $(...).data('answered', 'True') will not change the attr data-answered="False" to data-answered="True". $(...).attr('data-answered', 'True') does.
With raw javascript, you can achieve desired result, by below code.
Probably, you have problems because of comparing by True instead of 'True'
var ans = Array.from(document.getElementsByClassName("question")).filter(e=> (e.dataset.answered == 'True') ).length
/*
*
* if your browser does not support ES6 syntax
* Array.from(document.getElementsByClassName("question")).filter(function(e){ return e.dataset.answered == 'True' } ).length
*
*/
document.getElementById('answered').innerHTML = ans;
<div class="question" data-answered="False">
... rest of the html
</div>
<hr>
<div class="question" data-answered="True">
... rest of the html
</div>
<hr>
<div class="question" data-answered="True">
... rest of the html
</div>
<hr>
<div class="question" data-answered="False">
... rest of the html
</div>
<hr>
<div class="question" data-answered="True">
... rest of the html
</div>
<hr>
<div class="question" data-answered="True">
... rest of the html
</div>
<hr>
<div class="question" data-answered="False">
... rest of the html
</div>
<hr>
<div id="results">
<p>Answered: <span id="answered"></span></p>
</div>
Here is The problem i am trying solve. I would like to create a JS script that uses angular to dynamically create div elements while adding an additional expression eg {{levelone}}.
Here is an an example of what i am expecting the output to be if i know i have 5 iterations of Dom elements.
<div ng-switch-when="0">{{levelZero}}</div>
<div ng-switch-when="1">{{levelOneA}}{{levelOneB}}</div>
<div ng-switch-when="2">{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
etc.....
So as you can see i am adding an expression on each time. I just dont know how i can keep adding them on via a repeat loop and then get them to compile correctly with AngularJS. I am trying to make my DOM as Dynamic as possible.
EDIT
Every time i loop 1 more i am adding an expression ->{{expression}} to the div with JS or angular. I am not hard coding the expression into each div as each div is also dynamically created. But with a twist i am adding that extra expression ie 3 expressions from the previous div and adding one more expression making four. see example below.
<div ng-switch-when="3"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}</div>
This one below is dynamically generated
<div ng-switch-when="4"{{levelTwoA}}{{levelTwoB}}{{levelTwoC}}{{THIS EXPRESSION IS GENERATED IN js AND ADDED & COMPILED}}</div>
The DOM will be dynamic as long as your data bindings are. I need more info (data model, expectations) to be more accurate but if you set up your data and bind it correctly, it should work. for example if your data looked like this
var data = {
"levelOne" : {},
"levelTwo" : {
"elements" : ["<span id="firstEl"></span>, ...]
},
"levelThree" : {
"elements" : ["<span id="firstEl"></span>, <span id="secondEl"></span>, ...]
}
Then in your template do what #paulgoblin suggested.
}
You could ng-repeat within each switch case. Eg.
<div ng-switch-when="0">
<span>{{levelZero}}</span>
</div>
<div ng-switch-when="1">
<span ng-repeat="expression in levelOne">{{expression}}</span>
</div>
<div ng-switch-when="2">
<span ng-repeat="expression in levelTwo">{{expression}}</span>
</div>
You might want do this with scope function.
<div ng-switch="assignment.id">
<div ng-switch-when="1">{{ getExpressions(assignment.id) }}</div>
<div ng-switch-when="2">{{ getExpressions(assignment.id) }}</div>
</div>
hi it's a cordova app that use devexpress framework based on knockout i need to set visible only one item in a list
the item should correspond to the param.id or this
id_agenzia:ko.observable(params.id),
i've tryed with jquery (setting the id "#"+$data.id_agenzia visible if == id_agenzia ) but if i integrate it doesn't work
the goal is to do something like this
if i put this line it ignores
how is the right way to set visible only the div that corresponds to $data.id_agenzia is valid for $data.id_agenzia==id_agenzia ?
thank you for help
this is the js code with jsfiddle code added
self.selected_id_agenzia = ko.observable('two');
self.jsonLista = ko.observableArray([
{id_agenzia:ko.observable('one'), nome:'N1'},
{id_agenzia:ko.observable('two'), nome:'N2'}
noDataLabel: noDataLabel,
this is the html code with jsfiddle code added
<div class="list-indentation" data-bind="foreach:jsonLista" style="padding-bottom:60px;">
<div id="$data.id_agenzia" data-bind="visible: id_agenzia()==selected_id_agenzia()">
<div class="agency-description-box" >
<span data-bind="text: $data.id_agenzia" class="agency-name"></span>
<span data-bind="text: $data.nome" class="agency-name"></span>
</div>
</div>
</div>
I think I misunderstood what you were doing with the variables. I have made a simplified fiddle to do what I think you want. To make it work:
I assumed a dxList was more or less like a foreach
I changed the name of the outer id_agenzia to selected_id_agenzia, as I was not able to get the comparison to work using $data and $root to distinguish them
I made both items ko.observables, and used the function call on each in the comparison
</div>
The code is all at the fiddle:
http://jsfiddle.net/3ktq4b9s/
Could you help me to understand - where I made the mistake. I have the following html code:
<div id="container">
Info mail.ru
</div>
<div id="container">
Info mail.com
</div>
<div id="container">
Info mail.net
</div>
and the following js code (using jQuery):
$('#getInfo').click(function(){
alert('test!');
});
example here
"Click" event fired only on first link element. But not on others.
I know that each ID in html page should be used only one time (but CLASS can be used a lot of times) - but it only should (not must) as I know. Is it the root of my problem?
TIA!
upd: Big thx to all for explanation!:)
Use a class for this (and return false in your handler, not inline):
<div id="container">
Info mail.ru
</div>
<div id="container">
Info mail.com
</div>
<div id="container">
Info mail.net
</div>
$('.getInfo').click(function(){
alert('test!');
return false;
});
http://jsfiddle.net/Xde7K/2/
The reason you're having this problem is that elements are retrieved by ID using document.getElementById(), which can only return one element. So you only get one, whichever the browser decides to give you.
While you must, according to the W3 specifications, have only one element with a given id within any document, you can bypass this rule, and the issues arising from the consequences if document.getElementById(), if you're using jQuery, by using:
$('a[id="getInfo"]').click(function() {
alert('test!');
return false;
});
JS Fiddle demo.
But, please, don't. Respect the specs, they make everybody's life easier when they're followed. The above is a possibility, but using html correctly is much, much better for us all. And reduces the impact of any future changes within the browser engines, jQuery or JavaScript itself.
It must only be used once or it will be invalid so use a class instead, return false can also be added to your jQuery code as so: -
$('.getInfo').click(function(){
alert('test!');
return false;
});
<a href="#info-mail.net" **class**="getInfo" ....
First id's are for one element only, you should have same id for several divs.
you can make it class instead.
your example changed:
<div class="container">
<a href="#info-mail.ru" class="getInfo" >Info mail.ru</a>
</div>
<div class="container">
<a href="#info-mail.com" class="getInfo" >Info mail.com</a>
</div>
<div class="container">
<a href="#info-mail.net" class="getInfo" >Info mail.net</a>
</div>
$('.getInfo').click(function(ev){
ev.preventDefault(); //this is for canceling your code : onClick="return false;"
alert('test!');
});
You can use the same id for several element (although the page won't validate), but then you can't use the id to find the elements.
The document.getElementById method only returns a single element for the given id, so if you would want to find the other elements you would have to loop through all elements and check their id.
The Sizzle engine that jQuery uses to find the elements for a selector uses the getElementById method to find the element when given a selector like #getInfo.
I know this is an old question and as everyone suggested, there should not be elements with duplicate IDs. But sometimes it cannot be helped as someone else may have written the HTML code.
For those cases, you can just expand the selector used to force jQuery to use querySelectorAll internally instead of getElementById. Here is a sample code to do so:
$('body #getInfo').click(function(){
alert('test!');
});
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<div id="container">
Info mail.ru
</div>
<div id="container">
Info mail.com
</div>
<div id="container">
Info mail.net
</div>
</body>
However as David Thomas said in his answer
But, please, don't. Respect the specs, they make everybody's life easier when they're followed. The above is a possibility, but using html correctly is much, much better for us all. And reduces the impact of any future changes within the browser engines, jQuery or JavaScript itself.