I'm working on a challenge that requires us to use Underscore and JQuery to make changes to the DOM, but the second part of the challenge is requiring us to use Javascript browser utilities to do the same thing.
We are given an Array, and asked to manipulate the data and append the result to the DOM. I did that using the _.each method and $().append. For the second part, I am using the Javascript forEach() method to manipulate the data, but how do I use javascript utilities to append the resulting variable to the DOM with without jQuery?
Select the container, iterate the array with a for loop or forEach method, create elements and append them.
var arr = ["Alice", "Bob"]
var ulEl = document.querySelector("ul");
for (var i = 0; i < arr.length; ++i) {
var li = document.createElement("li");
li.innerHTML = arr[i];
ulEl.appendChild(li);
}
<ul>
</ul>
Instead of using the jQuery library, its possible to manipulate the DOM using vanilla JavaScript functions. In particular, take a look at some of the functions in the DOM API like document.querySelector
Related
Honestly, I don't know where to start with "extracting." My best guess would be to use the basic .html() tag from JQuery to solve this problem. This is for a small project to improve my JavaScript skills. Any ideas on how this could be done? Thanks so much...
I apologize for being unclear. I meant extracting all the links from a particular page from a domain I don't own. Then, putting these links into an array. Thanks!
Well, this comes to mind ?
var arr = [].slice.call( document.querySelectorAll('a') );
It gets all the matching elements with querySelectorAll, and converts the returned nodeList to an array using [].slice.call, where [] is a shortcut for Array.prototype. In other words it calls the native Array.slice method with call(), passing the elements in as the this value, effectively creating an array from the elements.
if you need the HTML, and not the DOM elements, you can map the elements array and return the outerHTML
var markup = arr.map(function(elem) { return elem.outerHTML; });
or if you just need the URL's, you can run the same map and return the href attribute instead
var urls = arr.map(function(elem) { return elem.getAttribute('href'); });
You don't necessarily need jQuery for this and if learning Javascript is your goal you might be better off without using it for now. querySelectorAll is available in all modern browsers and can accomplish what you are looking for. Per the documentation:
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
A NodeList is not an array however so you would need to do a little extra work to make an array of the link elements. You can read in the documentation why they are different.
The selectors used in the method are CSS Selectors and you can checkout the documentation for querySelector for examples.
So to do what you want you could do something like:
var a_list = document.querySelectorAll('a'); // returns NodeList
var a_array = Array.prototype.slice.call(a_list); // converts NodeList to Array
If the jQuery is an acceptable option, you can get all the links by a simple
var links = $('a[href]');
The "links" is an array already.
I would also fiddle around with something like this.
Array.prototype.slice.call(document.querySelectorAll('a'));
Googling it would be a good start so you can learn more about how it works and use it to your advantage.
I am learning to avoid duplicated dom queries. Recommendation so far is to save the initial query into a variable and then re-use that variable as needed.
Question:
If I save the following into a variable:
var mylist = $("ul.mylist");
Will the following make another dom query?
mylist.find("li:first");
Or will it just search within that variable?
If so, is there a better way to do it? that it would avoid another query?
Yes, it will do another "dom query". To only have 1 look-up you can save the list item node jQuery wrapper in the variable
var mylist = $("ul.mylist li:first");
Or, you can manually search within the DOM properties of the unordered list, but jQuery, I believe, won't do this for you, using the .find() method.
var mylist = $("ul.mylist");
myList[0].children[0];
// or using jquery
myList.first();
With jquery, I've got the following code:
$('a[data-hello]').click(function(){ = That select all "a" elements with "data-hello".
I'm trying to make this with raw Javascript. I stop here:
document.querySelectorAll("data-hello").onclick = function() {
(btw, theres a way to select all the A elements with data-hello and not all with data-hello? o.O)
But querySelectorAll returns a Array. Because of this, it only works if I determine a position. This way:
document.querySelectorAll("data-hello")[5].onclick = function() {
But I want ALL ELEMENTS, not specific elements, like with jQuery. I cant use jQuery.
It is so simple with Jquery :( I must make a "for" to wade through all the positions in JS? Is this necessary? sorry I do not understand...
What I want to do:
I want to get the data attribute value of the element that is clicked. I use this for this inside the function and, then, I applied another function that add a class in a specific element.
Basically, there is buttons with classes in data attribute value. This classes will be applied to a specific element.
Put the array (actually a NodeList) of elements in a variable and loop through them to set the event handler on each of them. That's what the jQuery methods do to apply something to all elements in a jQuery object. There is no way around the loop, with jQuery it's just hidden within the methods. You can use the same selector syntax as in jQuery with querySelectorAll.
var arr = document.querySelectorAll("a[data-hello]");
var f = function() {
// do something
};
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = f;
}
querySelectorAll accepts a string of comma-separated CSS selectors, just like jQuery, so you can give it the same string: 'a[data-hello]'.
The difference between native and jQuery that you are running into is in calling methods on the elements returned. jQuery returns a jQuery object, which has methods that often loop over all the elements, .click() being one such methods. You need to replicate that with the array of elements that querySelectorAll is returning by looping over the array and applying the same handler to each element's onclick property.
Try this:
var myElements = document.querySelectorAll("a[data-hello]");
Array.prototype.forEach.call(myElements, function (element) {
element.onclick = function () {
// Your onclick handler code goes here.
console.log('clicked', element);
};
});
as simple as that:
var dataElems = document.querySelectorAll("[data-hello]")
for (var i=0;i<dataElems.length;i++) {
dataElems[i].onclick = function(i,v) {
alert(this.innerHTML)
}
}
example http://jsfiddle.net/acrashik/W86k8/
Hopefully I can explain it well enough. I do
var foo = document.getElementsByTagName('bar');
var len = foo.length;
for(var i=0;i<len;i++){
//Do stuff
}
Inside that for I also want to be able to get an element (specifically a class) that is buried deep within foo[i]. My thought is something like
var whatIWant = document.getElementsByClassName("name").foo[i];
but that doesn't seem to be what I need to do. Am I just not sure on the syntax or do I need to do something completely different?
You've almost got it:
foo = document.getElementsByTagName('bar');
// foo is now a nodelist of all nodes named 'bar'.
for (i = 0; i < foo.length; i++) {
bar = foo[i].getElementsByClassName('baz');
// bar is now a nodelist of all elements with class 'baz' in the dom tree under foo[i].
}
If you were using jquery, it'd be as simple as:
$('bar .baz').each(function() {
$(this). etc...;
});
As far as I'm aware getElementsByClassName is HTML5 (according to this: https://developer.mozilla.org/en/DOM/document.getElementsByClassName) and so using it means that not all browser will support it.
When you grab an Element from the dom, like with document.getElementsByTagName, you get the same method getElementsByTagName and so you can do:
foo[i].getElementsByTagName("...")
For the collection of desired elements, then you can iterate over that array and search for the matching classes.
Also, I recommend using javascript libraries such as jQuery or MooTools, it will make your life easier.
Relevant discussion.
I understand I can build an array of references to elements/nodes. I realize also that I could use the neat trick of treating an array like a heap (index 2n and 2n+1 for children) to build a (potentially wasteful) binary search tree using it.
But all that's still not enough for the premature optimizer in me. Besides, implementing a BST is going to be bug prone.
Here's my question. Can I somehow use an element reference as index into javascript's hashes (which are objects, or vice versa?). If not, can I conjure up a unique string from an element reference, which I can then use as my hash key? If not, how the hell does jQuery do it?
The easiest option is to just use your own attribute on the DOM object:
var element = document.getElementById("test");
element.myData = "whatever";
Here's the general idea behind how jQuery's .data() function works that you could use in your own plain javascript. It uses one custom attribute on the object and then stores everything else in a data structure indexed by the value of that custom attribute.
var idCntr = 0; // global cntr
var data = {};
var element = document.getElementById("test");
var id = element.uniqueID;
if (!id) {
id = idCntr++ + "";
element.uniqueID = id;
}
data[id] = "whatever";
// then some time later, you can do this
var element = document.getElementById("test");
console.log(data[element.uniqueID]); // whatever
It is a bit more involved to store multiple attributes for a given object in the data object, but this is the general idea.
And, if you can use jQuery, it's trivial:
$("#test").data("myData", "whatever"); // sets the data
console.log($("#test").data("myData")); // retrieves the data
If you want to really see how jQuery's .data() works, you can step through the first call to set data and then retrieve it when using the unminified jQuery. It's easy to see what it does.