Protovis JavaScript doesn't work in dropdownlist onchange event - javascript

I noticed the following problem. When I remove either block of code, either one works well but when I put them together, only one of it worked.
I am trying to call a method from a dropdownlist using the onchange event but its fails when my code for Protovis/JavaScript is added.
<script type="text/javascript">
function getDate()
{
alert("dateValue");
}
</script>
<script type="text/javascript+protovis">
function Colour(color) {
new pv.Panel()
.width(12)
.height(20)
.anchor("center").add(pv.Dot)
.strokeStyle(null)
.fillStyle(color)
.radius(5)
.root.render();
}
</script>
<select name="mydropdown" onchange="getDate(this)">
<option value="None">Select Date</option>
</select>
I want to get both of them to work properly.

The above code works as expected here: http://jsfiddle.net/nrabinowitz/NAEku/
But, when I actually call the Colour() function elsewhere on the page, there's an error, and my guess is that's the root of your problem. The issue here is that when you use a script block with type="text/javascript+protovis", it gets eval'd by the Protovis library after the page is fully loaded - so any functions or variables you define in a javascript+protovis block won't be available in the global scope for normal script blocks further down the page.
So my guess is that you're trying to call Colour() before the Protovis block has been evaluated. The quick fix for this example, since you're not using any special Protovis syntax, is to just change the script block to type="text/javascript", which will cause it to be evaluated normally.
Updated, functional jsFiddle here: http://jsfiddle.net/nrabinowitz/NAEku/1/

Related

Script is written dynamically with variables inside SRC, but it does not executes as when it's written statically

I've been trying to show a post list in Blogger that varies depending on the month/year. How this exhibition is dynamic, I need to pass these two values (month/year) to a variable inside <script> tag's src attribute – what I'm able to do –, but the script is not executed (even being written inside the HTML). Below, I write how the code works and what I've done until now:
<script>
function textospordata(json) {
// Here the commands that write a list with specific texts go.
}
</script>
<!-- The static script (with fixed values) works. The callback textsbydate() is executed and the texts are listed. -->
<script src="http://mysite.blogspot.com/feeds/posts/default?published-min=2019-05-01T00:00:00&published-max=2019-05-31T23:59:59&orderby=published&alt=json-in-script&callback=textsbydate"></script>
<!-- When it's written dynamically, the script is even created inside the page, but the callback isn't called and so the texts aren't listed. -->
<script>
const urlAno = '2019'; // Year example. The code to get it is another.
const urlMes = '05'; // Month example. The code to get it is another.
const srcUrl = 'http://mysite.blogspot.com/feeds/posts/default?published-min='+urlAno+'-'+urlMes+'-01T00:00:00&published-max='+urlAno+'-'+urlMes+'-31T23:59:59&orderby=published&alt=json-in-script&callback=textsbydate';
var script = document.createElement('script');
script.src = srcUrl;
document.getElementById('body-post').appendChild(script);
</script>
Besides what is inside the snippet, I've already tried to write the <script> tag using document.write("<script src='"+srcUrl+"'></"+"script>");. I've already also tried to insert the code inside a function and call it separately, and besides to try to use the onload and a script.async: false.
In every attempt, the <script> tag is written inside the HTML exactly how it should be written (<script src="http://mysite.blogspot.com/feeds/posts/default?published-min=2019-05-01T00:00:00&published-max=2019-05-31T23:59:59&orderby=published&alt=json-in-script&callback=textsbydate"></script>, like in the example), but the texts are not listed and nothing works when compared to when it is written in the static way.
And at last, I believe the soluction be to do the dynamic script be executed synchronously. I think it must be executed before page's DOM. I've tried to read some answers to similar questions here at S.O., but without success. And in addition, the console does not show any error about it.
What may be wrong in my code?

Is it ok to add elements to documentElement (the <html> element)? Will anything unexpected happen?

Are there any issues with code like the following?
document.documentElement.insertAdjacentHTML('beforeend', `
<div style="border: 5px solid pink">This content is outside the <body>, but both Firefox and Chrome render it fine.</div>
`)
Is this reliable? Or can there be issues in some browsers? From what I can tell, it is totally fine in Firefox and Chrome.
I can't find any information about this, but it seems to work.
EDIT:
The reason I found for using document.documentElement, is we can rely on the fact that document.documentElement seems to be always defined no matter when a <script>'s code runs.
However, document.body is sometimes null depending on when a <script>'s code runs.
For example, consider the following code using document.body. If you stick it in a .html file, then open it in your browser, you will see the message null.
<script>
alert(document.body)
</script>
Here's a live example: https://plnkr.co/edit/PkhHjSHi6esfrl32
Now consider this code:
<script>
alert(document.documentElement)
</script>
The message that you will see is [object HTMLHtmlElement] (or similar). Live example: https://plnkr.co/edit/nSxtGZzN8tU0hCbq
This means, that to write code using document.body, it takes more effort and requires more code.
To get the document.body version to work, we have to do something like the following:
<body>
<script>
alert(document.body)
</script>
</body>
Live example: https://plnkr.co/edit/7BcZDZX4jemhwfcV. Of course, it's not that much more code, but when following the principle of simplicity, it seems that document.documentElement leads to slightly simpler code.
In my tests so far, it seems to work just fine (anything outside the of the eventually-created <body> renders as a sibling to the body element.
What problems may placing DOM elements in document.documentElement cause, that I have not forseen?
by default scripts run synchronously just like normal code. In normal code this won't work
const b = a + 1; // ERROR! a is not defined
const a = 1;
Because a does not exist when b is trying to use it you'll get an error. HTML and scripts are exactly the same
<script>
document.getElementById('a').textContent = 'yo!'; // ERROR <div id="a"> is not defined
</script>
<div id="a"></div>
fails for exactly the same reason as the JavaScript example. <div id="a"> does not exist when the script runs
This explains your <body> issue. If you put the script before the <body> tag then it does not yet exist. If you put it after then it does.
So the simple answer is you can do whatever you want as long as the things you want to reference exist when you try to reference them.
As for adding to the root element, yes you can do that. You don't have to have a body tag. In fact Google even suggests leaving it out.
note: I said above scripts run synchronously by default. There are plenty of ways to make them run later. The modern way is with the defer keyword though that way requires the script to be in a separate file. An old and no longer recommended way is to use the load event using one of <body onload="someFunc()"> or window.onload = someFunc() or window.addEventListener('load', someFunc). In these cases the script actually runs immediately but then effectively sets a callback to be called when the rest of the page has finished loading. Most modern JavaScript no longer uses the load event and either puts the script after the stuff it needs to reference or uses defer. Also es6 modules always "defer"
note that <html> and <body> are special tags. The HTML element is always the root element whether you declare one or not. Also, both <html> and <body> will only have one element each regardless of how many you declare them. Further, <body>, if you declare it, will always be a child of the root element.

Page Specific JavaScript Function on Several Files of HTML

I have about 10 pages of HTML and each has a link to indexJS.js. I have a function loadMoreOnScroll() in the js file that is meant to run only for my index.html. But the loadMoreOnScroll() is run on all the pages as users scroll to the bottom.
How do I restrict loadMoreOnScroll() to only run for index.html?
Add classes to distinguish pages.
<body class="index">...
And with JavaScript:
if(document.body.className.match(/\bindex\b/)){
// code
}
of jQuery:
if($("body").hasClass("index")){
// code
}
Add a class to the body tag on the index then in javascript you can do something like
if(document.querySelector('body').className === 'myclass'){
loadMoreOnScroll();
}
Note: this assumes you have no other classes on the body. You could use a data attribute and do getAttribute('data-page') or something to similar effect.
You can just remove the loadMoreOnScroll() function from indexJS and create a new JavaSscript file with loadMoreOnScroll() in it. Be sure to include a reference to the new file in the index.html.
I'm assuming you're invoking loadMoreOnScroll from within your indexJS.js file, correct?
If so, the solution is to remove the function call from your javascript file and instead call it directly from index.html.
indexJS.js
// Create the function but don't call it here
function loadMoreOnScroll(){...}
index.html
<script src="indexJS.js></script>
<script>
// call the function
loadMoreOnScroll();
</script>
Edit:
A few other people suggested adding a body class and targeting your page that way. This approach is fine, and may work well in many scenarios but just keep in mind two things:
This works well for if you need to call your function on only one or two pages. Any more and you'll have to maintain a growing list of body classes within indexJS.js.
Using the body class as a hook decouples the function call from the page that its applies to.
In other words, the body class will have functionality tied to it that's not immediately obvious if you're only looking at the HTML. If you're working on the code yourself, you'll probably be ok, but in a team environment, it could be error-prone. (Or if you revisit the code after a few months). It all depends on the scope of your project.

Uncaught ReferenceError: function is not defined [duplicate]

This question already has answers here:
Why isn't my JavaScript working in JSFiddle?
(7 answers)
Closed 9 years ago.
Im doing a simple jquery function using rangy script but im not being able to get it work, it says the error above.
<div onclick="cmon('cenas');"> cenas </div>
<textarea class="guides_chapters_textarea" id="textarea" name="gmessage" rows="7" cols="25"> Insert starting items here</textarea>
Javascript:
function cmon(text){
$("#textarea").insertText(text, 0, "collapseToEnd");
}
Jsfiddle: http://jsfiddle.net/VmhMM/
To get your example working, there is a few things you can do. Strictly speaking, there is actually nothing wrong with your code. The fault lies in how your code is being used/added to the page.
Here is one method of getting your code to work, by setting the function on the window object directly.
window.cmon = function cmon(text){
$("#textarea").insertText(text, 0, "collapseToEnd");
}
Another method mentioned by #elclanrs in the comment on the question (which is a better option in this case) points to the setting in the left panel of the JSFiddle to do with where your function is being run. By default, it adds it to the onLoad event which makes the function out of scope as it is being defined inside the event. Here is exactly what JSFiddle did to your code:
$(window).load(function(){
function cmon(text){
$("#textarea").insertText(text, 0, "collapseToEnd");
}
});
The concept that is going on is known as closures. So when you define a function, any variables or other functions defined inside of that are not accessible externally. If you set the variable on a global object or any other object outside the scope of your newly defined function (like I did in the example I linked), you can access what you defined outside of the closure.
You must use (no wrap in head) at the left side. This means you must load this script between tags. But If you still want to use it onload then:
<div id="cmon"> cenas </div>
<textarea class="guides_chapters_textarea" id="textarea" name="gmessage" rows="7" cols="25"> Insert starting items here</textarea>
<script>
$("#cmon").click(function(){
cmon($(this).text());
});
function cmon(text){
$("#textarea").insertText(text, 0, "collapseToEnd");
}
</script>
Here is the solution : http://jsfiddle.net/VmhMM/2/

Javascript error in Chrome and Mozilla but not Opera. Name not defined

So I have recently started programming pages... Little thins and I was trying something in a page that I had done previously so I just copied the code and changed the values. I was wondering if anyone can shade some light why it worked fine in my Opera browser but not on my Chrome or Firefox (I was using wamp for my computer act as a localwebserver)
What I did was using a element and the change of it's value (the user selecting a date) to call a function that went to use ajax and call a database and return stuff, I don't think the details are needed)
So I had the following
<select name="daySelector" id="daySelectorId" onchange="changeDate(daySelector.value)">
<option value="-1">Day</option>
<option value="2012-01-30">2012-01-30</option>
<option value="2012-01-31">2012-01-31</option>
<option value="2012-02-01">2012-02-01</option>
<option value="2012-02-02">2012-02-02</option>
<option value="2012-02-03">2012-02-03</option>
<option value="2012-02-04">2012-02-04</option>
<option value="2012-02-05">2012-02-05</option>
<option value="2012-02-06">2012-02-06</option>
<option value="2012-02-07">2012-02-07</option>
<option value="2012-02-08">2012-02-08</option>
<option value="2012-02-09">2012-02-09</option>
<option value="2012-02-10">2012-02-10</option>
<option value="2012-02-11">2012-02-11</option>
<option value="2012-02-12">2012-02-12</option>
<option value="2012-02-13">2012-02-13</option>
</select>
Opera worked just fine and returned what I wanted...
But Chrome and Firefox for some reason say that daySelector is not defined... When I use the 'this' reference all browsers work just fine. The funny thing is that the project I took the code from was something I did before I update my pc which had only firefox installed (an older version that is) and I am pretty sure it didn't cause any problems...
So any ideas. I realize this is not a problem per se but I am curious about details like this and I wanted to know... BTW, to those that have programmed in html/ajax/js/... for more than a few months... Should I just pass the whole element and take what I need inside the function?
Opera is likely referencing document.daySelector.value whereas FF and Chrome are referencing window.daySelector.value. Replace with this.value it will be bound to the node.
Replace your onchange with: onchange="changeDate(this.value)"
daySelector isn't defined in that context. Opera must handle it for you or silently be consuming the error.
Replace
onchange="changeDate(daySelector.value)"
with
onchange="changeDate(this.value)"
this should work fine
The submitted answers are correct, however I would urge you to look at jQuery as this would be a lot simpler and it is cross browser.
For example:
// Select the form element by id using the jQuery selector
var daySelector = $('#daySelectorId');
// Set the onchange event
daySelector.onChange(function(){
// Get the value of the form element
var value = $(this).val();
// Call the change date function
changeDate(value);
});
I appreciate that this may seem a little complex, but if you break it down it will make sense, that is why I have put in clear comments.
Once you have 'got the jist' of jQuery, you will be able to compress the above statement into:
$('#daySelectorId').onChange(function(){changeDate($(this).val())});
Just place this into your javascript code and remove the 'onchange=changeDate(day...' attribute from your html.
You will not need to worry about this not working cross browser
Make sure you look at the jQuery documentation to learn how to implement it. Again, it is very easy. Quick example using Google Code (dont forget to get an API key from Google, link found below):
<script type="text/javascript" src="http://www.google.com/jsapi?key=GENERATED_API_KEY"></script>
<script type="text/javascript">
google.load("jquery", "1.7.1");
</script>
The above will simply load jQuery into your website. Place this into all of your webpages that you would like to use it.
Get your API key here: http://code.google.com/apis/loader/signup.html
Hope this helps

Categories

Resources