Parse string for text between divs - javascript

I have a string of html text stored in a variable:
var msg = '<div class="title">Alert</div><div class="message">New user just joined</div>'
I would like to know how I can filter out "New user just joined" from the above variable in jQuery/Javascript so that I can set the document title to just the message.

Like this:
document.title = $(msg).filter("div.message").text();
Note that if the message changes to be wrapped in an element, you'll need to replace filter with children.
EDIT: It looks like the div that you want is nested in other element(s).
If so, you can do it like this:
document.title = $("div.message", msg).text();
Explanation: $('<div>a</div><div>b</div>') creates a jQuery object holding two different <div> elements. You can find the one you're looking for by calling the filter function, which finds mathcing elements that are in the jQuery object that you call it on. (Not their children)
$('<p><div>a</div><div>b</div><p>') creates a jQuery object holding a single <p> element, and that <p> element contains two <div> elements as children. Calling $('selector', 'html') will find all descendants of the elements in the HTML that match the selector. (But it won't return the root element(s))

This is a hack and not very clean, but it should work:
add a div node and set its html to your text message,
get the text of the added element and store it in a variable
destroy the node
set the title with the contents of the variable in step 2

Related

How to grab the h3 text within a div

My website HTML has the following:
To grab the H3 text (SOME TEXT) as a variable in Tag Manager - when a user clicks on the div class "c-card c-card--primary c-parkcard " I think I need to use a DOM Element variable
But it's not returning the text.
Should the Element Selector be:
.c-card.c-card--primary.c-card__body.u-h6.c-card__title
However, it returns a null value in Tag Manager
The solution was to create a custom JS variable that when the image was clicked on would find the "c-card c-card--primary c-parkcard " div (9 parents up) and then go back down to find the h3 element by class and then return the text:
function(){
var z = {{Click Element}}.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode
.getElementsByClassName('u-h6 c-card__title')[0].innerText;
return z;
}
use of getElementsByClass is as simple as:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
$content_node=$dom->getElementByClass("c-card__body");
$div_a_class_nodes=getElementsByClass($content_node, 'h3', 'u-h6 c-card__title');
You have set "h3" as "attribute name. "h3" is not an attribute (but the name of the tag). You do not want to set an attribute name at all, because you do not want to return the value of an attribute, but the innerText of the tag, and that is the default behaviour anyway.
If you use a DOM variable this will return the first instance on the page. If your selector matches several DOM nodes, you will still just get the first one, regardless if what the user clicks. If you expect this to update depending on the clicked element, you should rather use the {{Click Text}} variable (a built-in variable that you might have to enable first).
Chances are that the actual click element is not the h3, but the nested link inside, but that does not really change things for you (as in both cases the innerText will be the contained texted nodes, which in this case is the same).

How do you add an element to a class (through JavaScript)?

Suppose that I want to add a newly created paragraph (using document.createElement("p")) into an existing div (with class name "container") in one of my html files. Is there a way to do this by calling some methods?
Since there's a getElementById() method, I figured I would use a getElementByClassName() method too, but that doesn't exist; what exists is getElementsByClassName() instead. One way I can get around this is to just change my div to have an id rather than a class name, and use the getElementById() to add the paragraph into the div, but I wanted to know if there was some method that I could call that would help me retrieve a class element (rather than the elements within the class itself).
I've tried looking for this online, but what I've found are answers to "how to add class names to elements" instead, which is not what I want to know.
For one element, this will chose first in DOM order:
var p = document.createElement("p");
p.innerHTML = "p element";
document.querySelector(".container").appendChild(p);
<div class="container">container</div>
For all elements with chosen class:
[...document.querySelectorAll('.container')].forEach(el => {
var p = document.createElement("p");
p.innerHTML = "p element";
el.appendChild(p);
})
<div class="container">container</div>
<div class="container">container2</div>
HTML DOM elements' IDs have to be unique within a document - and so asking for an element by Id will return you just one element (or null if there isn't a matching element).
However a class name can be applied to multiple elements, so you would expect to get zero one or more elements when searching by class, hence the getElementsByClassName returns a collection.
So if you have a list of elements with the class name container, and you know your document (hopefully) only contains one element with that name, you can pick the first element returned by the getElementsByClassName - e.g. getElementsByClassName('container')[0]
Note - getElementsByClassName returns all elements to which the class has been directly applied, for the children of the element on which it is being called. I've interpreted your query as relating to the whole document in the context of your original question.

jquery.html() returns only first text when loaded from string

Supposedly a jquery object can be initialized from string. This can often happen when processing ajax results, i.e. I'm trying to replicate http://api.jquery.com/jQuery.post/
However, I'm seeing strange behavior:
function test() {
var content = $("<html><body><div>hello</div><div>world</div></body></html>");
alert("content.text() = " + content.text());
alert("content.html() = " + content.html());
}
The first alert shows: content.text() = helloworld
The second alert shows: content.html() = hello
What's happening here?
Solution
Thanks everyone for the explanations. I ended up adding another layer of <div> to have a single child of <body>, as in
<html>
<body>
<div> <=== added
<div>hello</div>
<div>world</div>
</div>
</body>
</html>
When parsing HTML fragments containing a body element, browsers in general (and jQuery does this as well) will disregard everything except what's inside the body element. So what you have there ends up being equivalent to:
var content = $("<div>hello</div><div>world</div>");
alert("content.text() = " + content.text());
alert("content.html() = " + content.html());
You end up with a jQuery object with two elements in it: The div elements.
In jQuery, normally accessor functions (html, val, css, etc.) only use the first element in the set when you use them as getters, and that's what html is doing above. text is an unusual accessor function in jQuery: It gives you the combined text of all of the elements in the set, not just the first.
We can see this in the docs, but it's still surprising. From html:
Get the HTML contents of the first element in the set of matched elements or set the HTML contents of every matched element.
From text:
Get the combined text contents of each element in the set of matched elements, including their descendants, or set the text contents of the matched elements.
(My emphasis in both cases.)
Browsers remove those html and body elements. The content collection has only 2 div elements.
When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, jQuery uses the browser's .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed.
This is the string representation of your content collection:
content.map(function() { return this.outerHTML || this.nodeValue; }).get().join('');
// -> <div>hello</div><div>world</div>
.text() method returns textContent/nodeValue of all the elements in the collection:
content.text(); // -> helloworld
.and .html() method returns innerHTML of the first element in the collection:
content.html(); // -> hello
This is what your content looks like to a browser:
"content = " Object { 0: <div>, 1: <div>, length: 2 }
Basically this is in some kind a set of 2 elements.
And here's what http://api.jquery.com/html/ say:
Get the HTML contents of the first element in the set of matched elements

javascript elements/tags array DOM node access

what's the different between using:
// assuming using elements/tags 'span' creates an array and want to access its first node
1) var arrayAccess = document.getElementsByTagName('elementName')[0]; // also tried property items()
vs
// assuming I assign an id value to the first span element/tag
// specifically calling a node by using it's id value
2) var idAccess = document.getElementById('idValue');
then if I want to change the text node....when using example 1) it will not work, for example:
arrayAccess.firstChild.nodeValue = 'some text';
or
arrayAccess.innerText/innerHTML/textContent = 'some text';
If I "access" the node through its id value then it seems to work fine....
Why is it that when using array it does not work? I'm new to javascript and the book I'm reading does not provide an answer.
Both are working,
In your first case you need to pass the tag name instead of the element name. Then only it will work.
There might be a case that you trying to set input/form elements using innerHTML. At that moment you need to use .value instead of innerHTML.
InnerHTML should be used for div, span, td and similar elements.
So your html markup example:
<div class="test">test</div>
<div class="test">test1</div>
<span id="test">test2</span>
<button id="abc" onclick="renderEle();">Change Text</button>
Your JS code:
function renderEle() {
var arrayAccess = document.getElementsByTagName('div')[0];
arrayAccess.innerHTML = "changed Text";
var idEle = document.getElementById('test');
idEle.innerHTML = "changed this one as well";
}
Working Fiddle
When you use document.getElementsByTagName('p'), the browser traverses the rendered DOM tree and returns a node list (array) of all elements that have the matching tag.
When you use document.getElementById('something'), the browser traverses the rendered DOM tree and returns a single node matching the ID if it exists (since html ID's are unique).
There are many differences when to use which, but one main factor will be speed (getElementById is much faster since you're only searching for 1 item).
To address your other question, you already have specified that you want the first element in the returned nodeList (index [0]) in your function call:
var arrayAccess = document.getElementsByTagName('elementName')[0];
Therefore, arrayAccess is already set to the first element in the returned query. You should be able to access the text by the following. The same code should work if you used document.getElementById to get the DOM element:
console.log(arrayAccess.textContent);
Here's a fiddle with an example:
http://jsfiddle.net/qoe30w2w/
Hope this helps!

JavaScript unexpected object behavior with jQuery

I have two <div> elements, and the following JavaScript code:
var myObject = {
$input: $('<input />'),
insert: function () {
$('div').append(this.$input);
$('div').append(' ');
}
};
myObject.insert();
This, as I expect, produces an <input> element within each of the two <div> elements.
Now when I create a new instance of myObject and call insert() again I will be expecting 4 <input> elements, two in each <div>. Weirdly, I only get 3 <input> elements!
See example code here:
http://jsfiddle.net/FNEax/
You're creating 1 input explicitly:
$input: $('<input />',{value:i}),
...but cloning it implicitly when you try to append it to multiple divs
// 2 divs
$('div').append(this.$input);
Then Object.create doesn't create a new $input, so on the second pass, it appends (moves) the input from the second div (which is actually the original) to the first div, and then does the implicit clone to populate the second.
Here's a jsFiddle example that increments an i variable whenever insert() is called, and adds it as the value of the input. Notice that it is always set at 0.
I also modified it to pass a string to insert so you can see which call each input came from.
The two inputs from the second call both still have the string passed to the first call.
EDIT:
I flipped it around mid explanation, but the concept is the same.
When the second insert() is called, the clone is first created of the original and added to the first div, then the original is appended to the second div (where it already is).
jQuery makes the clones first, then appends the original last.
Here's another jsFiddle example that adds a custom property to the original, then adds some text next to the element with that custom property after each insert(). The text is always added next to that original in the second div.
This is what is happening. From the jQuery docs:
If an element selected this way is inserted elsewhere, it will be moved into the target (not cloned)
If there is more than one target element, however, cloned copies of the inserted element will be created for each target after the first.
So the first time around, since your input isn't anywhere in the DOM it is cloned and inserted into both divs. But, the second time it is called it is removed from the second div, before being cloned and added back into both divs.
At the end of your code, the first div contains both inputs, but the second div only contains the most recent input, since each input was removed from your last div.
http://jsfiddle.net/hePwM/
Once an element is inserted into the DOM, another .append() call with it as the appended content causes it to move within the DOM (docs). Your code creates a jQuery collection with a single input therein, which input has yet to be appended to the DOM. So the first call to insert() appends it to each (using the cloning or copying mechanism internal to jQ).
In the second call, however, this.$input references something which is already in the DOM (due to the first call). Internally, jQuery is each-ing the collection of DIVs and appending the input which lives inside of this.$input. So it adds it, the moves it.
The primary issue is that you're re-appending the same input over and over. Remember that JavaScript generally references existing objects rather than make new ones. That same input element keeps getting re-referenced.
If you want a method to add an input to every DIV, you should simply pass the input markup into append:
$( 'div' ).append( '<input />' );
The wierd behavior is due to the fact you are using a JQuery collection where you shouldn't be. How it even worked in the first place is beyond my skillset.
var myObject = {
input: '<input />',
insert: function () {
$('div').append(this.input);
//$('div').append(' ');
}
};
try each():
var myObject = {
insert: function () {
$('div').each(function(index) {
$(this).append($('<input />'));
$(this).append(' ');
});
}
};
myObject.insert();
myObject.insert();

Categories

Resources