Mutually Exclusive Data Attribute Selectors - javascript

Is it possible to select elements based on mutually exclusive data attributes, for example: I'd like to .show() any divs with data attribute of country="united-kingdom" and also with type="partner" OR "director"? Something like:
$('.post[data-country="united-kingdom"]&[data-type="partner,director"]').show();
or
$('.post[data-country="united-kingdom"]&[data-type="partner"]or[data-type="director"]').show();

I'd like to .show() any divs with data attribute of country="united-kingdom" and also with type="partner" OR "director"?
Then you want a selector group:
$('.post[data-country="united-kingdom"][data-type="partner"], .post[data-country="united-kingdom"][data-type="director"]').show();
That says: Match any element which
Has class post, has data-country set to united-kingdom, and has data-type set to partner
or
Has class post, has data-country set to united-kingdom, and has data-type set to director
The "or" part comes from the ,, which is what makes it a selector group rather than a single selector.
In a comment, you've said:
The user might select ten or more of each taxonomy term which requires generating loads of permutations of this conditional.
In that case, you may be better off with filter:
var countries = ["united-kingdom"]; // This would be created from inputs
var types = ["partner", "director"]; // This too
then
var results = $(".post[data-country][data-type]").filter(function() {
var $this = $(this);
return countries.indexOf($this.attr("data-country") != -1 &&
types.indexOf($this.attr("data-type") != -1;
});
In ES2016 or above, you could use Array#includes — which gives you a simple boolean — instead of Array#indexOf which you have to check against -1; and there'a polyfill you can use in ES2015 and earlier...:
var results = $(".post[data-country][data-type]").filter(function() {
var $this = $(this);
return countries.includes($this.attr("data-country") &&
types.includes($this.attr("data-type");
});
This can even be taken further:
var criteria = {};
// From inputs, ...
criteria["country"] = ["united-kingdom"];
criteria["type"] = ["parter", "director"];
then
var keys = Object.keys(criteria);
var selector= ".post" + keys.map(function(key) {
return "[data-" + key + "]";
}).join();
var results = $(selector).filter(function() {
var $this = $(this);
return keys.every(function(key) {
return criteria[key].includes($this.attr("data-" + key));
});
});
And as long as we're thinking about ES2015 and ES2016:
const keys = Object.keys(criteria);
const results = $(selector).filter(() => {
const $this = $(this);
return keys.every(key => criteria[key].includes($this.attr("data-" + key)));
});
or if you really want to go crazy:
const keys = Object.keys(criteria);
const results = $(selector).filter(() =>
keys.every(key => criteria[key].includes(this.getAttribute("data-" + key)))
);

You can add multiple selectors separated by a comma
$('.post[data-country="united-kingdom"][data-type="artist"], .post[data-country="united-kingdom"][data-type="partner"]').show();
Or use a filter with a selector
$('.post[data-country="united-kingdom"]').filter('[data-type="artist"], [data-type="partner"]').show();
or a filter with a callback
var countries = ["united-kingdom", "india", "france"],
types = ["artist", "partner"];
$('.post').filter(function() {
return types.indexOf( $(this).data('type') ) !== -1 &&
contries.indexOf( $(this).data('coutry') ) !== -1;
}).show()

Related

pure javascript, filter box doesn't filter properly

I have an array of devices, each device has own unique id, I wish to make searchBox which will filter by this id. So far I managed it partly, so it checks if character from input match character from device-id. However not in way I would want that, example below:
id =35678; input.value = 5
it shouldn't work as first character is 3
id = 35679; input.value= 35
it should work as first character is same
Problem is in match/include function, but no really idea how to replace it to make it work
input_box.addEventListener('keyup', function(){
var search_result = this.value;
var device = document.querySelectorAll('[device_id]')
var array_of_devices = [];
for (var i = 0; i < device.length; i++) {
array_of_devices.push(device[i].getAttribute('device_id'))
}
array_of_devices.forEach(el => {
if (!el.match(search_result)) {
var not_matched = document.querySelector(`[device_id="${el}"]`)
not_matched.style.display = "none"
} else {
var matched = document.querySelector(`[device_id="${el}"]`)
matched.style.display = "block"
}
})
})
You can use startsWith instead of match
let arr = ['35678', '451234', '45454', '56565']
let find = (value) =>{
return arr.filter(id=> id.startsWith(value))
}
console.log(find(5))
console.log(find(35))
console.log(find(46))
Instead of using .match you can simply use .indexOf and check the index, if it 0 then the entered string is matching the device name from the begining.
array_of_devices.forEach(el => {
// Condition below is changed to use indexOf
if (el.indexOf(search_result) === 0) {
var not_matched = document.querySelector(`[device_id="${el}"]`)
not_matched.style.display = "none"
} else {
var matched = document.querySelector(`[device_id="${el}"]`)
matched.style.display = "block"
}
});
I would suggest you to build a string of device elements based on the search string and add it to your DOM instead of modifying the display properties. This is costing you a bunch of DOM operations which is computationally heavy.
Notice each id in array should be string
const ids = ['3575', '5555']
const found = value => ids.filter(i => i.indexOf(value, 0) === 0)
console.log(found(5));
console.log(found(35));

Search in an Object Array with more than one condition jQuery grep()

I have an Object Array with Key-Value pair on jQuery like this
And I am searching in these arrays to find a match with with an id that I will provide so I have
var result = $.grep(records, function(e){ return e.id== id; });
So this looks like, search a record in the array with an id of whatever the value of id that i passed it. It works fine but what if I want to pass two parameters to match the records in the array? let's say columnheader and parent_colheader? What will my previous
var result = $.grep(records, function(e){ return e.id== id; });
syntax should be?
Use multiple variables with &&
var id = 1;
var columnheader = 'test';
var parent_colheader = 'test';
var result = $.grep(records, function(e) {
return e.id == id && e.columnheader == columnheader && e.parent_colheader == parent_colheader;
});

How to select elements with a specific array length

In an each function, I search through the DOM for many elements with a specific className. This ClassName, according to its length, will create an array that is long 2 or 4.
I need to select these two type of element separately in order to act differently.
How can I do that?
<div class="foo-1"></div>
<div class="foo-1"></div>
<div class="foo-1-boo-2"></div>
jQuery
$( '[class*=foo-]' ).each(function() {
var foo = $( this );
var fooArray = foo.attr( 'class' ).split( '-' );
var arrayLength = fooArray.length;
});
the console will return that there are 3 elements, two of them have length 2 and one 4.
I need to separate these two results in order to act differently as they were variables.
I need something like:
var caseA = (foo with an arrayLength === 2);
var caseB = (foo with an awwayLength === 4);
One possible way is to use .filter method with a function as an argument:
var elements = $('[class*=foo-]'),
caseA = elements.filter(function() {
return this.className.split('-').length === 2;
}),
caseB = elements.filter(function() {
return this.className.split('-').length === 4;
});
console.log(caseA.length, caseB.length);
I'm guessing you want these as jQuery sets instead of arrays so you can easily manipulate them en masse with jQuery. So this will do it:
var caseA = $('[class*=foo-]').filter(function() {
return $(this).attr("class").split("-").length === 2;
});
var caseB = $('[class*=foo-]').filter(function() {
return $(this).attr("class").split("-").length === 4;
});
If you have tons of elements and it proves to be slow you can optimize this slightly by making it more complex and using one each instead of filter. But I wouldn't bother until it proves to be necessary.
Another possible way is to just use a conditional statement -
$('[class*=foo-]').each(function () {
var foo = $(this);
var fooArray = foo.attr('class').split('-');
var arrayLength = fooArray.length;
(2 == arrayLength ? console.log('to do something') : '');
(4 == arrayLength ? console.log('do something for') : '');
});
I mixed two solutions in the comment of this post:
var caseA = col.filter(function() {
return this.className.split( '-' ).length === 2;
});
var caseB = col.filter(function() {
return this.className.split( '-' ).length === 4;
});

How to make an array of CSS classes

How do I make an array of CSS classes, not the CSS class names? I need the "." and everything.
I need users to be able to click on certain buttons, and add the classes the button belongs to into an array.
I used this before:
var myPicks[];
$('.button').click( function() {
var hello = " " + $(this).attr('class').split(' ')[0];
myPicks.push(hello);
}
But that seems to add the name of the classes, not the classes themselves. It's possible I'm wrong and there's something wrong with another part of my JQuery code.
Try
var myPicks = [];
$('.button').click( function() {
Array.prototype.push.apply(myPicks, $.map($(this).attr('class').split(' '), function(value, idx){
return '.' + value
}))
console.log('myPicks', myPicks)
});
if you want only unique classes
var myPicks = [];
$('.button').click( function() {
$.each($(this).attr('class').split(' '), function(idx, value){
var selector = '.' + value;
if($.inArray(selector, myPicks) == -1){
myPicks.push(selector)
}
})
console.log('myPicks', myPicks)
});
Demo: Fiddle
I will not recommend save the name of the class with the dot included into that array(), It will be useless if you need it later for something else.
(Or your goint to need to split it again)
Instead, I suggest to save it like you have now and then and only when you needed, add the dot to that value
like:
var myPicks = new Array();
myPicks[0] = "something";
// original value:
var newValue = myPicks[0]; // newValue == 'something'
//used as ID:
var newValue = '#' + myPicks[0]; // newValue == '#something'
// used as a class:
var newValue = '.' + myPicks[0]; // newValue == '.something'
BUT, of course if you need that way... just replace the PUSH function and add the dot to it:
var newHello = '.' + hello;
myPicks.push(newHello);

Return Multiple CheckBox Values if Checked in jQuery

I have multiple checkbox in my page. i want to retrieve its values if checked.
Here is HTML Code..
<input name="ctl1189" type="checkbox" id="chkTicket_189310" class=" chkTicket" value="189310">
<input name="ctl1190" type="checkbox" id="chkTicket_189311" class=" chkTicket" value="189311">
And So on..
Javascript Code:
function updateTicketAction() {
var allUpdatedVendorTickets = $('.chkTicket').filter(function() { return this.value != $input.is(':unchecked'); });
var sFinalUpdateList = '';
allUpdatedVendorTickets.each(function() {
var ids = $(this).attr('id').split('_')[1];
sFinalUpdateList += ((sFinalUpdateList == '') ? '' : '|') + ids + ',' + $(this).val();
});
alert(sFinalUpdateList);
}
function updateTicketAction() {
var sFinalUpdateList = '';
$("input.chkTicket:checked").each(
function() {
var ids = $(this).attr('id').split('_');
var id = ids[1];
sFinalUpdateList += ((sFinalUpdateList == '') ? '' : '|') + id + ',' + $(this).val();
}
);
alert(sFinalUpdateList);
}
http://jquery-howto.blogspot.com/2008/12/how-to-check-if-checkbox-is-checked.html
I just created a fiddle. Look in the JavaScript console for the resulting object, which you can then further process.
Code:
var checkedCheckboxes = $('.chkTicket:checked'),
results = {};
checkedCheckboxes.each(function () {
var key = $(this).attr('id').split('_')[1];
results[key] = $(this).val();
});
function alertResults(results) {
var text = '', sep = '';
$.each(results, function (key, value) {
text += sep + key + '=' + value;
sep = '|';
});
alert(text);
}
alertResults(results);
console.log(results);
try this code
var collect='';
$('input:checked').each(function(i,e){
collect+=(collect===''? $(e).attr('name')+'='+$(e).val():','+$(e).attr('name')+'='+$(e).val());
alert(collect);
})
Here is a jsfiddle snippet that returns all checked inputs..
One question though, why do you split your id-attribute when you have your id stored in value-attribute? Anyways, hope this works for you!
function updateTicketAction() {
var allUpdatedVendorTickets = $('.chkTicket:checked');
var sFinalUpdateList = '';
allUpdatedVendorTickets.each(function () {
sFinalUpdateList += ((sFinalUpdateList == '') ? '' : '|') + $(this).val();
});
alert(sFinalUpdateList);
}
Or you can use map():
var el = $('input[type=checkbox]:checked').map(function(i,e){
var id = $(e).attr('id').replace('chkTicket_', '');
var val = $(e).val();
return {
'id' : id,
'value' : val
}
});
console.log(el[0].id);
Your filter function is wrong.
this.value != $input.is(':unchecked');
You're comparing a .value property (string) to the return value of the .is jQuery method (boolean). It's similar to:
'value' != !true //checked
'value' != !false //unchecked
Both will always return true - unless value is 0 or an empty string which evaluates to a falsy value and the right side of the expression evaluates to false, for which the != different operator will return false.
So, your filter's callback doesn't filter anything at all, except taking out checked boxes with value 0 or no value (which is unintentional).
You can avoid using a filter function by using the :checked selector:
var allUpdatedVendorTickets = $('.chkTicket:checked');
Now you'll have a jQuery object containing only the checked .chkTicket, much better.
Next thing, you're making bad use of strings.
"189310,189310|189311,189311"
That's what your function is generating. Every time you need to manipulate those results, you'll have to split the string at |, creating a new array. It's much better to store it as an array already.
var sFinalUpdateList = [];
Assuming your keys and values are always the same as in your example, you should store them only once as well.
allUpdatedVendorTickets.each(function() {
sFinalUpdateList.push(this.value);
});
This will generate a much more clean and maintainable array with only the checked boxes' values:
sFinalUpdateList =>
[0] -> "189310"
[1] -> "189311"
You can obtain their IDs by appending chkTicket_ to those values.
jsFiddle

Categories