How in JavaScript fetch line from which the function was called? - javascript

The code below shows my almost complete page source (without doctype) and line number from where test() was called. Because code does not contain doctype then I when I do alert(code[line]) I don't get the right line.
<script>
function test(what)
{
var err = new Error;
var line = err.stack.split("\n")[1].split(':')[2];
var code = document.documentElement.outerHTML.split("\n");
console.log(code);
alert(line);
}
test('hello there');
<script>
How do I get 'test('hello there');' from my test function as a string?
The problem is with line numbering. My line returns the correct line number as in the source file, but my code returns page source with different numbering (it misses DOCTYPE and have different line breaks). So the question is: how to get the "real" page source?

A solution is to look not in the whole HTML document but in the right script element. It works but you'd need some care before to use it :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script>
function test(what) {
var err = new Error;
console.log(err.stack.split("\n"))
var line = err.stack.split("\n")[2].split(':')[1];
var script = document.scripts[0];
var code = (script.innerText||script.textContent).split(/<br>|\n/);
console.log(line);
console.log(code, code.length);
console.log(code[+line]); // this logs "test('hello there');"
}
test('hello there');
</script>
</body>
</html>
The first thing to do would probably be to give an id to your script element instead of relying on the number.
And I really wouldn't use such a thing apart for some short tests.
Demonstration (click "Run with JS")

Here's a working, but ugly solution. Ugly because:
1. Loads the same page again
2. Uses async ajax
<script>
function getSource()
{
var request = new XMLHttpRequest();
request.open('GET', location.href, false);
request.send(null);
if (request.status === 200)
{
return request.responseText;
}
return '';
}
function test(what)
{
var err = new Error;
var line = err.stack.split("\n")[1].split(':')[2];
var code = getSource().split("\n");
alert(code[line-1]);
}
test('hello there');
</script>

Related

Run A JavaScript Function Written In Called/Responce Data Of AJAX In Main Page

My problem is that I have a JavaScript function written in a PHP file and when I call it from AJAX request, I want to run that JavaScript function on the main page too after successful AJAX request. As an example, I have a main.html file where I have written an AJAXX function as below.
main.html
<script type="text/javascript">
/* AJAX Function
----------------------------------------------- */
function ajaxFunction() {
var FD = new FormData();
var ajx = new XMLHttpRequest();
ajx.onreadystatechange = function () {
if (ajx.readyState == 4 && ajx.status == 200) {
document.getElementById("mainContent").innerHTML = ajx.responseText;
hello(); //Uncaught ReferenceError: hello is not defined
}
};
ajx.open("POST", "/example.php", true);
ajx.send(FD);
document.getElementById("mainContent").innerHTML = 'Loading...';
return false;
}
</script>
And my example.php file contains a JavaScript function as
example.php
<?php
echo 'Some contents and functions';
echo '<script type="text/javascript">
function hello() {
alert("Hello");
}
</script>';
echo 'Some contents and functions';
?>
Now when I run index.html file, I get Uncaught ReferenceError: hello is not defined error in console rest I am seeing the function body is written on HTML page while inspecting elements on-page.
As I know that innerHTML does not run scripts. So what's the workaround to this problem. You can view the below-linked answer also that I think is related to my question but tried and not working with my problem.
Researched Questions/Answers:
https://stackoverflow.com/a/3250386/3170029
https://stackoverflow.com/a/47614491/3170029
As I shared and you know that innerHTML does not run scripts. so we have to look around it then I found a solution on StackOverflow and I am sharing here with this problem's answer.
main.html
<script type="text/javascript">
/* AJAX Function
----------------------------------------------- */
function ajaxFunction() {
var FD = new FormData();
var ajx = new XMLHttpRequest();
ajx.onreadystatechange = function () {
if (ajx.readyState == 4 && ajx.status == 200) {
setInnerHTML(document.getElementById("mainContent"), ajx.responseText); // does run <script> tags in HTML
hello();
}
};
ajx.open("POST", "/example.php", true);
ajx.send(FD);
document.getElementById("mainContent").innerHTML = 'Loading...';
return false;
}
//https://stackoverflow.com/a/47614491/3170029
var setInnerHTML = function(elm, html) {
elm.innerHTML = html;
Array.from(elm.querySelectorAll("script")).forEach(oldScript => {
const newScript = document.createElement("script");
Array.from(oldScript.attributes)
.forEach(attr => newScript.setAttribute(attr.name, attr.value));
newScript.appendChild(document.createTextNode(oldScript.innerHTML));
oldScript.parentNode.replaceChild(newScript, oldScript);
});
}
</script>
Its concept is clear. When you get the response data from PHP file then first extract <script ..... </script> tags from it and add them in index.html file hear by using createElement('script') and copy all the script to this then you can easily call your function after response data anywhere.
In other words, You can create an executing script element outside of that initial parse using the DOM method of calling createElement('script'), setting its src/content, and adding it to the document. The alternative is what jQuery's getScript90 does.

SoundCloud API gives "Uncaught SyntaxError: Unexpected token : " error

In the console it's giving me the error "Uncaught SyntaxError: Unexpected token : ", but if I access direct SoundCloud URL in my browser then it's giving valid JSON. Earlier this code was working fine and today this issue started.
<html>
<head>
<script src="https://api.soundcloud.com/resolve.json?url=https://api.soundcloud.com/tracks/251912676/?secret_token=s-EkyTy&client_id=08f79801a998c381762ec5b15e4914d5"></script>
</head>
<body>
<h2>hellooo</h2>
</body>
</html>
Update:
Below is the actual code for which I am asking the question, above html I just created for example.
SoundCloud.prototype._jsonp = function (url, callback) {
var target = document.getElementsByTagName('script')[0] || document.head;
var script = document.createElement('script');
var id = 'jsonp_callback_' + Math.round(100000 * Math.random());
window[id] = function (data) {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
window[id] = function () {};
callback(data);
};
script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + id;
target.parentNode.insertBefore(script, target);
};
I got the reason of issue, earlier soundcloud were responding response in jsonp but now they are providing JSON even I passed JsonP callback function. I had to make ajax request to fix it.
I used following code to fix it.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
callback( JSON.parse(this.responseText) );
}
};
xhttp.open("GET", url, true);
xhttp.send();
The following script tag expects JavaScript code in the source and not JSON.
<script src="file.js"></script>
I suppose that you want to use this externally produced json...
A way to "get" it is using an asynchronous ajax request like $.get(url,callback);
Calling it as a script will sure fail...
Because it's not a script.
Try to run the snippet!
var url = "https://api.soundcloud.com/resolve.json?url=https://api.soundcloud.com/tracks/251912676/?secret_token=s-EkyTy&client_id=08f79801a998c381762ec5b15e4914d5"
var json;
$.get(url,function(result){
json = result;
// show in console
console.log(JSON.stringify(json));
// Now using it...
$("#json_usage").html(json.tag_list+" and all the "+json.permalink);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<!--script src="https://api.soundcloud.com/resolve.json?url=https://api.soundcloud.com/tracks/251912676/?secret_token=s-EkyTy&client_id=08f79801a998c381762ec5b15e4914d5"></script-->
</head>
<body>
<h2>hellooo <span id="json_usage"></span> !</h2>
</body>
</html>
In the above, the resulting json is placed in the json variable and then console logged.
Sorry you've been having trouble with JSONP responses from the SoundCloud API. This was due to a bug that made it into production in the last few days. We've just deployed a fix, and so this endpoint will now be returning valid JSONP responses rather than just JSON, if you specify a callback parameter. Sorry for the confusion!

"Unexpected end of input" of the doctype tag when running AJAX asynchronous but not when synchronous

I've got this project where I get the error Uncaught SyntaxError: Unexpected end of input on line 1 of my HTML code, which is the DOCTYPE tag. I don't know how to fix this since the tag doesn't have a closing tag.. I only get this error when running the AJAX asynchronous, which I must do or the AJAX just gets stuck in an infinite loop manner.. I'm using this to interact with an API that grabs all the red days of a calendar year. Any ideas on how I fix this? I've been searching for an answer but I haven't found any that matches my problem.
Here's my AJAX code:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.dryg.net/dagar/v2/' + year, true);
xhr.send();
var json = JSON.parse(xhr.responseText);
for (item in json.dagar) {
var propertyObject = json.dagar[item];
for (subitem in propertyObject) {
if (subitem === 'röd dag') {
var redDay = propertyObject[subitem];
if (redDay === 'Ja') {
calendar.markRedDays(propertyObject.datum);
break;
}
}
}
}
And this is the HTML:
<!DOCTYPE html> <--- This is where the error points to
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Online Calender</title>
<script src='https://cdn.firebase.com/js/client/1.1.1/firebase.js'></script>
<link href='http://fonts.googleapis.com/css?family=Port+Lligat+Sans' rel='stylesheet' type='text/css'>
<link rel='stylesheet' type='text/css' href='style.css'>
</head>
<body>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
<script src="firebase1.js"></script>
</body>
</html>
It appears that the response (xhr.responseText) is empty because the request is ascynchronous (it has not been received yet).
The method that throws that exception is JSON.parse.
A callback should be registered (as noted in the first comment on your question) to handle the response.
Please note that you should handle the case when the reposone is not JSON. For example, it may be an html page saying the an error has occured.
Good Luck
Ok, the truth is you need to learn how AJAX works and read the docs I linked in the comments.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.dryg.net/dagar/v2/' + year, true);
xhr.httpRequest.onreadystatechange = callbackFunction;
xhr.send();
alert("this alert is triggered after the request was sent but before it returned")
Now the request is sent, and it will eventually return, but your code will keep on running through the normal flow. Once the request returns it will trigger the "onreadystatechange" event. Thanks to the line I added above this will call your callbackFunction. This should look as follows:
var callbackFunction = function(){
// This is the state when the xhr request has returned, see the docs
if (xhr.readyState === 4) {
// This means there was no error.
if (xhr.status === 200) {
//Here you can access the response of the xhr
var json = JSON.parse(xhr.responseText);
for (item in json.dagar) {
var propertyObject = json.dagar[item];
for (subitem in propertyObject) {
if (subitem === 'röd dag') {
var redDay = propertyObject[subitem];
if (redDay === 'Ja') {
calendar.markRedDays(propertyObject.datum);
break;
}
}
}
}
} else {
alert('There was a problem with the request.');
}
}
If it's still unclear look at the example on the MDN docs page

document.write() after window.onload [duplicate]

I am creating a simple ajax call that retrieves the content of a specified url and writes it to the page. The problem I am having is that it replaces the entire body contents with this information
here is the JS:
(function(){
var mb = window.mb = {};
function get_ad(url, parameters){
var result = "";
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/html');
}
} else if (window.ActiveXObject) { // IE
var avers = ["Microsoft.XmlHttp", "MSXML2.XmlHttp", "MSXML2.XmlHttp.3.0", "MSXML2.XmlHttp.4.0", "MSXML2.XmlHttp.5.0"];
for (var i = avers.length -1; i >= 0; i--) {
try {
http_request = new ActiveXObject(avers[i]);
if (http_request){
break;
}
} catch(e) {}
}
}
if (!http_request) {
alert('Cannot create XMLHTTP instance');
return false;
}
http_request.onreadystatechange = function(){
if (http_request.readyState == 4) {
if (http_request.status == 200) {
gen_output(http_request.responseText);
} else {
alert('Error');
}
}
}
http_request.open('GET', url + parameters, true);
http_request.send(null);
}
function gen_output(ad_content){
document.write("<div id=\"mb_ad\">");
document.write(ad_content);
document.write("</div>");
}
get_ad("http://localhost/test/test.html", "");
})();
and here is the html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
i am text before <br/>
<script type="text/javascript" src="mb.js"></script>
<br />
i am text after
</body>
</html>
using firebug to inspect, i do not see the text before or the text after, just the <div id="mb_ad"> and the content from the test.html page. If i remove the ajax call and just do 3 document.writes the text before and the text after will display properly. jQuery is not an option, I have to do this without the help of a large library as size and speed are of the essence.
You can't use document.write once the document has completed loading. If you do, the browser will open a new document that replaces the current.
Use the innerHTML property to put HTML code inside an element:
function gen_output(ad_content){
document.getElementById('mb_ad').innerHTML = ad_content;
}
Put the element before the script, so that you are sure that it exists when the callback function is called:
i am text before
<div id="mb_ad"></div>
i am text after
<script type="text/javascript" src="mb.js"></script>
It doesn't matter much where you place the script, as nothing will be written to the document where it is.
in case you cant control the remote script you might be able to write something like so:
<script>
var tmp = document.write;
document.write = function () {
document.getElementById('someId').innerHTML = [].concat.apply([], arguments).join('');
};
</script>
<script .....>
document.write = tmp;
Well it is a nasty hack but it seems to work...
var div = document.createElement('div');
div.id = 'mb_ad';
div.innerHTML = ad_content;
Now, you can append this node wherever you want it to be.
you can use <script>document.body.innerHTML+="//Your HTML Code Here";</script>
Same Leon Fedotov answer but more jQuery
{
var old_write = document.write;
var $zone = $('.zone.zone_' + name);
// redefine document.write in this closure
document.write = function () {
$zone.append([].concat.apply([], arguments).join(''));
};
// OA_output[name] contains dangerous document.write
$zone.html(OA_output[name]);
document.write = old_write;
}
I had the same problem with the following code :
$html[] = '<script>
if($("#mf_dialogs").length == 0) {
document.write("<div id=\"mf_dialogs\"></div>");
}
</script>';
The following code replaces document.write efficiently :
$html = '<div id="dialogHolder"></div>
<script>
if($("#mf_dialogs").length == 0) {
document.getElementById("dialogHolder").innerHTML="<div id=\"mf_dialogs\"></div>";
}
</script>';
The way you can emulate document.write somewhat is the following code:
<script>
(function(script) {
var parent = script.parentNode;
var node = document.createTextNode('Surprise!');
parent.replaceChild(node, script);
})(document.currentScript);
</script>
This way you can put arbitrary HTML in place of a script element. If you have a simpler case, like you can wrap a script in another tag, you can do even simpler version.
<script>
document.currentScript.parentElement.innerHTML = 'Surprise!';
</script>

JavaScript Document.Write Replaces All Body Content When Using AJAX

I am creating a simple ajax call that retrieves the content of a specified url and writes it to the page. The problem I am having is that it replaces the entire body contents with this information
here is the JS:
(function(){
var mb = window.mb = {};
function get_ad(url, parameters){
var result = "";
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/html');
}
} else if (window.ActiveXObject) { // IE
var avers = ["Microsoft.XmlHttp", "MSXML2.XmlHttp", "MSXML2.XmlHttp.3.0", "MSXML2.XmlHttp.4.0", "MSXML2.XmlHttp.5.0"];
for (var i = avers.length -1; i >= 0; i--) {
try {
http_request = new ActiveXObject(avers[i]);
if (http_request){
break;
}
} catch(e) {}
}
}
if (!http_request) {
alert('Cannot create XMLHTTP instance');
return false;
}
http_request.onreadystatechange = function(){
if (http_request.readyState == 4) {
if (http_request.status == 200) {
gen_output(http_request.responseText);
} else {
alert('Error');
}
}
}
http_request.open('GET', url + parameters, true);
http_request.send(null);
}
function gen_output(ad_content){
document.write("<div id=\"mb_ad\">");
document.write(ad_content);
document.write("</div>");
}
get_ad("http://localhost/test/test.html", "");
})();
and here is the html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
i am text before <br/>
<script type="text/javascript" src="mb.js"></script>
<br />
i am text after
</body>
</html>
using firebug to inspect, i do not see the text before or the text after, just the <div id="mb_ad"> and the content from the test.html page. If i remove the ajax call and just do 3 document.writes the text before and the text after will display properly. jQuery is not an option, I have to do this without the help of a large library as size and speed are of the essence.
You can't use document.write once the document has completed loading. If you do, the browser will open a new document that replaces the current.
Use the innerHTML property to put HTML code inside an element:
function gen_output(ad_content){
document.getElementById('mb_ad').innerHTML = ad_content;
}
Put the element before the script, so that you are sure that it exists when the callback function is called:
i am text before
<div id="mb_ad"></div>
i am text after
<script type="text/javascript" src="mb.js"></script>
It doesn't matter much where you place the script, as nothing will be written to the document where it is.
in case you cant control the remote script you might be able to write something like so:
<script>
var tmp = document.write;
document.write = function () {
document.getElementById('someId').innerHTML = [].concat.apply([], arguments).join('');
};
</script>
<script .....>
document.write = tmp;
Well it is a nasty hack but it seems to work...
var div = document.createElement('div');
div.id = 'mb_ad';
div.innerHTML = ad_content;
Now, you can append this node wherever you want it to be.
you can use <script>document.body.innerHTML+="//Your HTML Code Here";</script>
Same Leon Fedotov answer but more jQuery
{
var old_write = document.write;
var $zone = $('.zone.zone_' + name);
// redefine document.write in this closure
document.write = function () {
$zone.append([].concat.apply([], arguments).join(''));
};
// OA_output[name] contains dangerous document.write
$zone.html(OA_output[name]);
document.write = old_write;
}
I had the same problem with the following code :
$html[] = '<script>
if($("#mf_dialogs").length == 0) {
document.write("<div id=\"mf_dialogs\"></div>");
}
</script>';
The following code replaces document.write efficiently :
$html = '<div id="dialogHolder"></div>
<script>
if($("#mf_dialogs").length == 0) {
document.getElementById("dialogHolder").innerHTML="<div id=\"mf_dialogs\"></div>";
}
</script>';
The way you can emulate document.write somewhat is the following code:
<script>
(function(script) {
var parent = script.parentNode;
var node = document.createTextNode('Surprise!');
parent.replaceChild(node, script);
})(document.currentScript);
</script>
This way you can put arbitrary HTML in place of a script element. If you have a simpler case, like you can wrap a script in another tag, you can do even simpler version.
<script>
document.currentScript.parentElement.innerHTML = 'Surprise!';
</script>

Categories