Copy text from div innerHtml to textarea - javascript

A connected question to this problem with the iframe issue:
Copy div from parent website to a textarea in iframe
I'm trying to copy InnerHtml from a div to a TextArea.
I've made two instances of google translator on the same web page, and I'm trying to apply auto-correction of the first instance to the second instance, without changing the first textarea.
I tried different code:
setInterval(function() {
childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
$("#source")[1].val(childAnchors1.text());
}, 100);
setInterval(function copyText() {
$(".goog-textarea short_text")[1].val($("#spelling-correction > a")[0].innerText());
}
, 100);
setInterval(function copyText() {
$("#source")[1].val($("#spelling-correction > a")[0].innertext());
}
, 100);
setInterval(function() {
var finalarea = document.getElementsByClassName("goog-textarea short_text")[1];
var correction = document.querySelectorAll("#spelling-correction > a")[0].innerHTML
document.getElementsByClassName("goog-textarea short_text")[1].value = correction.innerText;
}, 100);
onclick='document.getElementsByClassName("goog-textarea short_text")[1].innerHTML=document.getElementById("spelling-correction > a")[0].innerHTML;'
But nothing of that seems to work, unfortunately...
I would be very grateful for any help.
I should have mentioned this. I used iframe to create the second instance, so simple solutions don't work...
This is the code I used for creating iframe instance:
var makediv = document.createElement("secondinstance");
makediv.innerHTML = '<iframe id="iframenaturalID" width="1500" height="300" src="https://translate.google.com"></iframe>';
makediv.setAttribute("id", "iframeID");
var NewTranslator = document.getElementById("secondinstance");
var getRef = document.getElementById("gt-c");
var parentDiv = getRef.parentNode;
parentDiv.insertBefore(makediv, getRef);
I tried to use this to communicate between the iframe and the parent website:
setInterval(function() {
var childAnchors1 = window.parent.document.querySelectorAll("#spelling-correction > a");
var TheiFrameInstance = document.getElementById("iframeID");
TheiFrameInstance.contentWindow.document.querySelectorAll("#source").value = childAnchors1.textContent;
}, 100);
But it doesn't work...
Ok, I made it work with:
var a = document.createElement('iframe');
a.src = "https://translate.google.com";
a.id = "iframenaturalID";
a.width = "1000";
a.height = "500";
document.querySelector('body').appendChild(a)
And
let iframe = document.getElementById("iframenaturalID");
setInterval(function() {
let source = iframe.contentWindow.document.getElementById("source");
let destination = window.parent.document.querySelector("#spelling-correction > a");
source.value = destination.textContent;
}, 100);
Now it does what I tried to do, however I still get mistake message: Uncaught TypeError: Cannot set property 'value' of null
at eval, which points at this line: source.value = destination.textContent;. It's not a big problem though, but still it's strange that it returns this mistake...
Ok, I was able to solve it by adding setTimeout.

Since a textarea is a form element, neither .innerText or .innerHTML will work. You need to extract its content with the value property (or .val() with JQuery).
And FYI:
It's innerText, not .innertext.
.innerText is a property, not a function, so you don't use () after it.
It's .innerHTML, not .innerHtml.
innerHTML is used when there is HTML in the string that should be
parsed as HTML and .textContent is used for strings that should not
be parsed as HTML. Usually, you don't map the contents of one to the
other.
document.querySelectorAll() scans the entire DOM to find all
matching nodes. If you know you only have one matching node or you
only want the first matching node, that's a waste of resources.
Instead, use .querySelector(), which stops searching after the
first match is found.
Since you are using JQuery, you should be consistent in its use. There's no need for .querySelector() or .querySelectorAll() with JQuery, just use JQuery selector syntax.
Here's an example that shows both the vanilla JavaScript and JQuery approaches using the HTML types that you show in your question with the same id values and nesting structure that you show. You can see that I'm using different selectors to correctly locate the input/output elements.
// Standare DOM queries to get standard DOM objects
let source = document.getElementById("source");
let destination = document.querySelector("#spelling-correction > a");
// JQuery syntax to get JQuery objects:
let jSource = $("#source");
let jDestination = $("#spelling-correction > a");
// Vanilla JavaScript way to set up the event handler and do the work
source.addEventListener("keyup", function(){
destination.textContent = source.value;
});
// JQuery way to set up the event handler and do the work
jSource.on("keyup", function(){
jDestination.text(jSource.val());
});
textarea, div {
border:3px solid grey;
width:500px;
height:75px;
font-size:1.5em;
font-family:Arial, Helvetica, sans-serif;
}
.destination { pointer-events:none; background:#e0e0e0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Type in the first textarea</p>
<textarea id="source"></textarea>
<div id="spelling-correction">
Did you mean:
</div>

The problem in all the codes you've tried is how to get the text correctly.
Starting with your First example it should be using innerText instead of text() since it's a jquery object and you're returning a DOM object not a jQuery object:
setInterval(function() {
childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
$("#source")[1].val(childAnchors1.innerText);
}, 100);
In your Second example and Third one, you need to remove the parentheses from the innerText like:
setInterval(function copyText() {
$(".goog-textarea short_text")[1].val($("#spelling-correction > a")[0].innerText);
}, 100);
I suggest the use of pure js and textContent attribute like:
setInterval(function() {
var childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
document.querySelectorAll("#source")[1].value = childAnchors1.textContent;
}, 100);
NOTE: I should point that your HTML code in invalid since you're using duplicate identifier when the id attribute should be unique in the same document.

Related

Replace multiple links

I'm trying to replace multiple links but only the first one is replaced,
all the other remain the same.
function rep(){
var text = document.querySelector(".link").querySelector("a").href;
var newText = text.replace(/http:\/\/test(.*)http:\/\/main(.*)com/, 'http://google$2com');
document.querySelector(".link").querySelector("a").href = newText;
}
Any suggestions?
It's multiple a href links inside .link elements which I'm talking about.
Your mistake is in using querySelector, so document.querySelector(".link").querySelector("a") literally translates to: get me the first a inside the first .link;
Use querySelectorAll; and you can combine the two selectors:
Vanilla JS:
[].forEach.call(document.querySelectorAll('.link a'), function(a){
a.href = a.href.replace(/http:\/\/test(.*)http:\/\/main(.*)com/, 'http://google$2com');
});
Or, since you'll select items more often, a little utility:
function $$(selector, ctx){
return Array.from((ctx && typeof ctx === "object" ? ctx: document).querySelectorAll(selector));
}
$$('.link a').forEach(function(a){
a.href = a.href.replace(/http:\/\/test(.*)http:\/\/main(.*)com/, 'http://google$2com');
})
Or in jQuery:
$('.link a').each(function(){
this.href = this.href.replace(/http:\/\/test(.*)http:\/\/main(.*)com/, 'http://google$2com');
});
This doesn't use JQuery, and I've changed your regular expression to something that made more sense for the example. It also works when you run the snippet.
function rep() {
var anchors = document.querySelectorAll(".link a");
for (var j = 0; j < anchors.length; ++j) {
var anchor = anchors[j];
anchor.href = anchor.href.replace(/http:\/\/test(.*)com/, 'http://google$1com');
}
}
rep();
a[href]:after {
content: " (" attr(href)")"
}
<div class="link">
What kind of link is this?
<br/>
And what kind of link is this?
<br/>
</div>
<div class="link">
What kind of link is this?
<br/>
And what kind of link is this?
<br/>
</div>
Edit: Expanded example showing multiple anchor hrefs replaced inside multiple link classed objects.
Edit2: Thomas example is a more advanced example, and is more technically correct in using querySelectorAll(".link a"); it will grab anchors in descendants, not just children. Edited mine to follow suite.
If you intend to only select direct children of link class elements, use ".link>a" instead of ".link a" for the selector.
Try using a foreach loop for every ".link" element. It seems that
every ".link" element have at least 1 anchor inside, maybe just one.
Supposing every .link element has 1 anchor just inside, something like
this should do:
$('.link').each(function(){
// take the A element of the current ".link" element iterated
var anchor = $(this).find('a');
// take the current href attribute of the anchor
var the_anchor_href = anchor.attr('href');
// replace that text and achieve the new href (just copied your part)
var new_href = the_anchor_href.replace(/http:\/\/test(.*)http:\/\/main(.*)com/,'http://google$2com');
// set the new href attribute to the anchor
anchor.attr('href', new_href);
});
I did't test it but it should move you to the way. Consider that we
could resume this in 3 lines.
Cheers
EDIT
I give the last try, looking at your DOM of the updated question and using plain javascript (not tested):
var links = document.getElementsByClassName('link');
var anchors = [];
for (var li in links) {
anchors = li.getElementsByTagName('A');
for(var a in anchors){
a.href = a.href.replace(/http:\/\/test(.*)com/, 'http://google$1com');
}
}
I suggest to read the following post comment for some cooler methods of looping/making stuff foreach item.
How to change the href for a hyperlink using jQuery

JavaScript global array undefined although it shows in alert

I have written a JQuery script in SharePoint to truncate a multiple lines of text column. Below is the script:
<script>
window.$divs = [];
window.$i = 0;
window.textFull = new Array();
$(document).ready(function(){
window.setInterval(function(){
/// call your function here
$divs = $("[class^=ExternalClass]");
for($i=0;$i<$divs.length;$i++)
{
textFull[$i] = $($divs[$i]).html();
if(typeof textFull[$i] != 'undefined' && textFull[$i].length > 50)
{
//alert($textFull[$i]); this alert show the correct text
$($divs[$i]).html(textFull[$i].substring(0,49)+"<a href='javascript:alert(textFull[$i]);'>...more</a>");
}
}
}, 500);
});
</script>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
In the above code "javascript:alert(textFull[$i])" shows 'undefined' in alert. But the alert above it shows correct text. Also I when I use a variable instead of an array it works fine in the alert inside anchor tag. I have also declared the array as global. So what am I missing?
You are running into the classic problem using for loop without using a closure to keep track of the index with
No need to create that array if all it is used for is to modify the html
Can do that much simpler using html(fn) and a jQuery event handler
$("[class^=ExternalClass]").html(function(index, oldhtml){
if(oldhtml.length >=50){
// store the full html in element data
$(this).data('html', oldhtml)
return oldhtml.substring(0,49)+"<a class="more-btn">...more</a>"
} else{
return oldhtml
}
}).find('.more-btn').click(function(){
var $div = $(this).parent();
$div.html( $div.data('html'));
});

setAttribute not working

I am making a plugin for form validation as practice, but for some reason after I create a h2 element and try to set it's attribute, it is not working. Here is the code
var testing = function(regex, value, error_msg, error_msg_field_id){
var pattern = new RegExp(regex);
if (!pattern.test(value)){
var ele = document.createElement("H2");
var node = document.createTextNode(error_msg);
ele.setAttribute('style', 'color:white');
alert("hi");
jQuery(error_msg_field_id).append(node);
}
}
the text appears with no problem, but it is not in white color. This make no sense at all to me
You are using setAttribute correctly, but you are setting the property on your h2-element, which is never actually inserted in your DOM.
You can change and simplify the relevant section of your code to:
var ele = document.createElement("H2");
ele.textContent = error_msg;
ele.setAttribute('style', 'color:white');
jQuery(error_msg_field_id).append(ele);
The usage of jQuery here is also not necessary. You can simply use
document.querySelector("#" + error_msg_field_id).appendChild(ele);
which is equally simple.

`.replaceChild()` on `this` Throwing NotFoundError: DOM Exception 8

I figured I would get fancy and use vanilla JavaScript during a jQuery event. The idea is that on click of a heading, I want to slide up a div (which works) and replace the tag clicked on to a larger heading.
From what I've read around, this can be caused by the parentNode referencing an element that's not the actual parent, but after checking it appears to be selecting the element that's directly above it.
So... here's the code!
HTML (in Jade)
.policy-container
h6.policy-heading Policies
.policy-list
.content-we-are-hiding
.not-actually-important
jQuery
$('.policy-heading').click(function() {
var self = this;
if (this.classList.contains('closed')) {
$(this).next().slideDown(300);
this.parentNode.replaceChild(self, '<h6 class="policy-heading">Policies</h6>');
} else {
$(this).next().slideUp(300);
this.parentNode.replaceChild(self, '<h2 class="policy-heading closed">Policies</h2>');
}
});
Everything seems pretty standard. Luckily I can just take care of this with jQuery, however I'd rather be using vanilla JS here. Any ideas why this isn't working?
As has been pointed out, replaceChild takes two nodes.
The following will work with native JS wrapped inside jQuery, as you've specified:
$('.policy-heading').click(function () {
var self = this,
h2 = document.createElement('h2'),
h6 = document.createElement('h6');
h2.class = "policy-heading closed";
h2.innerHTML = "Policies";
h6.class = "policy-heading";
h6.innerHTML = "Policies";
if (this.classList.contains('closed')) {
$(this).next().slideDown(300);
this.parentNode.replaceChild(h6, self);
} else {
$(this).next().slideUp(300);
this.parentNode.replaceChild(h2, self);
}
});
replaceChild takes two nodes, you are giving it a node and a string.
It looks like you'd be much better off just sticking with jQuery and using toggle functions for the sliding and class change.
try this :
.click(function(this)
you also need some debugging to understand what is going on I would advice you to use :
console.log(this)
use this :
el = document.createElement('h6');
el.class = "policy-heading";
el.innerHTML = "Policies";
this.parentNode.replaceChild(self, el);
As everyone pointed out, .replaceChild accepts two DOM elements, rather than the string like I was using. I also had its arguments backwards, the first is for the new element, the second is the replaced element.
Example code that works
$('.policy-container').on('click', '.policy-heading', function() {
var self = this,
newElement;
if (this.classList.contains('closed')) {
newElement = document.createElement( 'h6' );
newElement.classList.add('policy-heading');
newElement.innerHTML = 'Policies';
} else {
newElement = document.createElement( 'h2' );
newElement.classList.add('policy-heading');
newElement.classList.add('closed');
newElement.innerHTML = 'Policies';
}
$(this).next().slideDown(300, function() {
self.parentNode.replaceChild( newElement, self );
});
});

Search for non-nested nodes with specific attribute set

The short long of it is I'm working on a small library in javascript that will replace <div src="somesite"></div> with the content from the specified source. This would allow coders to create dynamic pages without having to do more work server-side without the annoyance of using iframes.
What I need is an efficent way to get the top most div nodes of a branch with an src attribute. E.G:
<div src="somesite/pagelet.htm" id="div1">
<div src="somesite/fallback.htm" id="div2"></div>
</div>
<div src="somesite/pagelet2.htm" id="div3"></div>
I want to retrieve #div1 and #div3 and ignore #div2 until later. At the moment I'm using the following function, but am wondering if there is a more efficent way to do this:
function getRootElementsByAttribute(rootEle, tag, attr) {
try {
tag = tag.toLowerCase();
if (rootEle.tagName.toLowerCase() === tag && rootEle.hasAttribute(attr)) {
return [rooEle]
}
var eles = rootEle.getElementsByTagName(tag),
nodes = [], ele, isRoot, eleParent, a;
for (a=0; a<eles.length; a++) {
ele = eles[a];
if (ele.hasAttrinute(attr)) {
isRoot = true;
eleParent = ele;
while ((eleParent = eleParent.parentNode)) {
if (eleParent.tagName.toLowerCase() === 'div' && eleParent.hasAttribute(attr)) {
isRoot = false;
break;
}
}
if (isRoot == true) nodes.push(ele)
}
}
}catch(e){}
return nodes;
}
Please no answers suggesting the use of a library. It seems overkill to import a whole library when all it would be used for is this single function
You could try to use an XPath expression to get all root divs with the attribute source using something like the following XPath expression:
/div[#src]
/div selects all divs that are on the root level. For all divs in the document use //div.
[#src] specifies that you only want nodes with the 'src' attribute.
var xmlDoc = //load your document here
var xpath = "/div[#src]"
var nodes = xmlDoc.evaluate(xpath, xmlDoc, null, XPathResult.ANY_TYPE,null);

Categories