Function Undefined: Must a javascript function be defined within the same file? - javascript

I've got a file notifications.js containing one event bound to an element, and a function updateNotification(). This function uses jQuery to update certain elements on the page when a JSON object is passed as a parameter.
The problem:
I'm attempting to call this function within the page (via <script> tags), however rather than calling it, it breaks the page. I did some digging around within the Chrome Developer Console (not sure of the name), and an error is flagged:
/pleaseshare/views/install/:50 Uncaught ReferenceError:updateNotification is not defined
However, when I pan within the console, I can clearly see the file notifications.js listed under scripts, and the function is defined there. If I define the function within the current scope (e.g. the line above the call), it works fine.
What I've tried
The function contains some javascript that requires jQuery, so I've attempted both with and without encasing it in $(document).ready( function() {});, with neither seeming to have any affect.
I'm pretty stumped.
For good measure, here's a link to show the structure of my javascript and html: http://snippi.com/s/znk6xe9
Any help in figuring out why this is happening, or explanations of why javascript functions cannot be called cross-file (although I'd hope this isn't the case), would be greatly appreciated ;)!!

A function cannot be called unless it was defined in the same file or one loaded before the attempt to call it.
A function cannot be called unless it is in the same or greater scope then the one trying to call it.
You code looks like the structure should work, but is clearly a reduced test case that has been reduced to the point where it won't.

Got it working. The issue was definitely multi-faceted, but I figured it out.
First off the use of RequireJS had an impact on updateNotification(), in that it couldn't be called cross-file, and was therefore considered undefined. I assume this because of how RequireJS loads files, and I'll look into the documentation later (and post an edit if I find anything relevant).
Secondly, updateNotification() would again be considered undefined when encased within jQuery's DOM ready loader $(document).ready(function(){}). However updateNotification() contains executions which require jQuery, so I had to encase the contents of the function in $(document).ready(function(){}).
This is an issue very unique to RequireJS/jQuery, hence why in most use cases this wouldn't occur.
Side note: The tags are edited to reflect this.

you need to import your script into your page:
<script type="text/javascript" language="javascript" src="path/to/notifications.js"></script>
This needs to be added above the <script> tag that calls updateNotification()

Functions do not need to be declared in the same file. In fact, avoiding having every declaration dumped into the global namespace is usually a concern in JavaScript.
In the sample code in the link you provided, updateNotification is declared as a global, so there should not be a scoping problem.
However, in the same sample, you don't show notifications.js being included. You need to import it using a <script></script> element and that element must come before the script element that includes the call to updateNotification. You also must include jQuery before notifications.js, since it uses jQuery. So you need something like:
<body>
// One or two elements
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="notifications.js"></script>
<script type="text/javascript">
$(document).ready( function() {
var json = {status : 'ok', message: 'Hello'};
updateNotification(json);
});
</script>
// All other elements
</body>

Related

React - Using external js from CDN

Sorry, I put this again since the old post got merged into some post that doesn't relate to my question ... I'm new to React and trying to convert a php website into react components. However, in old website there are some function in pure jquery and from CDSNJS. The external javascripts function are not binding well with my component and I cannot figure out how to. Please can anyone give me some advice.
Case 1:
I got a an external function like this:
;(function ($) {
/* Global variables */
var prty, flickr;
$.fn.flickrGallery = function(flickrID) {
//Defaults settings
var opts = $.extend({}, {
Key:prty.settings["Key"],
Secret:prty.settings["Secret"],
User:prty.settings["User"],
PhotoSet:flickrID,
Speed:400,
navigation:1,
keyboard:1,numberEl:1 });
//Setup
prty.Setup($(this), opts);
}; //End FN
prty = {
.... Internal code
};
})(jQuery);
And this is my component's code:
async componentDidMount() {
//$('#gallery').flickrGallery(2); // Not work
//const el = ReactDOM.findDOMNode(this.display); Not work
//$(el).vectorMap({map: 'world_mill_en'});
//$(el).flickrGallery(2);
//const el = ReactDOM.findDOMNode(this.domRef); Not work
//window.$('#addSupModal').modal('show')
//$(el).flickrGallery(2);
window.$(this.productIntro).flickrGallery(2); Not work
}
Every time I run, an error like this appears:
Unhandled Rejection (TypeError): window.$(...).flickrGallery is not a function
Case 2:
Beside the case above, I'm also using a lib from CDNJS
<!-- jQuery 1.8 or later, 33 KB -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Fotorama from CDNJS, 19 KB -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fotorama/4.6.4/fotorama.js"></script>
I have tried including these links into index.html but the same error as above happens when I run ... Please help
Try to access the flickrGallery function via window.jQuery instead of window.$.
The plugin add the flickrGallery function to jQuery. In most of the time, jQuery should be the same as $. However, in some cases, multiple version of jQuery are loaded and jQuery may no longer be equals to $.
The following suggestions were told to be not solving the problem. I will keep them below in case someone find it useful.
It looks like your react component script is executed and rendered before the external scripts is being executed. There are many causes to it and one of the reasons is the ordering of your script tags.
In the document head, make sure the ordering of your script tag is as follow.
<script src="path/to/external/library.js"></script>
<script src="path/to/your/react/script.js"></script>
These script tags do not have the defer nor async attribute, suggesting they should be downloaded, parsed and executed in order. The external script is executed first.
In other cases, where there are defer, async, etc. attributes are in the script tag, you can understand the order of execution by reading this cheat sheet.
If you are using plugin which adds its functionality to some global variable, your bundler may tree-shake it away because it does not detect any usage of its exports and thinks the module is not needed. In this case, you have to add side effect import (Doc).
In your entry module, add this at the very top:
import 'some-jquery-plugin'

Reassigning javascript function in an attached js file

I have an HTML page with multiple attached js files that include functions that are used on that page.
For functions that are included on the base HTML page they are successfully re-assigned. FunctionA = FunctionB.
The problem comes when I try to reassign a function that is part of one of the attached js files. The normal reassignment doesn't work. Say FunctionC is on attached js file more functions.js .
I try FunctionC = FunctionD. FunctionC runs as it would normally - WITHOUT the reassignment to FunctionD. I know the reassignment to FunctionD 'should' occur before the FunctionC runs because it fires when I check with console.log.
Any ideas as to why this isn't working would be appreciated.
You have to make your reassignments after included file.
For example (Disclamer: don't do this in real projects - this is for demo purposes only) the code below includes jQuery library, but then overwrites jQuery function with a custom one:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
jQuery = function(s) {
alert(s);
}
</script>
<script>
jQuery('aaa');
</script>
when this runs it produces alert (demo), but if you reverse the order of first two script tags - original "attached" jQuery function will take over.

Why does the global jQuery object get overwritten after the page loads?

I'm writing a jQuery extension contained in a self executing function:
(function($) {
// global variables for the purposes of this test
__$ = $;
__$support = $.support;
$.support.abc = "123";
// Setup for my extension goes here.
})(jQuery);
On my test page, I have
<script type="text/javascript" src="jquery-1.5.2.js"></script>
<script type="text/javascript" src="myplugin.js"></script>
<script type="text/javascript">
$(function() {
console.log(__$ === $); // false
console.log(__$support === $.support); // false
console.log($.support.abc); // undefined
});
</script>
Why does this happen? I have no other scripts or jQuery plugins that might overwrite the jQuery object.
I haven't been able to find what code in the jQuery source itself overwrites the jQuery object after the document is ready. Any ideas?
If there's no way to avoid this, what would be the correct procedure for defining new properties on the jQuery.support object that can still be accessed after the document is ready?
EDIT: I omitted a critical part of my test code that inadvertently reevaluated the jQuery source -- and explains why this issue was happening. See my answer below.
Something is wrong because I get the correct output.
Wow, I feel stupid.
My test code (the part that I hadn't posted in the question) was intentionally calling jQuery.ajax() on jquery-1.5.2.js (since this is a reasonably big file for testing progress events). However, I had forgotten that unless one manually sets the dataType option to something other than script, jQuery will evaluate any JavaScript that's retrieved by jQuery.ajax().
So jQuery was evaluating a new copy of its own source code, and window.jQuery was therefore getting overwritten.

Google Website Optimiser Control Javascript

Could someone explain the javascript that makes up Google's Website Optimiser Control script? Specifically: the first two lines, which seem to be empty functions, and why is the third function wrapped parentheses () ?
As far as I can tell this script is basically writing out a new <script> which presumably loads something for A/B testing.
function utmx_section(){}
function utmx(){}
(function() {
var k='0634742331',d=document,l=d.location,c=d.cookie;
function f(n) {
if(c) {
var i=c.indexOf(n+'=');
if (i>-1) {
var j=c.indexOf(';',i);
return escape(c.substring(i+n.length+1,j<0?c.length:j))
}
}
}
var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
d.write('<sc'+'ript src="'+'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'+'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='+new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+'" type="text/javascript" charset="utf-8"></sc'+'ript>')
}
)();
I've attempted to step through with the firebug debugger but it doesn't seem to like it. Any insights much appreciated.
Many thanks
inside anonymous function it shortens names of document and cookies inside it at first, function f(n) gets value of cookie under name n. Then Google reads its cookies and with help of d.write it loads its scripts (as I see they are related to Google Analytic). This way it makes On-Demand JavaScript loading... Actually you load these scripts all the time, Google just needs some additional parameters in url, so this is done this way - save parameters in cookie, which next time are used to get script again.
And finally back to the first two magic lines :) After Google loads its script (after executing d.write), there are some functions which uses utmx and utmx_section, as well as definition of these functions, or better to say overriding. I think they are empty at first just because another function can execute it before its real definition, and having empty functions nothing will happen (and no JS error), otherwise script would not work. E.g. after first iteration there is some data, which is used to make real definition of these functions and everything starts to work :)
The first 2 functions are in fact empty, and are probably overridden later on.
The third function is an anonymous self-executing function. The brackets are a convention to make you aware of the fact that it is self executing.
the "f" function looks up the value given to it in the document's cookies and returns it. Then a new script tag is written to document (and requested from server) with these values as part of its URL.

Why is my JavaScript function sometimes "not defined"?

I call my JavaScript function. Why do I sometimes get the error 'myFunction is not defined' when it is defined?
For example. I'll occasionally get 'copyArray is not defined' even in this example:
function copyArray( pa ) {
var la = [];
for (var i=0; i < pa.length; i++)
la.push( pa[i] );
return la;
}
Function.prototype.bind = function( po ) {
var __method = this;
var __args = [];
// Sometimes errors -- in practice I inline the function as a workaround.
__args = copyArray( arguments );
return function() {
/* bind logic omitted for brevity */
}
}
As you can see, copyArray is defined right there, so this can't be about the order in which script files load.
I've been getting this in situations that are harder to work around, where the calling function is located in another file that should be loaded after the called function. But this was the simplest case I could present, and appears to be the same problem.
It doesn't happen 100% of the time, so I do suspect some kind of load-timing-related problem. But I have no idea what.
#Hojou: That's part of the problem. The function in which I'm now getting this error is itself my addLoadEvent, which is basically a standard version of the common library function.
#James: I understand that, and there is no syntax error in the function. When that is the case, the syntax error is reported as well. In this case, I am getting only the 'not defined' error.
#David: The script in this case resides in an external file that is referenced using the normal <script src="file.js"></script> method in the page's head section.
#Douglas: Interesting idea, but if this were the case, how could we ever call a user-defined function with confidence? In any event, I tried this and it didn't work.
#sk: This technique has been tested across browsers and is basically copied from the Prototype library.
I had this function not being recognized as defined in latest Firefox for Linux, though Chromium was dealing fine with it.
What happened in my case was that I had a former SCRIPT block, before the block that defined the function with problem, stated in the following way:
<SCRIPT src="mycode.js"/>
(That is, without the closing tag.)
I had to redeclare this block in the following way.
<SCRIPT src="mycode.js"></SCRIPT>
And then what followed worked fine... weird huh?
It shouldn't be possible for this to happen if you're just including the scripts on the page.
The "copyArray" function should always be available when the JavaScript code starts executing no matter if it is declared before or after it -- unless you're loading the JavaScript files in dynamically with a dependency library. There are all sorts of problems with timing if that's the case.
My guess is, somehow the document is not fully loaded by the time the method is called. Have your code executing after the document is ready event.
Verify your code with JSLint. It will usually find a ton of small errors, so the warning "JSLint may hurt your feelings" is pretty spot on. =)
A syntax error in the function -- or in the code above it -- may cause it to be undefined.
This doesn't solve your original problem, but you could always replace the call to copyArray() with:
__args = Array.prototype.slice.call(arguments);
More information available from Google.
I've tested the above in the following browsers: IE6, 7 & 8B2, Firefox 2.0.0.17 & 3.0.3, Opera 9.52, Safari for Windows 3.1.2 and Google Chrome (whatever the latest version was at the time of this post) and it works across all browsers.
If you're changing the prototype of the built-in 'function' object it's possible you're running into a browser bug or race condition by modifying a fundamental built-in object.
Test it in multiple browsers to find out.
This has probably been corrected, but... apparently firefox has a caching problem which is the cause of javascript functions not being recognized.. I really don't know the specifics, but if you clear your cache that will fix the problem (until your cache is full again... not a good solution).. I've been looking around to see if firefox has a real solution to this, but so far nothing... oh not all versions, I think it may be only in some 3.6.x versions, not sure...
Solved by removing a "async" load:
<script type="text/javascript" src="{% static 'js/my_js_file.js' %}" async></script>
changed for:
<script type="text/javascript" src="{% static 'js/my_js_file.js' %}"></script>
Use an anonymous function to protect your local symbol table. Something like:
(function() {
function copyArray(pa) {
// Details
}
Function.prototype.bind = function ( po ) {
__args = copyArray( arguments );
}
})();
This will create a closure that includes your function in the local symbol table, and you won't have to depend on it being available in the global namespace when you call the function.
This can happen when using framesets. In one frame, my variables and methods were defined. In another, they were not. It was especially confusing when using the debugger and seeing my variable defined, then undefined at a breakpoint inside a frame.
I'm afraid, when you add a new method to a Function class (by prtotyping), you are actually adding it to all declared functions, AS WELL AS to your copyArray(). In result your copyArray() function gets recursivelly self-referenced. I.e. there should exist copyArray().bind() method, which is calling itself.
In this case some browsers might prevent you from creating such reference loops and fire "function not defined" error.
Inline code would be better solution in such case.
I think your javascript code should be placed between tag,there is need of document load

Categories

Resources