Why can't I retrieve "this" dom element without onclick? - javascript

I have a very basic question about using the "this" keyword to retrieve a DOM element.
Consider the following HTML/Javascript:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
console.log(this);
</script>
Here is a div withOUT onclick
</div>
<div class="onclick-div" onclick="console.log(this)">
Here is a div with onclick
</div>
</div>
While clicking the "onclick-div" it does return the DOM object for that div. However, the console.log event calls 'this' indirectly in the "regular-div" and returns window.
Is it possible to get "this" DOM object when 'this' is called indirectly? My purpose is I want to fire a function in line in the HTML, but need to send the function "this". Here's an example of what i'm trying to do:
<div class="container">
<div class="regular-div">
<script type="text/javascript">
loadSomeHTML(this, varA, varB, varC);
</script>
</div>
</div>
Thanks everyone for any clarification of how "this" works in the above context.

In your first example, the script isn't in any way associated with the div. It's just been output within the div, but it's not connected to it. The script runs as the page is being parsed.
Is it possible to get "this" DOM object without a user interaction?
If you mean inline with the parsing of the HTML, you could do this:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Note that the script tag is immediately after the ending </div> tag for the div you're trying to target. The script gets what's currently the last div in the document as of when the script runs. Or of course you could identify the div in some way (a class, for instance) and use that (and then potentially remove it so you could do it again later in the document).
It looks dodgy, but it's perfectly valid cross-browser, and was even recommended at one stage by the Google Closure Library engineers.
Live Example:
<div class="container">
<div class="regular-div">
Here is a div withOUT onclick (look in console for result)
</div>
<script type="text/javascript">
(function() {
var list = document.querySelectorAll('div');
console.log(list[list.length - 1]);
})();
</script>
</div>
Example using a class we move:
<div class="container">
<div class="target-me">
The first div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
<div class="target-me">
The second div
</div>
<script type="text/javascript">
(function() {
var div = document.querySelector(".target-me");
div.classList.remove("target-me");
console.log(div);
})();
</script>
</div>
Note I didn't use id, because if we used an id and JavaScript wasn't enabled, we'd end up with an invalid document (because it would have multiple elements with the same id). It'd be fine if JavaScript were enabled (because we'd remove the id from earlier ones before later ones were created), but...

Javascript has no implicit connection to the HTML DOM. The reason why onclick works the way you want is because the HTML DOM implementation passes the element to the js callback. You need to do something similar in your other case. One way to do this is:
<div class="container">
<div class="regular-div" id="mydiv">
<script type="text/javascript">
loadSomeHTML("#mydiv", varA, varB, varC);
</script>
</div>
</div>
Then your js implementation does the lookup to find the element:
function loadSomeHTML(selector, varA, varB, varC) {
var el = document.querySelector(selector);
// now el is where you want to insert your HTML
// ...
}

The code inside the script tag doesn't have any connection with the tag itself. this should, basically, return the object on which the current function was called, or the global environment, window. In the first div, the code is just executed, on no object, so window is returned. The value of onclick, on the other hand, is treated as a function (with even some parameters, like e), that gets called on the element with the attribute. So, the code in the script element is executed in the global scope, whereas the one in the attribute is in a function scope (that's why all vars are shared across script tags).

As explained in How may I reference the script tag that loaded the currently-executing script?, the proper way of obtaining a reference to the script element whose code is being executed is
document.currentScript;
Then, to get the parent node of that element, use
document.currentScript.parentNode;
<div class="container">
<div id="regular-div">
<script type="text/javascript">
alert('#' + document.currentScript.parentNode.id);
</script>
Here is a div withOUT onclick
</div>
</div>

Related

Javascript : Why can't I use the "this" with childnodes?

<div id="test" onmouseover="working(this)">
<p>help</p>
<p>me</p>
</div>
<div id="test" onmouseover="not_working(this)">
<p>help</p>
<p>me</p>
</div>
When I use the first function(not_working) it doesn't work, but when I used the second function(working) it does.
function not_working(element){
document.getElementById(element).childNodes[1].innerHTML="succeed";}
function working(element){
document.getElementById("test").childNodes[1].innerHTML="succeed";}
Sorry if I miss something simple, I'm still learning html and only have limited knowledge on javascript.
this is a reference to the element, the event was created from (the div in your case), but getElementById takes an id ("test" in your case).
Also the hovered element is already being passed in the function as element so you can just do:
function working(element) {
element.childNodes[1].innerHTML="succeed"
}

Copy/Clone div content to another div

I need to copy content from div1 and paste/append it to div2 by click. Then if I change content in div1 and click the button again the content should go to div3 without changing the content in div2. This is what I found so far.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="div1">
<p>Hello world</p>
</div>
<button onclick="$('#div2, #div3').html($('#div1').html());">Copy</button>
<div id="div2"></div>
<div id="div3"></div>
Because I assign value it would paste the same in both divs and I have no idea how to do it separately. I guess some loops will be needed.
Is it possible and if it is could somebody give me some ideas or links to read materials. Thanks in advance!
You can use a variable to store the number of the div element and then increment it accordingly. (Here I am assuming only div2 and div3 are there)
Since you have not mentioned how the value of div1 is going to update. I am manually doing it using $('#div1').html("New Value"); inside the function add().
<html>
<body>
<body>
<div id="div1">
<p>Hello world</p>
</div>
<button onclick="add()">Copy</button>
<div id="div2"><p>div1 Placeholder</p></div>
<div id="div3"><p>div2 Placeholder</p></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
var n = 2;
function add(){
$('#div'+n).html($('#div1').html());
$('#div1').html("<p>New Value</p>");
n++;
}
</script>
</body>
</html>
Try running the snippet. Clicking the button once will put the value of div1 to div2 and then it changes the original content of div1 to New Value. Again if you click the button, the new value of div1 i.e., New Value will be put to div3.
Though this will also try to update div1 again to New Value, which won't make any change. It would be better if you write some other ways to update the div1 element.
Take care of the <p> tag if you want it to be retained. Well, that also depends on the way you update the value of div1.
To append you can use $('#div'+n).append($('#div1').html());
I wrote a little help code to get you started. So what i did was to move the logic to a function which iterate a variable i (which can only take the value 2 and 3). This does not check if the text has changed and will overwrite div2 and div3 in turns on every click (remove if test if you only want to do it once).
<html>
<body>
<body>
<div id="div1">
<p>Hello world</p>
</div>
<button onclick="copyPaste()">Copy</button>
<div id="div2"></div>
<div id="div3"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
<script>
var i = 2;
function copyPaste() {
//add logic to check if text has changed before executing next line
$(`#div${i++}`).html($('#div1').html());
if(i < 3) i = 2;
}
</script>
</body>
</html>
Using a script tag with javascript code as in Saif's answer is perfectly valid (you only should be careful not to overwrite the global var used to keep count). To be more inobtrusive the click event could also be added in the script tag.
As another possibility with the opposite approach, you could do all in the the button attributes, using jQuery's data. The count is here stored in an attribute in the button, but it could also be stored in the original div #div1. The code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div1">
<p>Hello world</p>
</div>
<button onclick="$('#div' + $(this).data('targetdiv')).html($('#div1').html()); $(this).data('targetdiv', $(this).data('targetdiv') + 1);" data-targetdiv="2">Copy</button>
<div id="div2"></div>
<div id="div3"></div>
Some important notes about data: using data to change the value doesn't update the DOM attribute itself, because once the value is retreived from the attibute, jQuery uses an internal javascript code to keep the value. There's no real need to udate the DOM, but if you really want it to, you can use attr instead of data. But if you use attr, never mix it with calls to data, as the latter won't see the DOM updates after the first time it has retreived the value (because it uses the value stored in the internal javascript cache instead of reading the DOM attribute).

Replace html in $(this) element with another html (jQuery)

I want to replace the content in the current element with and html string taken out of an object.
It has to work dynamically regardless of what div, p...etc it is in.
<div id="content">
<h5><script>$(this).append(en.login_terms_and_conditions);</script></h5>
</div>
It's possible to do what you've shown, but it's probably not a good idea. You'd use $(document.body.lastElementChild):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// Presumably you have something defining that `en` variable and the object it refers to:
var en = {
login_terms_and_conditions: "terms and conditions here"
};
</script>
<p>one</p>
<p>two</p>
<p>three</p>
<div id="content">
<script>$(document.body.lastElementChild).html(en.login_terms_and_conditions);</script>
</div>
<p>four</p>
<p>five</p>
<p>six</p>
...or of course, just $("#content") if that id is always on the element.
This works because the element is added to the DOM as of when your script runs (the details on that are complicated, but covered in the spec), even though the element's end tag has not yet been parsed.
I wouldn't do that, though, for a couple of reasons, not least that if you're doing this with jQuery, you have to load jQuery prior to that element, which holds up the rendering of your page. You could fix that by not using jQuery for this bit:
<script>
// Presumably you have something defining that `en` variable and the object it refers to:
var en = {
login_terms_and_conditions: "terms and conditions here"
};
</script>
<p>one</p>
<p>two</p>
<p>three</p>
<div id="content">
<script>document.body.lastElementChild.innerHTML = en.login_terms_and_conditions;</script>
</div>
<p>four</p>
<p>five</p>
<p>six</p>
...but it still seems like there are simpler solutions, like just document.write-ing the content, or using server-side templating.
Your example is not quite how jQuery works. The location of the script is irrelevant to the scope of this when attempting to affect an element.
Instead you need to select the #content element directly, then call html() with the value of the login_terms_and_conditions property. Try this:
var en = {
login_terms_and_conditions: '<h2>fizz buzz</h2>'
}
$(function() {
$('#content').html(en.login_terms_and_conditions);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="content">
<h5>foo bar</h5>
</div>
First, this does not work as you want. You have to select an element first and then refer to it with this.
Second, even if you would want to add an object key directly into html, that's not possible. ( is possible in JSX but that's another thing :) ).
Third, to make it more dynamic (as I understood you want), you can add some specific data-attributes to your html elements. For example a data-obj='content' for the content and so on. Then, you can iterate your en object and add en[key] value to it's respective html element with the data-obj.
See below
const en = {
title: 'Title in english',
content: 'Some content in english here <br/>Some content in english here ',
link: 'Link text'
}
for (let key in en) {
if( en.hasOwnProperty(key) ) {
let element = $(`[data-obj='${key}']`)
element.html(en[key])
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content">
<h5 data-obj="title"></h5>
<p data-obj="content"></p>
<a data-obj="link"></a>
</div>
If you want to target by id, then you could try something like this:
$("#content").html(en.login_terms_and_conditions);

Access view-source instead of prepared DOM

Hopefully I can explain my question correctly, so sorry in advance for any wrong use of jargon or other:
Is it possible to access with javascript the original markup as viewed in the source code rather then the code from the DOM after it has been 'modified'
Let's say an element #div1 has the actual text that will be used in another element with id #div2, in the source code the text will be visible in #div1 but in the DOM while inspecting #div1 will be empty and #div2 will have that text,
I know it would be a matter of the order of loading the scripts, but I was hoping there could be another way.
Hopefully this makes some sense.
Yep, the simpliest way to access original html is to place your js code before any other scripts (or place only libs like jquery before).
The second opportunity is to load document again with ajax, parse and get what you want. Here is code example:
<div id="div1">
Hello
</div>
<div id="div2">
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
$('#div2').html($('#div1').html())
$('#div1').html('')
</script>
<script>
alert($('#div1').html())
// ajax get
// empty string in get request means current location
$.get("", function (html) {
var el = $(html).filter('#div1');
alert(el.html())
});
</script>

how to access the element inside iframe, from parent document?

function contents_nb(name, height) {
1. document.getElementById('contents_iframe').height = height+'px';
2. var $currentIFrame = $('#contents_iframe');
3. $currentIFrame.contents().find(".wrap_contents").hide();
4. $currentIFrame.contents().find(".greetings").fadeIn(2500);
}
this is my jquery syntax.
no.1 ~ 3, it works well.
but line no.4, it doesn't work.
structure of html document inside iframe is ...
<body>
<div class="wrap_contents">
<div class="greetings">
</div>
<div class="operational_philosophy">
</div>
</div>
</body>
</html>
what is the reason? what causes this problem?
and syntax of the parent html document is..
<iframe id="contents_iframe"></iframe>
what is the problem??
why can not find class inside class?
You may used jquery contents() function to access/find the elements,
$("#iframeID").contents().find("#contentID");

Categories

Resources