I have a Jquery function that helps with validation over 1 object. I need to expand it so that the function will run over 3 different objects. I am trying to define a function that takes a parameter(whichquote) to insert the appropriate object in the function. Here is my code. What I am doing wrong? I assume I do not have the selector correct as the code works if I put it in.
Original Function that works:
var depends = function() {
var selectorD = $("input[name^='lead[quote_diamonds_attributes]'], select[name^='lead[quote_diamonds_attributes]']");
var vals = '';
selectorD.not(':eq(0)').each(function () {
vals += $(this).val();
});
return vals.length > 0;
};
Function I am trying to create that allows me to use it on other objects. This currently does not work.
var depends = function(whichquote) {
var selectorD = $("input[name^='lead[+ whichquote +]'], select[name^='lead[+ whichquote +]']");**
var vals = '';
selectorD.not(':eq(0)').each(function () {
vals += $(this).val();
});
return vals.length > 0;
};
I think the problem is with my concating in the var selectorD but cannot seem to get the syntax correct.
Your selector isn't actually inputting whichquote because the string concatenation is incorrect.
Try
var selectorD = $("input[name^='lead[" + whichquote + "]'], select[name^='lead[" + whichquote +"]']");
I'm teaching myself JavaScript and JQuery and working through a simple Glossary app as I go. Currently my glossary terms are in two json files (one for terms and one for acronyms). I have a page with text on it and code to make a definition display in an alert when I click on a word that is available in the glossary of terms or glossary of acronyms. That part is working. What I would like to do is to be able to change the style of each word in the text that has a matching definition (color, underline, etc). I think I need to use a loop to check if the word in in the glossary (I can already do that) and then apply but I'm not really sure the span works when doing it dynamically. The one span tag in my code is modified example that had been posted in another question here and I have it working for me, I'm just not too certain how it does what it does. Anyone have time to get me going in the right direction?
//breaks the paragraph html into word by word targets
var p = $('p#paragraph');
var words;
p.html(function(index, oldHtml) {
words = oldHtml.replace(/\b(\w+?)\b/g, '<span class="word">$1</span>')
return words;
});
//when word is clicked checks to see if word in the glossary, if so displays alert box with word and definition
p.click(function(event) {
if (this.id != event.target.id) {
var termNeeded = event.target.innerHTML;
//checks Terms json first
var checkAcronyms = true;
for (var i = 0; i < jsonTerms.GlossaryTerms.length; i++) {
var obj = jsonTerms.GlossaryTerms[i];
if (obj.term == termNeeded) {
alert(obj.term + ": " + obj.definition);
checkAcronyms = false;
break;
};
};
//if the word is not in the terms, then checks in the acronyms
if (checkAcronyms == true){
for (var i = 0; i < jsonAcronyms.GlossaryAcronyms.length; i++) {
var obj = jsonAcronyms.GlossaryAcronyms[i];
if (obj.term == termNeeded) {
alert(obj.term + ": " + obj.definition);
break;
};
};
};
};
});
//brings in the JSON data
var jsonTerms;
$.getJSON("GlossaryTerms.json", function(data) {
jsonTerms = data;
//console.log(jsonTerms);
});
var jsonAcronyms;
$.getJSON("GlossaryAcronyms.json", function(data) {
jsonAcronyms = data;
//console.log(jsonAcronyms);
});
Maybe something like this would do the trick:
I changed your code around a bit, and please beware that it is untested.
You would have to define a CSS style with the name "defined", which will indicate that the word has a definition.
I extracted your logic into a separate function for reuse. Also, created the addStyleToWords function, which should iterate over all your words, check if they have a definition, and if they do, then add an extra class to that element.
var jsonTerms;
var jsonAcronyms;
function checkWord(termNeeded) {
//checks Terms json first
for (var i = 0; i < jsonTerms.GlossaryTerms.length; i++) {
var obj = jsonTerms.GlossaryTerms[i];
if (obj.term == termNeeded) {
return obj;
}
}
//if the word is not in the terms, then checks in the acronyms
for (var i = 0; i < jsonAcronyms.GlossaryAcronyms.length; i++) {
var obj = jsonAcronyms.GlossaryAcronyms[i];
if (obj.term == termNeeded) {
return obj;
}
}
return null;
}
function addStyleToWords() {
$(".word").each(function() {
var el = $(this);
var obj = checkWord(el.text());
if (obj != null) el.addClass("defined");
});
}
//breaks the paragraph html into word by word targets
var p = $('p#paragraph');
p.html(function(index, oldHtml) {
return oldHtml.replace(/\b(\w+?)\b/g, '<span class="word">$1</span>');
});
//when word is clicked checks to see if word in the glossary, if so displays alert box with word and definition
p.click(function(event) {
if (this.id != event.target.id) {
var obj = checkWord(event.target.innerHTML);
if (obj != null) alert(obj.term + ": " + obj.definition);
});
//brings in the JSON data
$.getJSON("GlossaryTerms.json", function(data) {
jsonTerms = data;
$.getJSON("GlossaryAcronyms.json", function(data) {
jsonAcronyms = data;
addStyleToWords();
});
});
Once you have added in your spans and the JSON data has loaded you need to loop through each
word span testing them for matches as you go.
p.find('span.word').each(function(){
// "this" now refers to the span element
var txt=this.innerHTML;
if(isInGlossary(txt)){
$(this).addClass('in_glossary');
}
})
You will need to define the isInGlossary(term) function, pretty much what you have done already in your p.click code.
I don't get it...
To if I understand you correctly, look at: JQuery addClass
My Suggestions:
If you want to iterate over each work in the paragraph, then, in your click handler find each span tag using $('p#paragraph).find('span').each(function(){...});
In your each function, get the work with $(this).html()
To style your word, add a class or css to $(this). see:JQuery addClass
Rather return your JSONArray as a JSONObject (much like an associative array) with the word being the property and the description being the value, that way you can search through it like so: var definition = json[word].
Need to get all direct nodes from DOM element and don't actually know, how it many and what kind they are.
.contents()?
Ok, let's see..
$('<div />').html('<p>p</p>').contents() ->
[<p>p</p>]
Ok.
$('<div />').html('textNode').contents() -> []
WTF?
$('<div />').html('textNode').append('another').contents() ->
["textNode", "another"]
Ok, so what about single text node?
I don't know if this is helpful. A while ago I built a Document Fragment generator using JSON styled input. I also wrote a (somewhat working) reverse function for it so you could turn your nodeList into a JSON string.
https://gist.github.com/2313580
var reverseFunction = function(DOM /* DOM tree or nodeList */) {
var tree = [];[].forEach.call(DOM, function(obj) {
if (obj instanceof Text) {
tree.push({
'textContent': obj.textContent
});
} else {
var tmp = {};
tmp['tagName'] = obj.nodeName;
for( var data in obj.dataset ) {
tmp['data-' + data] = obj.dataset[data];
}
for (var i = 0, l = obj.attributes.length; i < l; i++) {
var key = obj.attributes[i].name,
val;
if (key.indexOf('data-') === -1) {
switch (key) {
case ('class'):
key = 'className';
break;
case ('style'):
val = {};
obj.attributes[i].value.split(';').forEach(function(rule) {
var parts = rule.split(':');
val[parts[0]] = parts[1];
});
break;
};
tmp[key] = val || obj.attributes[i].value;
}
}
if (obj.childNodes.length > 0) {
tmp['childNodes'] = reverseFunction(obj.childNodes);
}
tree.push(tmp);
}
});
return tree;
};
This does find textNodes and separates them... You may be able to extract something from it.
Update: to answer a comment in your question above...
var div = document.createElement('div');
div.appendChild(document.createTextNode('dsf'));
console.log( div.childNodes.length, div.childNodes, div.childNodes[0].textContent);
I hope this makes a bit more sense to you know. The array appears empty in the console but it is not. check the length and attempt to access it and you will see.
.contents() is concerned with DOM nodes. That string in the 2nd example is not a DOM element.
var selValues = {};
selValues['234'] = $('#asd').val();
selValues['343'] = function () { var el = ''; $('#asd input[#type=checkbox]:checked').each(function() { el += $(this).val() + '|'; }); return el; } };
here's the explanation:
im creating a key-value array where it extracts different values from DOM objects. The last array that you see in the example actually tries to extract checked items in a checkbox list. I tried to delegate the loop and return a delimited string of all checked values, but it's not working.
A mapping is probably a better solution here:
var el = $('#asd input:checkbox:checked').map(function(){
return $(this).val();
}).get().join('|');
If I'm understanding your question correctly, the problem you are running up against is that you are merely storing a function in selValues['343'], not evaluating it.
You could try selValues['343'] = function () { var el = ''; $('#asd input[#type=checkbox]:checked').each(function() { el += $(this).val() + '|'; }); return el; } }(); (notice the parentheses at the end) which should evaluate your function and store the result in selValues['343'].
Seems to work for me: http://jsfiddle.net/HM4zD/
I have a div with id="a" that may have any number of classes attached to it, from several groups. Each group has a specific prefix. In the javascript, I don't know which class from the group is on the div. I want to be able to clear all classes with a given prefix and then add a new one. If I want to remove all of the classes that begin with "bg", how do I do that? Something like this, but that actually works:
$("#a").removeClass("bg*");
A regex splitting on word boundary \b isn't the best solution for this:
var prefix = "prefix";
var classes = el.className.split(" ").filter(function(c) {
return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = classes.join(" ").trim();
or as a jQuery mixin:
$.fn.removeClassPrefix = function(prefix) {
this.each(function(i, el) {
var classes = el.className.split(" ").filter(function(c) {
return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = $.trim(classes.join(" "));
});
return this;
};
2018 ES6 Update:
const prefix = "prefix";
const classes = el.className.split(" ").filter(c => !c.startsWith(prefix));
el.className = classes.join(" ").trim();
With jQuery, the actual DOM element is at index zero, this should work
$('#a')[0].className = $('#a')[0].className.replace(/\bbg.*?\b/g, '');
I've written a simple jQuery plugin - alterClass, that does wildcard class removal.
Will optionally add classes too.
$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
You don't need any jQuery specific code to handle this. Just use a RegExp to replace them:
$("#a").className = $("#a").className.replace(/\bbg.*?\b/g, '');
You can modify this to support any prefix but the faster method is above as the RegExp will be compiled only once:
function removeClassByPrefix(el, prefix) {
var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
el.className = el.className.replace(regx, '');
return el;
}
Using 2nd signature of $.fn.removeClass :
// Considering:
var $el = $('<div class=" foo-1 a b foo-2 c foo"/>');
function makeRemoveClassHandler(regex) {
return function (index, classes) {
return classes.split(/\s+/).filter(function (el) {return regex.test(el);}).join(' ');
}
}
$el.removeClass(makeRemoveClassHandler(/^foo-/));
//> [<div class="a b c foo"></div>]
For modern browsers:
let element = $('#a')[0];
let cls = 'bg';
element.classList.remove.apply(element.classList, Array.from(element.classList).filter(v=>v.startsWith(cls)));
An approach I would use using simple jQuery constructs and array handling functions, is to declare an function that takes id of the control and prefix of the class and deleted all classed. The code is attached:
function removeclasses(controlIndex,classPrefix){
var classes = $("#"+controlIndex).attr("class").split(" ");
$.each(classes,function(index) {
if(classes[index].indexOf(classPrefix)==0) {
$("#"+controlIndex).removeClass(classes[index]);
}
});
}
Now this function can be called from anywhere, onclick of button or from code:
removeclasses("a","bg");
http://www.mail-archive.com/jquery-en#googlegroups.com/msg03998.html says:
...and .removeClass() would remove all classes...
It works for me ;)
cheers
I was looking for solution for exactly the same problem. To remove all classes starting with prefix "fontid_" After reading this article I wrote a small plugin which I'm using now.
(function ($) {
$.fn.removePrefixedClasses = function (prefix) {
var classNames = $(this).attr('class').split(' '),
className,
newClassNames = [],
i;
//loop class names
for(i = 0; i < classNames.length; i++) {
className = classNames[i];
// if prefix not found at the beggining of class name
if(className.indexOf(prefix) !== 0) {
newClassNames.push(className);
continue;
}
}
// write new list excluding filtered classNames
$(this).attr('class', newClassNames.join(' '));
};
}(fQuery));
Usage:
$('#elementId').removePrefixedClasses('prefix-of-classes_');
In one line ...
Removes all classes that match a regular expression someRegExp
$('#my_element_id').removeClass( function() { return (this.className.match(/someRegExp/g) || []).join(' ').replace(prog.status.toLowerCase(),'');});
I know it's an old question, but I found out new solution and want to know if it has disadvantages?
$('#a')[0].className = $('#a')[0].className
.replace(/(^|\s)bg.*?(\s|$)/g, ' ')
.replace(/\s\s+/g, ' ')
.replace(/(^\s|\s$)/g, '');
Prestaul's answer was helpful, but it didn't quite work for me. The jQuery way to select an object by id didn't work. I had to use
document.getElementById("a").className
instead of
$("#a").className
I also use hyphen'-' and digits for class name. So my version include '\d-'
$('#a')[0].className = $('#a')[0].className.replace(/\bbg.\d-*?\b/g, '');
(function($)
{
return this.each(function()
{
var classes = $(this).attr('class');
if(!classes || !regex) return false;
var classArray = [];
classes = classes.split(' ');
for(var i=0, len=classes.length; i<len; i++) if(!classes[i].match(regex)) classArray.push(classes[i]);
$(this).attr('class', classArray.join(' '));
});
})(jQuery);
The top answer converted to jQuery for those wanting a jQuery only solution:
const prefix = 'prefix'
const classes = el.attr('class').split(' ').filter(c => !c.startsWith(prefix))
el.attr('class', classes.join(' ').trim())
$("#element").removeAttr("class").addClass("yourClass");