YUI nested selectors - javascript

I am a YUI(AUI) beginner. In jQuery I would do
$(image).find(selector).text();
How can this be achieved in YUI?
AUI().use('event', 'node', function(A) {
var subImages = A.all('.sub_image_conatiner');
for (var i = 0; i < subImages.size(); i++){
var image = subImages.get(i);
//get child elements of image here
}
});

I thought Y.all(foo).all(selector).get('text') would just work but it unfortunately doesn't.
I'd recommend that you use only one selector to match the sub elements:
Y.all('.parent-class .child-class').get('text');
If you can't, then you don't have to iterate through the nodes like a normal JS array. You can use .each().
var texts = [];
Y.all(foo).each(function (node, i) {
texts = texts.concat(node.all(bar).get('text'));
});
console.log(texts);
I'll file a bug with YUI to see if it makes sense to add Y.NodeList.prototype.all

Related

For loop within a for loop? - Javascript

newbie javascript question. I made sure to research as much as I could before posting here, I've tried many solutions but could be searching for the wrong thing.
I've attached an image below of the issue I have. I'm trying to retrieve everything in the dark blue boxes, but I can't identify those input tags as there is nothing unique about them, I can however identify their parent divs by the class 'f-active'. When the divs have that class they have been selected by the user which is what I am interested in.
My attempt so far
var divArray = document.querySelectorAll('div.add-filter.f-active');
var arr = [];
for(var i=0; i < divArray.length; i++){
var childArray = divArray[i].children;
// console.log(childArray);
for(var i=0; i < childArray.length; i++){
if(childArray[i].tagName == "INPUT"){
var catNameCollection = arr.push(childArray[i].name);
// console.log(catNameCollection);
}
}
}
I tried to use a for loop to get all the parents, then use another for loop to select the children (input tags) and then grab the name attribute, however it is just outputing numbers. I did originally try to create 'divArray' as document.querySelectorAll('div.add-filter.f-active').children, but this and then grab the name attribute in the for loop, but this didn't return anything at all.
Any help anyone could offer would be greatly appreciated, I'd love to know what I'm doing wrong.
Thank you!
Your i is same for both loops. Use:
var divArray = document.querySelectorAll('div.add-filter.f-active');
var arr = [];
for(var i=0; i < divArray.length; i++){
var childArray = divArray[i].children;
// console.log(childArray);
for(var k=0; k < childArray.length; k++){
if(childArray[k].tagName == "INPUT"){
var catNameCollection = arr.push(childArray[k].name);
// console.log(catNameCollection);
}
}
}
Classic for-loops usually aren't the best tool for iterating through DOM elements - they add a lot of clutter and are error-prone, especially when you have to nest them.
In your case it'd be simpler to instead modify your query to directly grab all input elements with a div.f-active parent, then extract the names by iterating through them with a forEach. For example (using ES6 or higher):
const arr = [];
// Get list of all <input> elements that have <div> element parents with class f-active.
const nodes = document.querySelectorAll('div.add-filter.f-active > input');
// Extract name from each input element matched by your selector.
nodes.forEach(node => arr.push(node.name));
Or if you're stuck using ES5:
var arr = [];
var nodes = document.querySelectorAll('div.add-filter.f-active > input');
nodes.forEach(function(node) {
arr.push(node.name);
});
Here's a quick JSFiddle I put together to demonstrate the concept for you. (You'll need to open the console to see the result)
Hopefully that helps :)

Better way to create arrays in javascript?

I'm trying to create an array in Javascript with a size that is equivalent to the number of times a certain class is found in the DOM, and then iterate through it to grab the text from an input field present in that class. I can easily do this like so:
var count = 0;
$('.className').each(function() {
count++;
});
var classes = new Array(count);
count = 0;
$('.className input[type=text]').each(function() {
classes[count++] = $(this).val();
});
This looks like a lot of code for what seems to be a relatively simple task. Is there a more efficient or less lengthy way of doing this?
Thanks
It looks like you want this :
var classes = $('.className input[type=text]').map(function(){
return this.value
}).get();
But it's a guess : it's not clear why you start by counting all elements of the class and then iterate on the inputs.
You can construct an array of elements directly from your selector via the makeArray function, then transform the result using a map.
var classes = $.makeArray($('.className input[type=text]')).map(function() {
return $(this).val();
});
Use jQuery's map function, then get if you need a pure array:
var values = $('.className input[type=text]').map(function() {
return $(this).val();
}).get();
each passes the index, so you don't need to do it yourself:
var classes = [];
$('.className input[type=text]').each(function(index, value) {
classes[index] = $(this).val();
});
Arrays are dynamic and therefore don't need to be initialized. Create a new array, loop through the inputs and push the values to the new array:
var classes = [];
$('.className input[type=text]').each(function(idx, elem) {
classes.push($(elem).val());
});

How to get all HTML attributes which start with something (the attribute names, *not* their values!)

I would like to get all the elements/nodes in an HTML page which contain attributes that start with something (again, the attribute names start with something, not their values!). For example, TinyMCE has a tendency of adding custom attributes to the elements it saves, like "mce_style", "mce_href", "mce_bogus", etc. I would like to have something like the CSS3 selector for attribute values, [attr^="mce_"], but not for the values, the attribute names.
Of course, I can iterate through all DOM nodes and their attributes and check them one by one, but I was wondering whether there is a more efficient way.
Please don't give me TinyMCE-specific answers, I'm pretty sure there's a flag which would prevent TinyMCE for saving these attributes, but the question is generic.
here's a simple demo to find all elements that contain an attribute starting with mce_. might need some refinements.
function getMCE() {
var el, attr, i, j, arr = [],
reg = new RegExp('^mce_', 'i'), //case insensitive mce_ pattern
els = document.body.getElementsByTagName('*'); //get all tags in body
for (i = 0; i < els.length; i++) { //loop through all tags
el = els[i] //our current element
attr = el.attributes; //its attributes
dance: for (j = 0; j < attr.length; j++) { //loop through all attributes
if (reg.test(attr[j].name)) { //if an attribute starts with mce_
arr.push(el); //push to collection
break dance; //break this loop
}
}
}
return arr;
}
console.log(getMCE())​
Try this:
FUNCTIONS
//custom selector expression
$.extend($.expr[':'],{
attr:function(o,i,m){
var attrs=$.getAttrAll(o),re=m[3],found=false;
$.each(attrs,function(k,v){
if(new RegExp(re).test(v)) { return found=true;}
});
return found;
}
});
// get all atrributes of an element
$.getAttrAll=function(el){
var rect = [];
for (var i=0, attrs=el.attributes, len=attrs.length; i<len; i++){
rect.push(attrs.item(i).nodeName);
}
return rect;
};
`
USAGE
// calling custom selector expression :attr(regexp)
$(function(){
$('body').find(':attr("^mce_")').css({background:'yellow'});
});
HTML
<body>
<p mce_style="height:50px" id="x" data-hello="hello">selected</p>
<div not_mce_bogus="abc">not_mce_bogus</div>
<div mce_href="http://rahenrangan.com">selected</div>
<p>othrs</p>
</body>
One option, if you don't mind temporarily altering your DOM, is to extract your HTML into a string and search for the attributes via RegExp. When you find the attributes, you could append a "needle" in the DOM so that you can use jQuery to select the elements.
Here is a working concept (run with console open):
http://jsfiddle.net/skylar/N43Bm/
Code:
$.fn.extend({
findAttributes: function(attribute) {
var attributeFinder = new RegExp(attribute + '(.+)="', "gi");
var elementHTML = this.html().replace(attributeFinder, "data-needle='pin' "+attribute+"$1=\"");
this.html(elementHTML);
return this.find("[data-needle=pin]").removeAttr('data-needle');
}
});
console.log($("body").findAttributes('mce_'));
Note: my regexp is not great. You'll have to take better care than I have in this example.
Try this: (I tried putting * instead of a tag but it colored all the elements including those who do not have mce_style attribute as well)
a[mce_style] { color : red; }​
Demo : http://jsfiddle.net/Tcdmb/
More info : https://developer.mozilla.org/en/CSS/Attribute_selectors

Using .attr() with .get() Issues

I am trying to store an array of objects in an array by going through each paragraph element in a div container with the .get() method. I try to access the attribute with .attr() but it doesn't seem to work. How would I modify this code in order to be able to access the 'id' attribute of each message?
var messages = $("#message_container p").get();
var idstest = [];
for (int i = 0; i < messages.length; i++){
idstest.push(messages[i].attr("id"));
}
I think it has to do with some fundamental incompatibility with .get() and .attr(). When I 'alert' the objects provided by .get() I get [object HTML---]. I'm assuming that is not the form necessary in order to use .attr?
get will give you the DOM element. These are NOT jquery objects so you can't use attr on them. There's no reason to use get at all here.
var messages = $("#message_container p");
var idstest = [];
messages.each(function(){
idstest.push($(this).attr("id"));
});
http://jsfiddle.net/ujdeH/
EDIT: You also can't use int.
If for some reason you did want to use get to get the raw DOM elements, you would then just use .id:
http://jsfiddle.net/ujdeH/1/
var messages = $("#message_container p").get();
var idstest = [];
for (var i = 0; i < messages.length; i++) {
idstest.push(messages[i].id);
}
try instead:
var idstest = [];
$("#message_container p").each(function(i){
idstest.push($(this).attr("id"));
});
Just wanted to add the $.map shortcut: http://jsfiddle.net/UuWq3/.
var idstest = $.map(messages, function(elem) {
return $(elem).attr("id");
});
$.map returns a new array based on the original array (or jQuery object). The array returned is constructed with the function you pass (in this case, messages is transformed by the function such that each element is replaced with it's ID).
You should wrap the object in jQuery container:
$(messages[i]).attr("id")
Actually no need for jQuery here, this pure JavaScript will work just fine on all browsers:
var idstest = [];
var container = document.getElementById("message_container");
if (container) {
var messages = container.getElementsByTagName("p");
for (var i = 0; i < messages.length; i++) {
idstest.push(messages[i].id);
}
}
jQuery is all good and powerful, but if you can achieve the same task with short/easy enough pure JS then why not?
This said, if all your existing code is jQuery then you might be better off sticking with it (using the code from other correct answers here) just for sake of consistency and readability.

Is there a way to loop through all fields in a fieldset?

I would like to change the class for all the fields in a specific fieldset.
Is there a way to loop through the fields in a fieldset?
You can use getElementsByTagName.
var fieldset= document.getElementById('something');
var fieldtags= ['input', 'textarea', 'select', 'button'];
for (var tagi= fieldtags.length; tagi-->0) {
var fields= fieldset.getElementsByTagName(fieldtags[tagi]);
for (var fieldi= fields.length; fieldi-->0;) {
fields[fieldi].className= 'hello';
}
}
(If you only care about input fields, you could lose the outer tag loop.)
If you needed them in document order (rather than grouped by tag) you'd have to walk over the elements manually, which will be a pain and a bit slow. You could use fieldset.querySelectorAll('input, textarea, select, button'), but not all browsers support that yet. (In particular, IE6-7 predate it.)
Using jQuery (yay!):
$('#fieldset-id :input').each(function(index,element) {
//element is the specific field:
$(element).doSomething();
});
Note the solution below is for NON-JQUERY Implementations.
Implement a getElementsByClassName Method like this:
After you implement the code below you can then use document.getElementsByClassName("elementsInFieldSetClass") it will return an array of the elements with that class.
function initializeGetElementsByClassName ()
{
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
window.onload = function () {
initializeGetElementsByClassName();
};
Another jQuery solution here.
If you are simply adding a class(es) to the elements, it's this simple:
$('fieldset :input').addClass('newClass');
.addClass() (like many other jQuery functions) will work on all of the elements that match the selector.
Example: http://jsfiddle.net/HANSG/8/
Permanently? Find & replace in your editor of choice.
When the user clicks something? jQuery way:
$('fieldset <selector>').each(function() {
$(this).removeClass('old').addClass('new');
});

Categories