I want to edit some HTML I get from a var I saved. like:
var testhtml = $('.agenda-rename').html();
console.log($('input',testhtml).attr('name'));
Also tried
console.log($(testhtml).find('input').attr('name'));
But i get undefined? I figured it'd work like an $.ajax, $.get, $.post? How else can i do it?
When you call .html(), you're only getting the content, not the .agenda-rename. So if the input is a direct child of .agenda-rename, then .find() won't be able to find it.
Probably better just to do without the .html() call:
var testhtml = $('.agenda-rename').clone(); // or .clone(true)
console.log($('input',testhtml).attr('name'));
Now you have the .agenda-rename element(s) and you'll be able to search for elements nested inside it/them.
EDIT: Based on comment, OP doesn't want to modify the original. As such, .clone() can be used. Answer above has been edited to reflect change.
If events are attached that should be retained, then you use .clone(true).
EDIT: The reason $('input',testhtml) and $(testhtml).find('input') give the same result is that they are actually the same thing.
jQuery converts the first version into the second behind the scenes. As such it is technically a little more efficient to use the second than the first.
Here's the code where jQuery makes the switch (after running a bunch of other tests to determine what it was passed).
http://github.com/jquery/jquery/blob/master/src/core.js#L150
Related
Edit: Everyone went on all kinds of tangents, but the question remains - how do I get an attribute of an html element inside an angular controller?
Here is a plnkr attempt: http://plnkr.co/edit/0VMeFAMEnc0XeQWJiLHm?p=preview
//$scope.myElem = angular.element('testDiv'); //this breaks angular
$scope.myElem = $document.find('testDiv'); //this doesn't break angular, but unclear what it returns
$scope.myAttr = $scope.myElem.name; //this returns nothing
If you need convincing that this is actually necessary - I need to find when a user scrolls through a div, as is shown here: http://jsfiddle.net/rs3prkfm/ Note that this has nothing to do with the question, simply a scenario. The question is simple - how do I get an attribute's value?
References:
Useless official docs: https://docs.angularjs.org/api/ng/function/angular.element
The only useful link that still doesn't work: http://mlen.io/angular-js/get-element-by-id.html
You could use the element api https://docs.angularjs.org/api/ng/function/angular.element
There should be only very few occasions where you would really need it, though.
You should manipulate the DOM using directives. The controller should only manipulate the data of the application and offer it to the html.
If you have direct manipulation on the Controller you can't, for example, bind several views to the controller. Also, if you change the id of one tag in the html and you are manipuling it directly in you controller, the controller will break.
Read this:
http://ng-learn.org/2014/01/Dom-Manipulations/
Hope it helps.
Use angular.element:
var myElem = angular.element("#testDiv"); // here you get your div
var myAttr = myElem.attr("name"); // you get: "testDiv"
Remember you have limitations using jqlite. If you want full functionallity of jquery element, import a full "jquery.js" before importing your angular script.
However, to manipulate the DOM you SHOULD use directives as stated by most of the answers.
I need some help in converting a javascrpipt function into jQuery. Below is my original JS code:
var text = document.getElementsByTagName("pre")[0].innerHTML;
After a little research on Stack I was able to come up with this equivalent:
var text = $(data).$('pre')[0].html();
Where data is the data I receive in a $.get request, like below.
$.get (
mypage,
function parse(data) {
var raw = $(data).$('pre')[0].html();
}
);
But that doesn't seem to work and i'm not very good with jQuery.
Granted that data holds HTML, $(data).find('pre').eq(0).html() should do.
To get the first element with tag pre from data you can do the following in jQuery,
$('pre',data).eq(0).html();
http://api.jquery.com/jquery/#jQuery-selector-context
The reason $(data).$('pre')[0].html(); doesn't work is that the [0] part extracts the first found element as a DOM element, not a jQuery object, so invoking .html() fails.
Others have already pointed out the solution. .eq(0) gets the first element as a jQuery object (per moonwave99 and melc's answers), and that's why you can then call .html() on it.
For further reading on the difference, see: jQuery object and DOM element
I have started to convert a code on my site to jquery from mootols I would like to include jQuery instead of mootools and then write some functions I'm using in mootools to jQuery so I can use the exact same code. Some of the code I'm using I already converted is for example:
jQuery.fn.addEvent = jQuery.fn.bind;
However I'm having a hard time doing these:
$some_node.getElement('.class'); //where $some_node is an element like $(.selector);
$some_node.addClass('class');
$some_node.fireEvent('focus');
_node.setProperty('disabled', 'disabled').addClass('disabled');
$btn_node.removeProperty('disabled').removeClass('disabled');
Is there something out there for this?
Assuming the $some_node is a jQuery object, then the function equivalent in jQuery would be
getElement('selector') should be find('selector').first(), as getElement in Mootools seems to return the first element, thus first is used to reduce the find result array back down to one.
addClass('class') is just... addClass('class'). Can't see why you would have trouble with this.
fireEvent('event') should be trigger('event')
setProperty('attribute', 'value') should be attr('attribute', 'value')
removeProperty('attribute') should be removeAttr('attribute')
Of course there almost certainly are subtle differences between the functions in both languages, most of which I cannot point out as I am unfamiliar with Mootools.
Surely the above would convert to:
$('.class').addClass('class');
$('.class').live("focus", function(e) {
//Do something on focus
//E.g. $(this).attr('disabled', 'disabled').addClass('disabled');
});
Or if you just wish to set the document focus on that element:
$('.class').focus();
For example in javascript code running on the page we have something like:
var data = '<html>\n <body>\n I want this text ...\n </body>\n</html>';
I'd like to use and at least know if its possible to get the text in the body of that html string without throwing the whole html string into the DOM and selecting from there.
First, it's a string:
var arbitrary = '<html><body>\nSomething<p>This</p>...</body></html>';
Now jQuery turns it into an unattached DOM fragment, applying its internal .clean() method to strip away things like the extra <html>, <body>, etc.
var $frag = $( arbitrary );
You can manipulate this with jQuery functions, even if it's still a fragment:
alert( $frag.filter('p').get() ); // says "<p>This</p>"
Or of course just get the text content as in your question:
alert( $frag.text() ); // includes "This" in my contrived example
// along with line breaks and other text, etc
You can also later attach the fragment to the DOM:
$('div#something_real').append( $frag );
Where possible, it's often a good strategy to do complicated manipulation on fragments while they're unattached, and then slip them into the "real" page when you're done.
The correct answer to this question, in this exact phrasing, is NO.
If you write something like var a = $("<div>test</div>"), jQuery will add that div to the DOM, and then construct a jQuery object around it.
If you want to do without bothering the DOM, you will have to parse it yourself. Regular expressions are your friend.
It would be easiest, I think, to put that into the DOM and get it from there, then remove it from the DOM again.
Jquery itself is full of tricks like this. It's adding all sorts off stuff into the DOM all the time, including when you build something using $('<p>some html</p>'). So if you went down that road you'd still effectively be placing stuff into the DOM then removing it again, temporarily, except that it'd be Jquery doing it.
John Resig (jQuery author) created a pure JS HTML parser that you might find useful. An example from that page:
var dom = HTMLtoDOM("<p>Data: <input disabled>");
dom.getElementsByTagName("body").length == 1
dom.getElementsByTagName("p").length == 1
Buuuut... This question contains a constraint that I think you need to be more critical of. Rather than working around a hard-coded HTML string in a JS variable, can you not reconsider why it's that way in the first place? WHAT is that hard-coded string used for?
If it's just sitting there in the script, re-write it as a proper object.
If it's the response from an AJAX call, there is a perfectly good jQuery AJAX API already there. (Added: although jQuery just returns it as a string without any ability to parse it, so I guess you're back to square one there.)
Before throwing it in the DOM that is just a plain string.
You can sure use REGEX.
Hi I would like to do dom selection and manipulation out of the dom.
The goal is to build my widget out of the dom and to insert it in the dom only once it is ready.
My issue is that getElementById is not supported on a document fragment. I also tried createElement and cloneNode, but it does not work either.
I am trying to do that in plain js. I am used to do this with jQuery which handles it nicely. I tried to find the trick in jQuery source, but no success so far...
Olivier
I have done something similar, but not sure if it will meet your needs.
Create a "holding area" such as a plain <span id="spanReserve"></span> or <td id="cellReserve"></td>. Then you can do something like this in JS function:
var holdingArea = document.getElementById('spanReserve');
holdingArea.innerHTML = widgetHTMLValue;
jQuery will try to use getElementById first, and if that doesn't work, it'll then search all the DOM elements using getAttribute("id") until it finds the one you need.
For instance, if you built the following DOM structure that isn't attached to the document and it was assigned to the javascript var widget:
<div id="widget">
<p><strong id="target">Hello</strong>, world!</p>
</div>
You could then do the following:
var target;
// Flatten all child elements in the div
all_elements = widget.getElementsByTagName("*");
for(i=0; i < all_elements.length; i++){
if(all_widget_elements[i].getAttribute("id") === "target"){
target = all_widget_elements[i];
break;
}
}
target.innerHTML = "Goodbye";
If you need more than just searching by ID, I'd suggest installing Sizzle rather than duplicating the Sizzle functionality. Assuming you have the ability to install another library.
Hope this helps!
EDIT:
what about something simple along these lines:
DocumentFragment.prototype.getElementById = function(id) {
for(n in this.childNodes){
if(id == n.id){
return n;
}
}
return null;
}
Why not just use jQuery or the selection API in whatever other lib youre using? AFAIK all the major libs support selection on fragments.
If you wan tto skip a larger lib like jQ/Prototype/Dojo/etc.. then you could jsut use Sizzle - its the selector engine that powers jQ and Dojo and its offered as a standalone. If thats out of the question as well then i suppose you could dive in to the Sizzle source and see whats going on. All in all though it seems like alot of effort to avoid a few 100k with the added probaility that the code you come up with is going to be slower runtime wise than all the work pulled into Sizzle or another open source library.
http://sizzlejs.com/
Oh also... i think (guessing) jQ's trick is that elements are not out of the DOM. I could be wrong but i think when you do something like:
$('<div></div>');
Its actually in the DOM document its just not part of the body/head nodes. Could be totally wrong about that though, its just a guess.
So you got me curious haha. I took a look at sizzle.. than answer is - its not using DOM methods. It seems using an algorithm that compares the various DOMNode properties mapped to types of selectors - unless im missing something... which is entirely possible :-)
However as noted below in comments it seems Sizzle DOES NOT work on DocumentFragments... So back to square one :-)
Modern browsers ( read: not IE ) have the querySelector method in Element API. You can use that to get and element by id within a DocumentFragment.
jQuery uses sizzle.js
What it does on DocumentFragments is: deeply loop through all the elements in the fragment checking if an element's attribute( in your case 'id' ) is the one you're looking for. To my knowledge, sizzle.js uses querySelector too, if available, to speed things up.
If you're looking for cross browser compatibility, which you probably are, you will need to write your own method, or check for the querySelector method.
It sounds like you are doing to right things. Not sure why it is not working out.
// if it is an existing element
var node = document.getElementById("footer").cloneNode(true);
// or if it is a new element use
// document.createElement("div");
// Here you would do manipulation of the element, setAttribute, add children, etc.
node.childNodes[1].childNodes[1].setAttribute("style", "color:#F00; font-size:128px");
document.documentElement.appendChild(node)
You really have two tools to work with, html() and using the normal jQuery manipulation operators on an XML document and then insert it in the DOM.
To create a widget, you can use html():
$('#target').html('<div><span>arbitrarily complex JS</span><input type="text" /></div>');
I assume that's not what you want. Therefore, look at the additional behaviors of the jQuery selector: when passed a second parameter, it can be its own XML fragment, and manipulation can happen on those documents. eg.
$('<div />').append('<span>').find('span').text('arbitrarily complex JS'). etc.
All the operators like append, appendTo, wrap, etc. can work on fragments like this, and then they can be inserted into the DOM.
A word of caution, though: jQuery uses the browser's native functions to manipulate this (as far as I can tell), so you do get different behaviors on different browsers. Make sure to well formed XML. I've even had it reject improperly formed HTML fragments. Worst case, though, go back and use string concatenation and the html() method.