For example, my element is a DOM element div, and within it are other divs.
So I generally use elem.querySelector('.whatever') to find a child within it. But I'd like to rename querySelector to find.
But how can I do this for all DOM elements, is there an easy way? I'd rather not just have "function find(elem, what)", but rather I'd like to do it on the element itself so "elem.find('.whatever')"
You can create a function to achieve the same thing, but will give extra work to the browser
HTMLElement.prototype.find = function(selector){
//or querySelector for one element depends on need
return this.querySelectorAll(selector);
};
elem.find('.whatever');
Warning! Modifying the core prototype is a bad practice.
Another solution from "connexo"
HTMLElement.prototype.find = HTMLElement.prototype.querySelector
You can also create your own version of "jquery" if you are afraid of modifying the core prototype
function $$(element) {
return {
find: function(selector) {
return element.querySelectorAll(selector);
}
}
}
//then just wrap any object
$$(elem).find(selector);
I almost always use the global document.querySelector form, and it's definitely too verbose for my taste.
While not exactly an alias, I really like this simple solution:
function get (selector, context=document) {
return context.querySelector(selector)
}
function getAll (selector, context=document) {
return context.querySelectorAll(selector)
}
// get single element
get("#id")
// get all elements
getAll("nav li")
// all within an element
getAll("li", element)
Related
I am trying to create a function like the function of jQuery which changes the style of an HTMLElement, probably you have seen it somewhere:
$("button").css("color", "red");
which is pretty handy, so here is what I've tried:
function $(selector, parent=document){
return parent.querySelector(selector);
}
so the above code is the code of the function $ which grabs an HTMLElement from the DOM,this seems to work perfectly.
Now, the next step for me is to define the $ function methods and properties, so the method I want to create is the css method as seen in the previous example:
$.css = function(style, value){
this[style] = value;
}
now after testing the css method it's not working (and of course it will never work, but I'm just trying to deliver my question idea for you).
I know a lot about object-oriented programming in JavaScript, I am comfortable with it, so I have no problem if you posted any answer, I will try my best to understand it.
I've tried a lot to understand what's the magic that the jQuery developers made to create this method.
What do you think the best approach to make it? what about mixins, what if I wanted other functions and not just "$" to inherit this "css" method?
To modify styles, you need to set a CSS property of the style declaration object of an element. For example:
elm.style.color = 'red';
You need to modify your $.css to access the current element(s) in the collection, and access their .style[propertyName] property.
You can put the collection onto a property of the instance, and make sure to put the css method as a prototype of the class:
function collection (selector, parent = document) {
this.elms = parent.querySelectorAll(selector);
}
collection.prototype.css = function(prop, value) {
for (const elm of this.elms) {
elm.style[prop] = value;
}
}
const $ = (...args) => new collection(...args);
$("button").css("color", "red");
<button>a button</button>
<button>a button</button>
Because your $ doesn't use new, you'll either need it to return an instance of a different class (as in the code above), or always use new when calling it, or have $ return its instance created via Object.create, or something like that. There are various methods.
Not sure if this is what you're after, but you could just apply the style inline?
var elem = document.querySelector('#some-element');
//set color to red
elem.style.color = 'red';
//set the background color to a light gray
elem.style.backgroundColor = '#e5e5e5';
//set the height to 225px
elem.style.height = '225px';
Seemingly-easy problem here: I'm trying to create a streamlined way to hide/show a collection of DOM elements using some jQuery/vanilla JS. This was from a refactor where several fragmented functions were re-done as better encapsulated versions of their former selves.
What these functions are trying to do take elements from an array (by ID), use map to convert them to jQuery objects, and then hide or show them.
Using jQuery 1.11 in an Angular project, but the angular aspect doesn't seem to interfere with this case, since it won't work in a jsFiddle either.
main problem: When I run the function (usually using a click event), I don't get any sort of error from console and I don't get any sort of result in the DOM either. Any ideas? I'm sure it's a simple thing I'm missing, but I need other eyes on it.
Here's a jsFiddle with the below code loaded in, ready for fixin'. Thanks!
http://jsfiddle.net/sLgqvdku/
function showItem(item) {
return item.show();
}
function hideItem(item) {
return item.hide();
}
function showItemsWithIDs(ids) {
ids.map($).forEach(showItem);
}
function hideItemsWithIDs(ids) {
ids.map($).forEach(hideItem);
}
var itemsHiddenToFocusTribute = ['#form', '#ask', "#submitButton", "#sidebar", "#AmountCtrl", "#giftbutton"];
It appears that only the first element in the array is actually being converted into a jQuery object in your code.
Here's what's happening: vanilla-JS .map passes three arguments to the specified callback function: the current element, the index, and the array.
If the callback function takes only one argument, the second and third are ignored. However, jQuery's $ actually allows two arguments: a selector, and a context (container element). So your code is passing (as the second argument) the array index as a context, resulting in an empty jQuery object -- except for the first element in itemsHiddenToFocusTribute, which has index 0 which is interpreted as no context at all.
You can fix this with an anonymous function that only passes the selector string to $:
function hideItemsWithIDs(ids) {
ids.map(function (i) {
return $(i);
}).forEach(hideItem);
}
http://jsfiddle.net/mblase75/e23qgad5/
However, a more jQuery-friendly way would be to create a single jQuery object of all the desired elements and loop through them using .each:
function hideItem(i,item) {
return $(item).hide();
}
function hideItemsWithIDs(ids) {
$(ids.join()).each(hideItem);
}
http://jsfiddle.net/mblase75/mm2L4xn1/
This is probably more efficient, too, since you're calling $ just once instead of array.length times.
All you're wanting is to send each id through the foreach loop? Then I'd just use each like so:
$(ids).each(function(index, id) {
hideItem(id);
});
You don't need to use map($) to convert them to jQuery objects, just put the object inside the dollar sign function call, like so: $(ids).
Also make sure you pass the actual id to showItem and hideItem when you call them, like so: hideItem(id). You also need to make sure that you use a jQuery object in your hideItem and showItem functions. I changed your code to this:
function showItem(item) {
return $(item).show();
}
function hideItem(item) {
return $(item).hide();
}
function showItemsWithIDs(ids) {
$(ids).each(function(index, id) {
showItem(id);
});
}
function hideItemsWithIDs(ids) {
$(ids).each(function(index, id) {
hideItem(id);
});
}
var itemsHiddenToFocusTribute = ['#form', '#ask', "#submitButton", "#sidebar", "#AmountCtrl", "#giftbutton"];
$('#clicker').click(function(){
hideItemsWithIDs(itemsHiddenToFocusTribute);
});
And here's the updated Fiddle
I have an application that has this format scattered around but I dont know what kind it is. It's not jQuery, so what is it?
$('some_edit').style.display = "block";
$('some_views').style.display = "none";
I get this in firebug and I know the element is present:
$("some_edit").style is undefined
It could be many things - examine the source code (or use Firebug) and see what JS libraries are being loaded.
A lot of people have defined the '$' symbol as a substitute for document.getElementById().
Basically:
function $(id) { return document.getElementById(id); }
$("ElementID").innerHTML = "Text"; //Usage
A more proper, "namespace" example:
var DOM = { // creating the namespace "DOM"
$: (function() {
if(document.getElementById)
return function(id){ return document.getElementById(id); }
else if(document.all)
return function(id) { return document.all[id]; }
else
return function(id) { /* I don't even want to get into document.layers */ }
})()
};
// Later in the code:
{
function ExampleFunction() {
// ...
DOM.$("ElementID").style.backgroundColor = "#96d0a0"; // a nice minty green color
// ...
}
}
I have used a self-invocation pattern (function(){ ... }()) in this example.
at first i thought the jquery selector would likely have been $("#some_edit") and then .css(). so I would have said, prototype or mootools or a home brew $.
you can certainly discount both mootools and prototype, because if the selector returns an object, then the style property will be available (ignoring best practices in both frameworks on setting styles).
this leaves, the site uses homebrew $ assignment or jquery, which is not being used correctly.
actually, $("foo").style.blah in jquery will produce this very exception (even if the selector was good) - here is jsfiddle to the rescue
case point jquery (triggers):
http://www.jsfiddle.net/dimitar/vmsZn/
case point prototype (works):
http://www.jsfiddle.net/dimitar/vmsZn/1/
case point mootools (works):
http://www.jsfiddle.net/dimitar/vmsZn/2/
It is setting the display style for the two page elements - the display property specifies the type of box an element should generate.
block = The element will generate a block box (a line break before and after the element)
none = The element will generate no box at all
Put a [0] in front of $('some_views') to return the Native DOM Element.
$('some_views')[0].style.display = "none";
or $('some_views').get(0).style.display = "none";
or $('some_views').css('display', 'none') to iterate through the collection of DOM elements.
It's JQuery -- uses $ as its key variable.
Added:
Could also be mootools. Also uses $
Added:
'some_edit' would be the id of an element.
ps. I agree $ could be anything. Odds are though that it is JQuery or Mootools. "When you hear hoof beats, think horses, not zebras."
I'm trying to pass "this" from a clicked span to a jQuery function that can then execute jQuery on that clicked element's first child. Can't seem to get it right...
<p onclick="toggleSection($(this));"><span class="redClass"></span></p>
Javascript:
function toggleSection(element) {
element.toggleClass("redClass");
}
How do I reference the :first-child of element?
If you want to apply a selector to the context provided by an existing jQuery set, try the find() function:
element.find(">:first-child").toggleClass("redClass");
Jørn Schou-Rode noted that you probably only want to find the first direct descendant of the context element, hence the child selector (>). He also points out that you could just as well use the children() function, which is very similar to find() but only searches one level deep in the hierarchy (which is all you need...):
element.children(":first").toggleClass("redClass");
Use the children function with the :first selector to get the single first child of element:
element.children(":first").toggleClass("redClass");
I've added jsperf test to see the speed difference for different approaches to get the first child (total 1000+ children)
given, notif = $('#foo')
jQuery ways:
$(":first-child", notif) - 4,304 ops/sec - fastest
notif.children(":first") - 653 ops/sec - 85% slower
notif.children()[0] - 1,416 ops/sec - 67% slower
Native ways:
JavaScript native' ele.firstChild - 4,934,323 ops/sec (all the above approaches are 100% slower compared to firstChild)
Native DOM ele from jQery: notif[0].firstChild - 4,913,658 ops/sec
So, first 3 jQuery approaches are not recommended, at least for first-child (I doubt that would be the case with many other too). If you have a jQuery object and need to get the first-child, then get the native DOM element from the jQuery object, using array reference [0] (recommended) or .get(0) and use the ele.firstChild. This gives the same identical results as regular JavaScript usage.
all tests are done in Chrome Canary build v15.0.854.0
element.children().first();
Find all children and get first of them.
you can use DOM
$(this).children().first()
// is equivalent to
$(this.firstChild)
Have you tried
$(":first-child", element).toggleClass("redClass");
I think you want to set your element as a context for your search. There might be a better way to do this which some other jQuery guru will hop in here and throw out at you :)
I've just written a plugin which uses .firstElementChild if possible, and falls back to iterating over each individual node if necessary:
(function ($) {
var useElementChild = ('firstElementChild' in document.createElement('div'));
$.fn.firstChild = function () {
return this.map(function() {
if (useElementChild) {
return this.firstElementChild;
} else {
var node = this.firstChild;
while (node) {
if (node.type === 1) {
break;
}
node = node.nextSibling;
}
return node;
}
});
};
})(jQuery);
It's not as fast as a pure DOM solution, but in jsperf tests under Chrome 24 it was a couple of orders of magnitude faster than any other jQuery selector-based method.
please use it like this
first thing give a class name to tag p like "myp"
then on use the following code
$(document).ready(function() {
$(".myp").click(function() {
$(this).children(":first").toggleClass("classname"); // this will access the span.
})
})
This can be done with a simple magic like this:
$(":first-child", element).toggleClass("redClass");
Reference: http://www.snoopcode.com/jquery/jquery-first-child-selector
i am using
$('.txt').first().css('display', 'none');
If you want immediate first child you need
$(element).first();
If you want particular first element in the dom from your element then use below
var spanElement = $(elementId).find(".redClass :first");
$(spanElement).addClass("yourClassHere");
try out : http://jsfiddle.net/vgGbc/2/
Let's say I'm generating markup through server-side code. I'm generating a bunch of HTML tags but I want to add custom client-side behavior.
With JavaScript (if I had a reference to the DOM node) I could have written:
var myDOMNode = ...
myDOMNode.myCustomAttribute = "Hi!";
Now the issue here is that I don't want to qualify every element with an unique id just to initialize data. And it's really strange to me, that there's not an easier and unobtrusive way to attach client-side behavior.
If I'm remembing this correctly, this is valid IE stuff.
<div onload="this.myCustomAttribute='Hi!'"></div>
If I was able to do this, I should be able to access it's "data context" though the identifier 'myCustomAttribute', which is really what I want.
The following will work but not validate:
<div myattribute="myvalue"></div>
But if you are injecting it into the HTML with Javascript, then perhaps that's not concern for you. Otherwise, you can use something like jQuery to process the elements before adding them to the DOM:
$(elements).each(function(){
$(this).attr('myattribute','myvalue');
});
First off you should access custom attributes using the getAttribute and setAttribute methods if you want your code to work on other browsers than IE.
As to your event handler question that really depends on how you add the event handler.
Assigning a function directly to the elements onXXXX property would allow you access the the element via this.
If you use IE's attachEvent you can't use this, you can access the element that generated the event using event.srcElementbut that may be child element of the div. Hence you will need to test for the existance of myCustomAttribute and search up the ancestors until you find it.
I do appricate the input but I've finally figured this out and it's the way I go about initialization that has been the thorn in my side.
What you never wan't do is to pollute your global namespace with a bunch of short lived identifiers. Any time you put id="" on an element you're doing exactly that (same thing for any top level function). By relying on jQuery, HTML5 data and CSS there's a solution to my problem which I think is quite elegant.
What I do is that I reserve a CSS class for a specific behavior and then use HTML5 data to parameterize the behavior. When the document is ready, I query the document (using Query) for the CSS class that represents the behavior and initialize the client-side behavior.
I've been doing a lot of ASP.NET and within this context both the id="" and name="" belongs to ASP.NET and is pretty useless for anything else than internal ASP.NET stuff. What you typically find yourself doing is to get at a server-side property called ClientID you can refer to this from client-side JavaScript, it's a lot of hassle. They made it easier in 4.0 but fundamentally I think it's pretty much broken.
Using this hybrid of CSS, HTML5 data and jQuery solves this problem altogether. Here's an example of an attached behavior that uses regular expressions to validate the input of a textbox.
<input type="text" class="-input-regex" data-regex="^[a-z]+$" />
And here's the script:
$(function () {
function checkRegex(inp) {
if (inp.data("regex").test(inp.val()))
inp.data("good-value", inp.val());
else
inp.val(inp.data("good-value"));
}
$(".-input-regex")
.each(function () {
// starting with jQuery 1.5
// you can get at HTML5 data like this
var inp = $(this);
var pattern = inp.data("regex");
inp.data("regex", new RegExp(pattern));
checkRegex(inp);
})
.keyup(function (e) {
checkRegex($(this));
})
.change(function (e) {
checkRegex($(this));
})
.bind("paste", undefined, function (e) {
checkRegex($(this));
})
;
});
Totally clean, no funky id="" or obtrusive dependency.
In HTML5 there are HTML5 data attributes introduced exactly for the case.
<!DOCTYPE html>
<div data-my-custom-attribute='Hi!'></div>
is now corect, validating html. You can use any name starting with data- in any quantity.
There is jQuery .data method for interaction with them. Use .data( key ) to get, .data(key, value) to set data-key attribute. For example,
$('div').each(function () {
$(this).html($(this).data('myCustomAttribute')).data('processed', 'OK');
});
How about this?
<script>
function LoadElement(myDiv)
{
alert(this.myCustomAttribute);
}
</script>
<div onload="LoadElement(this)"></div>
not tested btw
Since you're trying to do this for multiple elements, you may try name attributes and getElementsByName.
<div name="handleonload">...</div>
window.onload = function () {
var divs = document.getElementsByName('handleonload');
for (var i = 0; i < divs.length; i += 1) {
divs[i].foo = 'bar';
}
};
Alternatively, you can use selectors, using libraries (such as jQuery and Prototype) and their respective iterators. This will also allow for you to search by other attributes (such as class).
Though, be cautious with your terminology:
obj.property = value;
<tag attribute="value">
<div style="width:100px;height:100px;border:solid black 1px" myCustomAttribute='Hi!' onclick="alert(myCustomAttribute);"></div>
The onload event is used for server side events. Its not part of the standard html element events.
Take a look at the following functions (especially the walk_the_dom one):
// walk_the_DOM visits every node of the tree in HTML source order, starting
// from some given node. It invokes a function,
// passing it each node in turn. walk_the_DOM calls
// itself to process each of the child nodes.
var walk_the_DOM = function walk(node, func) {
func(node);
node = node.firstChild;
while (node) {
walk(node, func);
node = node.nextSibling;
}
};
// getElementsByAttribute takes an attribute name string and an optional
// matching value. It calls walk_the_DOM, passing it a
// function that looks for an attribute name in the
// node. The matching nodes are accumulated in a
// results array.
var getElementsByAttribute = function (att, value) {
var results = [];
walk_the_DOM(document.body, function (node) {
var actual = node.nodeType === 1 && node.getAttribute(att);
if (typeof actual === 'string' &&
(actual === value || typeof value !== 'string')) {
results.push(node);
}
});
return results;
};
With the above two functions at hand, now we can do something like this:
some link
<script>
var els = getElementsByAttribute('dreas');
if (els.length > 0) {
els[0].innerHTML = 'changed text';
}
</script>
Notice how now I am making finding that particular element (which has an attribute called dreas) without using an id or a class name...or even a tag name
Looks like jQuery is the best bet for this one based on my searching. You can bind an object to a DOM node by:
var domNode = ...
var myObject = { ... }
$(domNode).data('mydata', mymyObj);
then you can call the data back up the same way, using your key.
var myObect = $(domNode).data('mydata');
I assume you could also store a reference to this within this object, but that may be more info then you really want. Hope I could help.