Find the div containing the current script [duplicate] - javascript

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How may I reference the script tag that loaded the currently-executing script?
I am trying to make a javascript function that includes a html doc on a page via AJAX, as a way of making a PHP-esque include() with no serverside interaction. I want the script to include the file at the location on the page the function is called from. Here's my function (assuming ajax is a valid xmlhttp object):
function include(src, elem){
ajax.open('GET', src, false);
ajax.send(null);
elem.innerHTML = ajax.responseText;
}
So this would print the contents of "src.html" in the div when it is clicked:
<div onclick="include('src.html', this);"> </div>
But I want it to load when the page does. Considering there is no onload event for divs I have to include the script in the div, which is fine:
<div id=write>
<script>include('src.html', this);</script>
</div>
But then the script has no reference to the div it is called from. Sure I could put an id on the div and pass that to the function, but I don't want to. I want to be able to call this from any unidentified element. Any ideas?

You could change your div (or other element(s)) to use a data- attribute to specify what script to run:
<div data-include="src.html"></div>
And then run a script onload of the page (or in a script block just before the closing </body> tag) that finds all elements with that attribute.
var elements = document.querySelectorAll("[data-include]");
for (var i = 0; i < elements.length; i++)
include(elements[i].getAttribute("data-include"), elements[i]);
Here's a demo of the above (with a dummy include() function that just puts the required source url string in the element rather than doing Ajax, but it shows the elements are selected correctly): http://jsfiddle.net/nnnnnn/gm2LN/
For simplicity I've used querySelectorAll() to select the elements, but note that it isn't supported in IE7 and older. But obviously you can substitute whatever other element selection method you like if you want or need to support older browsers.

Here:
<div id=write>
<script>include('src.html', this);</script>
</div>
"this" points to the window object.
I think of putting an id to the script element and doing something like this:
<div id=write>
<script id='test'>include('src.html', document.getElementById('test').parentNode);</script>
</div>
Now elem in "include" function will point to the div containing the script element. In this case you are still relying on id but not on the div's side

When the page is loaded, all scripts will be executed sequencially, as soon as they are parsed. Therefore, you just need to get the last script that is apparent in the DOM to get the currently executed script:
var script = document.scripts[document.scripts.length-1];
ajax(url, function successCallback(html) {
script.insertAdjacentHTML("afterend", html);
});
(Demo to test - notice that document.scripts needs FF 9+)
However, I see no reason not to use serverside include().

nnnnnn was on the money, but I modified it ever so softly. I ended up making an include tag with a src attribute. On pageload I loop through all the "include" tags and fill them with the data from their src attribute:
function include(src, elem){
ajax.open('GET', src, false);
ajax.send(null);
elem.innerHTML = ajax.responseText;
}
window.onload = function(){
var includes = document.getElementsByTagName('include');
for(var i = 0; i <= includes.length; i++){
var elem = includes[i];
var src = elem.getAttribute('src');
include(src, elem);
}
}
Then anywhere I want to include a html file I just include my custom element:
<include src='includeme.html'> </include>
In practice this produces a bit of popup but for my application that's fine.
Thanks for the help!

Related

Understanding "order matters" on external .js files in html

EDIT:
Okay, gonna try to use as little code as possible to explain my problem.
I have a select dropdown menu that has a function changetext() tied to it. Whenever a value is selected in the dropdown menu, text inside a tag is changed.
The script to the function is stored in an external js file and is placed at the bottom of my html file.
Inside the js file is something like this.
var selectormenu = document.getElementById("selector");
var spanTag = document.getElementById("texthere");
function changetext(){
if(selectormenu.value == "one"){
spanTag.innerHTML = "one";
}
}
By using this js file, I get a TypeError in my browser console. However, if I place var selectormenu and spanTag inside the function, the script works.
EDIT: Since the question case sensitivity was fixed, I am adjusting my answer. You need the DOM element to already be created, because document.getElementById needs to have something to select. Then, your function needs to be named before the parentheses. Finally, you need to call the function, because it won't run unless it's called.
<div id="divid>Hello World!</div>
<script>
var soandso = document.getElementById("divid");
function statsChange() {
soandso.innerHTML = "123";
}
statsChange();
</script>

Replacing document.write()

I am trying to replace the document.write() function in Javascript. Not completely sure how to do, as I don't know which element to write the HTML to.
Currently, the code javascript code is inserted to my page using:
<script src="//example.com/file.js" type="text/javascript"></script>
The file contains a document.write() function:
document.write('<h2>Testing HTML</h2>Hello');
However, as document.write() can't be called asynchronously, I need to figure out another solution. I can not use getElementsById() or something like that, because I simply don't know any element on the target website.
I want the HTML code to be inserted exactly on the position that the script tag is.
Any suggestions?
Try this:
<script src="//example.com/file.js" type="text/javascript" id="myScript"></script>
And in the javascript:
var script = document.getElementById('myScript');
script.outerHTML += '<h2>Testing HTML</h2>Hello';
As you don't have the script ID, try this:
var scripts = document.getElementsByTagName('script');
var script = scripts[scripts.length - 1];
// Async
setTimeout(function() {
script.outerHTML += '<h2>Testing HTML</h2>Hello';
}, 2000);
First you will need to create an element to add your HTML to, if you already have your HTML in a variable, that's great, use it instead of yourElement below.
// Create an element, add HTML to it
var yourElement = document.createElement ('div');
yourElement.innerHTML = '<div>Test</div>';
Then, you will get the current JavaScript tag...
// Get the current script tag (meaning yours)
var scripts = document.getElementsByTagName ('script');
var thisScript = scripts[scripts.length - 1]
And you will insert your HTML element before this tag...
// Insert your element before current script tag
thisScript.parentNode.insertBefore (yourElement, thisScript);
You can also insert your HTML element after the JavaScript tag as well.
Credit: This code was inspired by HashOver: tildehash.com/hashover/hashover.js

Need JS to modify the element following the script

I have a report authoring tool that lets me add descriptive text in the report header, prior to a table containing the data. The examples included with the tool show how include Javascript in the description for various special effects. I would like to change certain cells in the table into links to other reports. Here's the HTML produced by the reporting tool.
<div class="element-info">
<div class="description">My Description</div>
<div class="properties">
<table>...</table>
</div>
</div>
I have tried replacing "My Description" with the following, but (perhaps unsurprisingly) it's changing something other than the table.
<div>My Description
<script type="text/javascript">
// currentScript is supported in my version of Firefox.
var me = document.currentScript;
// go up two levels to get the enclosing div
var element_info = me.parentElement.parentElement;
// from there we want the properties div, then the table
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
</script>
</div>
I expect that the problem is that when the script runs, the HTML in the following div has not yet been parsed. Mozilla says that the defer attribute will be ignored in scripts without a src= attribute, and I've verified that it does nothing.
Although my example code is using plain Javascript, the authoring tool is based on jQuery, so it's full repertoire is available if needed.
If the problem involves the fact that the html hasn't yet been parsed, you can immediately gain a reference to the script, but only later utilize it, once the document is loaded. It would look like this:
<div>My Description
<script type="text/javascript">
// Get the reference immediately...
var script_of_interest = document.currentScript;
// And only use it once everything is loaded:
window.onload = function() {
var element_info = script_of_interest.parentElement.parentElement;
var mytable = element_info.lastChild.firstChild;
mytable.style.color = "red";
};
</script>
</div>
Make sure your the node your script operates on is loaded before the execution, otherwise your the node may be undefined or just nothing. You may try wrap your code with
$(document).ready(function(){
//your code
}).

javascript to add second class to element on click event

I am trying to add a second class to my element on click
Before
<div class="foo1">
<a class="class1" >Text</a>
</div>
After
<div class="foo1">
<a class="class1 class2" >Text</a>
</div>
here are my javascript codes; both of them work:
either this one (thanks to #Shomz)
var elements = document.getElementsByClassName('class1 ');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.className += ' class2';
}
or this one (thanks to #t-j-crowder)
[].forEach.call(document.querySelectorAll(".class1 "), function(element) {
element.className += " class2";
});
Question
The site allows the users to click on class1 and change it to class1 class2 . However, by running these codes, the class1 only temporarily changes to class1 class2, I mean the clicking event is not implemented, it has only visually changed. When the site is reloaded, it is back to the previous state. How to apply a fix to change permanently the class by clicking on it?How to achieve the class changing through a click event and to record this permanently? How can these js codes record this click and change it permanently?
Ok so based upon your comment you need to communicate the change to a server, then when the page loads it needs to request the data back from the server to reflect any stored changes. Theres a number of ways to do this depending on your programming capability, preference in language and compatibility requirements.
The most popular method would likely be a data file that is written dynamically by a php script. When the page is loaded it would generate your content based upon the contents of the datafile on the server(not to be confused with your HTML page). When the user modifies and element your page would call the php script using the AJAX POST method in javascript, then the php script would read the existing datafile, modify it accordingly and save it to the server.
For starters you will need a web server with PHP; if your testing locally MAMP is a good choice for Mac and I believe they now do a windows version as well.
Your would have 3 files( presuming all of your css and js is written in your HTML file):
index.htm
data.js
update.php
Assuming a linear list of div elements, each with a switchable class and child content.
index.htm
<html>
<head>
<script src='datafile.js'></script>
<script>
window.addEventListener('load',onload,false); //register the on load handler
function onload(){
var body = document.getElementsByTagName('body')[0];
var newelement;
for(var i = 0; i < elements.length; i++){
//for each element in the data file
newelement = document.createElement('div');
//create a div element
newelement.innerHTML = elements[i].content;
//place the content within the div
newelement.className = elements[i].class;
//set our classes
body.appendChild(newelement);
//add the div to the body
newelement.addEventListener('click',onclick,false);
//add a click listener to the element
}
}
function onclick(){ //on click function
var elementIndex = elements.indexOf(this); //this will be the element in the callback context
//modify class
postchange(elementIndex,classList);
}
function postchange(element,class){
// new post method
// data = {'element':element,'class':class};
// post data to update.php
}
</head>
<body>
</body>
</html>
data.js
var elements = [
{
"content":'Hello I am div 1',
"class":'classA'
},
{
"content":'Hi, I have been known as div 2... but you can call me Tim',
"class":'classA classB'
}
]
I've left the PHP out, it's not my main language so I don't feel happy improvising any code for you without looking it up and testing it first. That and it shouldn't be too hard for you to find information on POST methods on Stack Overflow.
Similarly I left the POST method in the JS out because the standard JS method is a little overcomplicated. Look up the jQuery POST method which is much more simple, again examples should be easy to find.

Getting the current script DOM object in a (jquery) ajax request

I have a html component that includes some javascript.
The component is a file in a template engine, so it can be used
in the initial rendering of the whole html page
as stand-alone html rendered through an ajax request
The javascript should be applied to an object in the template, i.e. :
<div class="grid" >
<div class="item" id="item_13">
This is item 13
</div>
<div class="item" id="item_14">
This is item 14
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$(HOW_DO_I_GET_PREVIOUS_ELEMENT???).someEffect(params)
})
</script>
I've checked this similar question but the best answers seem to rely on the current script being the last one in the 'scripts' variable as the next ones are not loaded yet. If I append the html and js with an ajax request, it will not be the case.
To be 100% clear : the question is about getting the previous object WITHOUT reference to any specific attribute : no unique id for the tag, no random id as there is theoretically always a chance it will show up twice, no unique class attribute,as exactly the same component could be displayed in another part of the HTML document.
Simple solution involving a two step process:
1) find out which element your script tag is
2) find the previous sibling of that element
in code:
<div id="grid">
<!-- ... -->
</div>
<script type="text/javascript">
var scripts = document.getElementsByTagName("script");
var current = scripts[scripts.length-1];
var previousElement = current.previousSibling;
// there may be whitespace text nodes that should be ignored
while(previousElement!==null && previousElement.nodeType===3) {
previousElement = previousElement.previousSibling; }
if(previousElement!==null) {
// previousElement is <div id="grid"> in this case
$(document).ready(function(){
$(previousElement).someEffect(params);
});
}
</script>
Is this good web programming? No. You should know which elements should have effects applied to them based on what you're generating. If you have a div with an id, that id is unique, and your generator can tell that if it generates that div, it will also have to generate the js that sets up the jQuery effect for it.
But let's ignore that; does it work? Like a charm.
If you can give your <script/> block an Id you could easily call prev() to get the previous element.
<script type="text/javascript" id="s2">
$(document).ready(function(){
$("#s2").prev().append("<h1>Prev Element</h2>");
})
</script>
Example on jsfiddle.
You will need to get a way to reference the script tag immediately after the "grid" div. As #Mark stated, the easiest way to do this is by giving the script tag a unique id. If this is beyond your control, but you do have control of the script contents (implicit by the fact that you are creating it) you can do something like this:
var UniqueVariableName;
var scripts = document.getElementsByTagName('script');
var thisScript = null;
for(var i = 0; i < scripts.length; i++){
var script = $(scripts[i]);
if(script.text().indexOf('UniqueVariableName') >= 0){
thisScript = script;
break;
}
}
if(thisScript){
thisScript.prev().append("<h1>Prev Element</h2>");
}
Hack? Yes. Does it Work? Also, yes.
Here's something that works in FF, Chrome and IE 8, untried anywhere else. It looks at the element before the last element on the page (which is the script being parsed), stores it locally (with a self calling function) so the load handler can use it.
http://jsfiddle.net/MtQ5R/2/
<div class="grid" >
<div class="item" id="item_13">
This is item 13
</div>
<div class="item" id="item_14">
This is item 14
</div>
</div><script>(function(){
var nodes = document.body.childNodes;
var prevSibling = nodes[nodes.length - 2];
$(document).ready(function(){
console.log( prevSibling );
})
})();</script>
Having said that. I still have to mention that you're tightly coupling the behavior (JS) and HTML, by putting them into the same file which kind of goes against the web flow of separating them. Also, I don't know how you'd expect this to work with an AJAX request since you're not just adding it to the HTML as it's being rendered. In that case, it would be very easy to get a reference to the html you just inserted though.

Categories