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.
Related
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
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);
Am struggling hard to bind an array object with list of span values using watcher in Angularjs.
It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).
The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.
DemoCode fiddle link
What am I missing in my code?
How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?
Please note that values will get changed any time as per a chart.
This is the code am using:
<script>
function rdCtrl($scope) {
$scope.dataset_v1 = {};
$scope.dataset_wc = {};
$scope.$watch('dataset_wc', function (newVal) {
//alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
$('#status').html(JSON.stringify($scope.dataset_wc));
}, true);
$(function () {
$('#tags input').on('focusout', function () {
var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
if (txt) {
//alert(txt);
$(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
var div = $("#tags");
var spans = div.find("span");
spans.each(function (i, elem) { // loop over each spans
$scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
id: i, // gives the id as "0,1,2.....n"
name: $(elem).text(), // push the text of the span in the loop
value: 3
}
});
$("#assign").click();
}
this.value = "";
}).on('keyup', function (e) {
// if: comma,enter (delimit more keyCodes with | pipe)
if (/(188|13)/.test(e.which)) $(this).focusout();
if ($('#tags span').length == 7) {
document.getElementById('inptags').style.display = 'none';
}
});
$('#tags').on('click', '.tag', function () {
var tagrm = this.innerHTML;
sk1 = $scope.dataset_wc;
removeparent(sk1);
filter($scope.dataset_v1, tagrm, 0);
$(this).remove();
document.getElementById('inptags').style.display = 'block';
$("#assign").click();
});
});
$scope.assign = function () {
$scope.dataset_wc = $scope.dataset_v1;
};
function filter(arr, m, i) {
if (i < arr.length) {
if (arr[i].name === m) {
arr.splice(i, 1);
arr.forEach(function (val, index) {
val.id = index
});
return arr
} else {
return filter(arr, m, i + 1)
}
} else {
return m + " not found in array"
}
}
function removeparent(d1)
{
dataset = d1;
d_sk = [];
Object.keys(dataset).forEach(function (key) {
// Get the value from the object
var value = dataset[key].value;
d_sk.push(dataset[key]);
});
$scope.dataset_v1 = d_sk;
}
}
</script>
Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.
You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/
function rdCtrl($scope){
$scope.dataset = [];
$scope.inputVal = "";
$scope.removeData = function(index){
$scope.dataset.splice(index, 1);
redoIndexes($scope.dataset);
}
$scope.addToData = function(){
$scope.dataset.push(
{"id": $scope.dataset.length+1,
"name": $scope.inputVal,
"value": 3}
);
$scope.inputVal = "";
redoIndexes($scope.dataset);
}
function redoIndexes(dataset){
for(i=0; i<dataset.length; i++){
$scope.dataset[i].id = i;
}
}
}
<div ng-app>
<div ng-controller="rdCtrl">
<div id="tags" style="border:none;width:370px;margin-left:300px;">
<span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
<div>
<input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
<button type="submit" ng-click="addToData()">Submit</button>
<img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />
</div>
</div>
<div id="status" style="margin-top:100px;"></div>
</div>
</div>
I have a tag like this:
Link
When I click this link, I have a function like this
$('#ssd').click(function (event) {
var customData;
// Code to get all the custom data in format like data-info*
});
Note, the data-info* like attributes could be any number, that means you could see 1 one of them, named data-info1, or there of them, named data-info1, data-info2, data-info3.
How would I do that, I looked up the JQuery selectors, something like Attribute Starts With Selector [name^="value"] won't work because the variation here is on name...
If I console.log($('#ssd').data()); I will get an object with extra attributes that I don't need, toggle: "popover", bs.popover: Popover
Any suggestions?
This is what I did:
dataFullList = $(this).data();
$.each(dataFullList, function (index, value) {
if (index !== "toggle" && index !== "bs.popover") {
item.name = value.split(":")[0];
item.number = value.split(":")[1];
dataIWant.push(item);
}
});
So I will get a dataIWant array without stuff I don't need.
Target all elements which data-* starts with
Custom jQuery selector selector:dataStartsWith()
Here's a custom jQuery selector that will help you to:
Given the data-foo-bar prefix , target the following elements:
data-foo-bar
data-foo-bar-baz
but not:
data-foo-someting
data-something
jQuery.extend(jQuery.expr[':'], {
"dataStartsWith" : function(el, i, p, n) {
var pCamel = p[3].replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return Object.keys(el.dataset).some(function(i, v){
return i.indexOf(pCamel) > -1;
});
}
});
// Use like:
$('p:dataStartsWith(foo-bar)').css({color:"red"});
// To get a list of data attributes:
$('p:dataStartsWith(foo-bar)').each(function(i, el){
console.log( el.dataset );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
Custom jQuery Method $().dataStartsWith()
$.fn.dataStartsWith = function(p) {
var pCamel = p.replace(/-([a-z])/ig, function(m,$1) { return $1.toUpperCase(); });
return this.filter(function(i, el){
return Object.keys(el.dataset).some(function(v){
return v.indexOf(pCamel) > -1;
});
});
};
$('p').dataStartsWith("foo-bar").css({color:"red"});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p data-foo-bar="a">I have data-foo-bar</p>
<p data-foo-bar-baz="b" data-extra="bbb">I have data-foo-bar-baz</p>
<p data-bar="a">I have data-bar DON'T SELECT ME</p>
<p data-something="b">I have data-something DON'T SELECT ME</p>
This function will get the data-info attributes and put them into an array:
function getDataInfo($element, i, a) {
var index = i || 1, array = a || [],
info = $element.data('info' + index);
if(info === undefined) {
return array;
}
array['info' + index] = info;
return getDataInfo($element, index + 1, array);
}
$(function() {
console.log(getDataInfo($('#ssd')));
});
Here's an if condition to isolate the invalid keys while you loop the data. Used as a filter, you can choose to delete the keys you do not want - like this:
$('#ssd').click(function(e){
var data = $(this).data();
for(var key in data) {
//here is a condition to use only those data-info items
if(data.hasOwnProperty(key) && key.indexOf('info') === -1) {
console.log(key); //just to see which key it is
delete data[key]; //if you need to build a collection of only data-info keys
}
}
});
Alternatively, negate the if condition to include only those keys you want.
You can use Prefix Data. It is jQuery plugin. Return the value at the prefixed data store for the first element in the set of matched elements. Returned value can be an object based on the attribute values and attributes name structure.
Usage
Take any HTML tag with multi data-* attributes with the same prefix. In the example we focus on myprefix prefix.
<div id="example-tag"
data-myprefix='{"property1": "value1", "property2": {"property21": "value21"}, "property3": "value2"}'
data-myprefix-property2='{"property22": "value22"}'
data-myprefix-property2-property23="value23"
data-myprefix-property3="overwite-value3"
data-myprefix-property4='{"property41": "value41"}'
data-other="We do not read it"></div>
If you want to read data from data-myprefix and every data-myprefix-* attribute you can use .prefixData() with given prefix.
$('#example-tag').prefixData('myprefix');
The previous example returns the object:
{
property1: "value1",
property2: {
property21: "value21",
property22: "value22",
property23: "value23"
},
property3: "overwite-value3",
property4: {
property41: "value41"
}
}
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
}
}