jQuery match part of class with hasClass - javascript

I have several div's with "project[0-9]" classes:
<div class="project1"></div>
<div class="project2"></div>
<div class="project3"></div>
<div class="project4"></div>
I want to check if the element has a "project[0-9]" class. I have .hasClass("project") but I'm stuck with matching numbers.
Any idea?

You can use the startswith CSS3 selector to get those divs:
$('div[class^="project"]')
To check one particular element, you'd use .is(), not hasClass:
$el.is('[class^="project"]')
For using the exact /project\d/ regex, you can check out jQuery selector regular expressions or use
/(^|\s)project\d(\s|$)/.test($el.attr("class"))

A better approach for your html would be:
I believe these div's share some common properties.
<div class="project type1"></div>
<div class="project type2"></div>
<div class="project type3"></div>
<div class="project type4"></div>
Then you can find them using:
$('.project')

$('div[class*="project"]')
will not fail with something like this:
<div class="some-other-class project1"></div>

$('div[class^="project"]')
will fail with something like this:
<div class="some-other-class project1"></div>
Here is an alternative which extends jQuery:
// Select elements by testing each value of each element's attribute `attr` for `pattern`.
jQuery.fn.hasAttrLike = function(attr, pattern) {
pattern = new RegExp(pattern)
return this.filter(function(idx) {
var elAttr = $(this).attr(attr);
if(!elAttr) return false;
var values = elAttr.split(/\s/);
var hasAttrLike = false;
$.each(values, function(idx, value) {
if(pattern.test(value)) {
hasAttrLike = true;
return false;
}
return true;
});
return hasAttrLike;
});
};
jQuery('div').hasAttrLike('class', 'project[0-9]')
original from sandinmyjoints: https://github.com/sandinmyjoints/jquery-has-attr-like/blob/master/jquery.hasAttrLike.js
(but it had errrors so I fixed it)

You can improve the existing hasClass method:
// This is all that you need:
(orig => {
jQuery.fn.hasClass = function(className) {
return className instanceof RegExp
? this.attr('class') && this.attr('class')
.split(/\s+/)
.findIndex(name => className.test(name)) >= 0
: orig.call(this, className);
}
})(jQuery.fn.hasClass);
// Test the new method:
Boolean.prototype.toString = function(){ this === true ? 'true' : 'false' };
const el = $('#test');
el.append("hasClass('some-name-27822'): " + el.hasClass('some-name-27822'));
el.append("\nhasClass(/some-name-\d+/): " + el.hasClass(/some-name-\d+/));
el.append("\nhasClass('anothercoolclass'): " + el.hasClass('anothercoolclass'));
el.append("\nhasClass(/anothercoolclass/i): " + el.hasClass(/anothercoolclass/i));
el.append("\nhasClass(/^-name-/): " + el.hasClass(/^-name-/));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<pre id="test" class="some-name-0 some-name-27822 another-some-name-111 AnotherCoolClass"></pre>

why don't you use for to check numbers
for (var i = 0; i < 10; i++) {
if(....hasClass("project"+i))
{
//do what you need
}
}

Related

How to iterate over an array of strings to generate class selectors

I have a long array of strings like "authorA", "authorB", "authorC". I am trying to iterate over that array to use it as a css class selector.
However, it does not work. I have tried all sorts of combinations, but I cannot get jquery to understand the string as a class. What am I doing wrong? Below is my latest attempt.
(selected_authors_array).forEach(function (item, index) {
$('#card-content > ('.' + item)').show();
});
This is the entire code:
var script = document.createElement("script");
script.innerHTML = `
$('[id="filtro-${artigo.author.name}"]').change(function() {
show_content('#conteudo-reports', 'Relatórios');
$("#nav-tab").fadeIn();
$("#pagination").fadeIn(); //pagination
$("#nav-share").fadeOut(); //back button
if(this.checked){
filtered_authors_set.add('.${(artigo.author.name).split(' ').join('')}');
}
else {
filtered_authors_set.delete('.${(artigo.author.name).split(' ').join('')}');
}
if(filtered_authors_set.size == 0){
$('#card-content > *').show();
$('#grid-content > *').show();
$('#list-content > *').show();
}
else {
$('#card-content > *').hide();
$('#grid-content > *').hide();
$('#list-content > *').hide();
selected_authors_array = Array.from(filtered_authors_set);
(selected_authors_array).forEach(function (item, index) {
console.log(item);
$('#card-content > item').show();
$('#grid-content > item').show();
$('#list-content > item').show();
});
}
});
`;
document.head.appendChild(script);
You can try this
const selected_authors_array = ["authorA", "authorB", "authorC"];
const selectors = [];
// create an array of selectors
selected_authors_array.forEach(function(item, index) {
selectors.push("." + item);
});
$("#card-content")
.find(selectors.join(', ')) // join them to form a list of selectors
.show();
.authorA,
.authorB,
.authorC {
display: none;
}
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="card-content">
<div class="authorA">Author A (should show)</div>
<div class="authorB">Author B (should show)</div>
<div class="authorC">Author C (should show)</div>
</div>
<div class="authorA">Author A (should hide)</div>
<div class="authorB">Author B (should hide)</div>
<div class="authorC">Author C (should hide)</div>
The way you have structured your selector is a string #card-content > (, a dot and a second string + item)
You can do it much easier with template literals
$(`#card-content > .${item}`).show();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

Jquery converted to Javascript results in title undefined? How do I convert this properly?

I'm trying to convert my jquery back to Javascript, but for some reason it states that title is undefined. I'm not sure how to convert it properly or what to do to fix this issue.
Here is the current jquery code
update: function (e) {
var el = e.target;
var $el = $(el);
var val = $el.val().trim();
if (!val) {
this.destroy(e);
return;
}
if ($el.data('abort')) {
$el.data('abort', false);
} else {
this.todos[this.indexFromEl(el)].title = val;
}
this.render();
},
Here is the code from indexFromEl function
indexFromEl: function (el) {
var id = $(el).closest('li').data('id');
var todos = this.todos;
var i = todos.length;
while (i--) {
if (todos[i].id === id) {
return i;
}
}
},
So based off the code above, I tried to convert it myself, but I don't think I did it correctly.
update: function (e) {
var el = e.target;
var val = el.value.trim();
if (!val) {
this.destroy(e);
return;
}
if(val === 'abort') {
return false;
} else {
return this.todos[this.indexFromEl(el)].title = val;
}
this.render();
},
How do I convert the first code block from jquery to javascript? Also, I'm not sure how to edit the first line in the indexFromEl jquery code
Here is the jquery script
<script id="todo-template" type="text/x-handlebars-template">
{{#this}}
<li {{#if completed}}class="completed"{{/if}} data-id="{{id}}">
<div class="view">
<input class="toggle" type="checkbox" {{#if completed}}checked{{/if}}>
<label>{{title}}</label>
<button class="destroy"></button>
</div>
<input class="edit" value="{{title}}">
</li>
{{/this}}
</script>
Since the id for each li is being set in the HTML markup, rather than by jQuery:
<li {{#if completed}}class="completed"{{/if}} data-id="{{id}}">
// ^^^^^^^^^^^^^^^^
Once you have a reference to the element in Javascript, all you need to do is retrieve the id property from the dataset, eg:
li.dataset.id
To do that, in your indexFromEl function, use:
const id = el.closest('li').dataset.id;
Or if you like using destructuring to make things a bit more DRY:
const { id } = el.closest('li').dataset;
Also note that it would be much cleaner to use findIndex if you want to find an index in an array:
indexFromEl: function (el) {
const { id } = el.closest('li').dataset;
return this.todos.findIndex(todo => todo.id === id);
}
(though, the above will return -1 if no index is found, rather than undefined, as your current code does, if that's an issue)
In your query version, you didn't return anything. So why returning JavaScript version?
First try to find what is this.todos[this.indexFromEl(el)] using instanceof
If this.todos[this.indexFromEl(el)] is Element then you can set(as you're assigning val) title attribute by setAttribute()
So,
this.todos[this.indexFromEl(el)].setAttribute('title', val);

Jquery find all elements with custom attribute begin with, get rest of it's name and it's value

Let's say we have element with custom attribute
... bind-html="varName" ...
I want to find all elements with attribute beginning with "bind-",
then get second part of it's name, which is unknown, in this case "html".
And at last get it's value "varName".
How do i achieved this with Jquery? I don't want to use second attribute to describe attibute to bind (like .. bind="varName" attr="html" ..)
You can use a loop through each object's attributes this.attributes and use the attribute's name and value properties.
Running example:
$("input").each(function() {
$.each(this.attributes, function() {
if (this.name.indexOf('bind-') == 0) {
console.log(this.name + ' has the value: ' + this.value);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<input bind-koby='hello'>
<input bind-douek='stack'>
<input will-not-show='yes'>
<input bind-hello='overflow'>
well that what you are looking for like
<div bind-html="varName">hi there i am </div>
well hi thats me
var namer = $(" *[attr*='bind']").text();
console.log(namer);
<div class="bindable" data-bind="html:varName1"></div>
<div class="bindable" data-bind="css:varName2"></div>
<div class="bindable" data-bind="js:varName3"></div>
<div class="bindable" data-bind="whatEver:varName4"></div>
(function(){
let bindables = $('.bindable');
bindables.each(function(){
let bindData = $(this).data('bind');
let bindDataArray = bindData.split(":");
console.log(bindDataArray);
});
}());
now u will get array with data u want
You can get all elements and their attributes which contain bind- by using jquery .properties and .indexOf() like following example.
// $("*") selects all elements in your html
$("*").each(function() {
$.each(this.attributes, function() {
// checks whether element has an attribute starts with "bind-" or not
if(this.specified && this.name.indexOf("bind-") !== -1) {
console.log("Attr Name: "+ this.name + " Attr Value: " + this.value)
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span bindNot-html="bindNot">element1</span>
<div bind-html="varName1">element2</div>
<a bind-html2="varName2">element3</a>
<div bind-html3="varName3">element4</div>
<span bindNot-html="bindNot">element5</span>

Filter values similar

I want filter values ​​similar, I tried as following js code, but this code can not filter value 111 because this no ,. my html code is as following (Some do, some do not this: ,).
How can fix js code for filter all strings?
DEMO: http://jsfiddle.net/bNuRE/
HTML:
<div class="oo">111</div>
<div class="oo">111, 222, 333</div>
<div class="oo">444, 111</div>
<div class="oo">222, 333</div>
///////////////////////////////////////////////////////
<div class="ww">111</div>
<div class="ww">777</div>
<div class="ww">333</div>
<div class="ww">666</div>
JS:
var valeache = $('.oo').text().split(', ');
$.each(valeache, function (a, val) {
$('.ww').filter(function () {
return $(this).text() == val
}).remove();
});
Your construction of valeache is wrong.
You need to iterate over each .oo element to correctly construct valeache.
var valeache = $('.oo').map(function(){
return $(this).text().split(', ');
}).get();
$.each(valeache, function (a, val) {
$('.ww').filter(function () {
return $(this).text().trim() == val;
}).remove();
});
var valeache = null;
$('.oo').text(function(i, text) {
valeache += text.replace(/\s/g,'') + ',';
})
valeache = $.unique( valeache .replace(/,$/,'').split(',') );
$.each(valeache, function (a, val) {
$('.ww').filter(function () {
return $(this).text() == val
}).remove();
});
Demo: http://jsfiddle.net/xfSK4/3/
It's not entirely clear to me what you're trying to do. Are you simply trying to remove the elements from the target list whose value match one of the (possibly comma-separated) values from any of the elements of the source list? If so, I think you can do it more easily:
var vals = $.map($('.oo'), $.text).join(", ").split(", ");
$('.ww').filter(function () {
return $.inArray($(this).text(), vals) > -1;
}).remove();
Demo: http://jsfiddle.net/CrossEye/MVGLQ/1/
That initial array contains duplicates, but that shouldn't be a problem.

How can I select the "shallowest" matching descendant?

How can I select the first "shallowest" input?
My current selection will be the div marked "selected".
I won't know how many levels down it will be.
<div class="selected"> <!-- already have this -->
<div class="unknown-number-of-wrapper-panels">
...
<div class="collection">
<div class="child">
<input type="text" value="2" /> <!-- don't want this -->
</div>
</div>
<input type="text" value="2" /> <!-- need this -->
<input type="text" value="2" />
...
</div>
</div>
It seems like find().first() gives me the deepest one.
Edited for clarity. I need to find it based on the fact that it is shallower, not based on other unique attributes.
This might be like a reverse of closest() ?
If I understand your issue, you need to recursively check the child nodes for elements with that class.
function findShallowest( root, sel ) {
var children = root.children();
if( children.length ) {
var matching = children.filter( sel );
if( matching.length ) {
return matching.first();
} else {
return findShallowest( children, sel );
}
} else {
return null;
}
}
var selected = $('.selected');
findShallowest( selected, ':text' );
Example: http://jsfiddle.net/Qf2GM/
EDIT: Had forgotten a return statement, and had an ID selector instead of a class selector for the initial .selected.
Or make it into your own custom plugin:
Example: http://jsfiddle.net/qX94u/
(function($) {
$.fn.findShallowest = function( sel) {
return findShallowest( this, sel );
};
function findShallowest(root, sel) {
var children = root.children();
if (children.length) {
var matching = children.filter(sel);
if (matching.length) {
return matching.first();
} else {
return findShallowest(children, sel);
}
} else {
return $();
}
}
})(jQuery);
var result = $('.selected').findShallowest( ':text' );
alert( result.val() );
You are after a breadth-first search rather than the depth-first search (which jQuery's find() uses). A quick google has found: http://plugins.jquery.com/project/closestChild
This could be used like this:
$(...).closestChild('input')
Just to golf this "plugin" a bit - Uses #user113716's technique, just reduced code size.
$.fn.findShallowest = function( selector ) {
var children = this.children(),
matching = children.filter( selector );
// return an empty set if there are no more children
if ( !children.length ) {
return children;
}
// if anything matches, return the first.
if ( matching.length ) {
return matching.first();
}
// check grand-children
return children.findShallowest( selector );
};
Try on jsFiddle
This is another approach. The idea is that you get the matching element with the least number of ancestors:
(function($) {
$.fn.nearest = function(selector) {
var $result = $();
this.each(function() {
var min = null,
mins = {};
$(this).find(selector).each(function() {
var n_parents = $(this).parents().length,
if(!mins[n_parents]) {
mins[n_parents] = this;
min = (min === null || n_parents < min) ? n_parents : min;
}
});
$result = $result.add(mins[min]);
});
return $result;
};
}(jQuery));
Usage:
$('selected').nearest('input');
DEMO
findShallowest, as #patrick has it, might be a better method name ;)
If you don't know the class name of the bottom level element you can always use something like
$('.unknown-number-of-wrapper-panels').children().last();
Well given your markup, would the following work?
$('.selected div > input:first')

Categories

Resources