ReferenceError: [...] is not defined - javascript

I am trying to use a JS function which is in an another JS file and I have this error :
ReferenceError: Lanceur is not defined
Lanceur is my object which is defined in my second file.
I have a constructor :
public class Lanceur {
constructor(angleAiguille) {
this.angleAiguille = angleAiguille;
} // And functions .....
I have this line in my first file : lanceur = new Lanceur(0);
And I call my files in a HTML files with <script src="js/canvas.js" type="text/javascript"></script>, for example.

You need to create the class before you can create an instance of it. You also don't need the keyword public as browsers don't support it currently (Unless you're compiling this through Babel or something similar, but that wasn't obvious from your post).
In your first file include the code that makes up the class, I've added a method as an example.
class Lanceur {
constructor(angleAiguille) {
this.angleAiguille = angleAiguille;
}
someMethod() {
console.log('Firing')
}
}
You can then create an instance of it like so in your second file and call its methods.
const instance = new Lanceur;
// Calling a method...
instance.someMethod();
You can learn more about JavaScript class constructors here.

Related

Odoo Override Javascript Class Method

First off, my apologies - I'm a complete novice when it comes to javascript so this is a bit above my head. I'm also fairly new to Odoo and have mostly stuck with python and XML customization thus far.
I'm trying to override a javascript method within a class to replace it completely with my own version. From the Odoo documentation (https://www.odoo.com/documentation/14.0/reference/javascript_reference.html#patching-an-existing-class) this should be a simple matter of using the .include() method to patch the original class with my new method. But when I do this I get an error Error while loading mymodule.CustomControlPanelModelExtension: TypeError: ControlPanelModelExtension.include is not a function
The original Odoo code that I'm trying to override:
odoo.define("web/static/src/js/control_panel/control_panel_model_extension.js", function (require) {
"use strict";
// a bunch of code here ...
class ControlPanelModelExtension extends ActionModel.Extension {
// more code here ...
// this is the method I'm trying to override
_getAutoCompletionFilterDomain(filter, filterQueryElements) {
// original method body here
}
// more code
}
// more code
});
Below is what I came up with based on the documentation but this gives me the error Error while loading mymodule.CustomControlPanelModelExtension: TypeError: ControlPanelModelExtension.include is not a function (this error is reported in browser dev tools console).
odoo.define('mymodule.CustomControlPanelModelExtension', function(require) {
"use strict";
var ControlPanelModelExtension = require('web/static/src/js/control_panel/control_panel_model_extension.js');
ControlPanelModelExtension.include({
// override _getAutoCompletionFilterDomain
_getAutoCompletionFilterDomain: function(filter, filterQueryElements) {
// my custom implementation here
},
});
});
Any ideas what I'm doing wrong here? I've tried various other things with extends and such but I don't think I want to extend - that won't replace the function in existing instances.
The problem here is that the include function is available only for the classes that inherit from OdooClass and in this case the class you are trying to inherit is a native JavaScript class.
Then, to add a property or method to a class, the prototype property of the object class must be modified.
odoo.define('mymodule.CustomControlPanelModelExtension', function(require) {
"use strict";
const ControlPanelModelExtension = require('web/static/src/js/control_panel/control_panel_model_extension.js');
function _getAutoCompletionFilterDomain(filter, filterQueryElements) {
// your custom implementation here
}
ControlPanelModelExtension.prototype._getAutoCompletionFilterDomain = _getAutoCompletionFilterDomain;
return ControlPanelModelExtension;
});

Call a function that is in another js file

I removed my JS code in separate file and now I want to call it and execute it in the one that it was before. My new file name is blockedComponents.js. I added it in BundleConfig and I am trying to call it methods like this:
function getBlockedComponentsMethods()
{
BlockedComponents.pageChangedHandler();
}
My function in the new file is called
function BlockedComponents();
Should I require it somehow , because now I have error that pageChangedHandler is not defined?
Sorry, I didn't get what are you trying to do here, but in general :
If you would like to call a static method like this :
BlockedComponents.pageChangedHandler();
You should do something like the following :
function BlockedComponents() {
//Code here ...
}
BlockedComponents.pageChangedHandler = function() {
//Code here ...
};

How to expose JS patch function of Incremental DOM library in GWT app using #JsInterop

I would like to use Incremental DOM library in my GWT app.
https://google.github.io/incremental-dom/#about
As I am coming from the Java world, I struggle with concepts of JavaScript namespaces and modules. I was able to use Closure Compiler with closure version of Incremental DOM (has to be build from sources).
It starts with the following line:
goog.module('incrementaldom');
So if I was to use it in regular JS I would type:
var patch = goog.require('incrementaldom').patch;
And then the patch function would be available in the scope of my code. But how to make it accessible from #JsInterop annotated classes?
I tried something like:
public class IncrementalDom {
#JsMethod(namespace = "incrementaldom", name = "patch")
public static native void patch(Element element, Patcher patcher);
#JsFunction
#FunctionalInterface
public interface Patcher {
void apply();
}
}
But it doesn't work. I get this error in the runtime:
(TypeError) : Cannot read property 'patch' of undefined
So I guess I have to somehow expose the incrementaldom module or at least only the patch method. But I don't know how.
After fighting for the whole day I found the solution. In the goog.module: an ES6 module like alternative to goog.provide document I found the missing information about the role of goog.scope function - required modules are visible only within the scoped call.
I created another Closure JS file named incrementaldom.js:
goog.provide('app.incrementaldom'); // assures creation of namespace
goog.require("incrementaldom");
goog.scope(function() {
var module = goog.module.get("incrementaldom");
var ns = app.incrementaldom;
app.incrementaldom.patch = module.patch;
});
goog.exportSymbol("app.incrementaldom", app.incrementaldom);
And now I can call it from Java code like this:
public class IncrementalDom {
#JsMethod(namespace = "app.incrementaldom", name = "patch")
public static native void patch(Element element, Patcher patcher);
#JsFunction
#FunctionalInterface
public interface Patcher {
void apply();
}
}
Still I have to define every object exported in original module separately in the Closure JS file. Fortunately I only need patch method. I hope one day I will find less cumbersome way for #JsInterop with goog.module :(

Is it possible to get the class or class name from inside a function?

I'm trying to write debugging tools and I would like to be able to get the class name of the caller. Basically, caller ID.
So if I have a method like so, I want to get the class name:
public function myExternalToTheClassFunction():void {
var objectFunction:String = argument.caller; // is functionInsideOfMyClass
var objectFunctionClass:Object = argument.caller.this;
trace(object); // [Class MyClass]
}
public class MyClass {
public function functionInsideOfMyClass {
myExternalToTheClassFunction();
}
}
Is there anything like this in JavaScript or ActionScript3? FYI AS3 is based on and in most cases interchangeable with JS.
For debugging purposes you can create an error then inspect the stack trace:
var e:Error = new Error();
trace(e.getStackTrace());
Gives you:
Error
at com.xyz::OrderEntry/retrieveData()[/src/com/xyz/OrderEntry.as:995]
at com.xyz::OrderEntry/init()[/src/com/xyz/OrderEntry.as:200]
at com.xyz::OrderEntry()[/src/com/xyz/OrderEntry.as:148]
You can parse out the "caller" method from there.
Note that in some non-debug cases getStackTrace() may return null.
Taken from the documentation:
Unlike previous versions of ActionScript, ActionScript 3.0 has no
arguments.caller property. To get a reference to the function that
called the current function, you must pass a reference to that
function as an argument. An example of this technique can be found in
the example for arguments.callee.
ActionScript 3.0 includes a new ...(rest) keyword that is recommended
instead of the arguments class.
Try to pass the Class name as argument:
Class Code:
package{
import flash.utils.getQualifiedClassName;
public class MyClass {
public function functionInsideOfMyClass {
myExternalToTheClassFunction( getQualifiedClassName(this) );
}
}
}
External Code:
public function myExternalToTheClassFunction(classname:String):void {
trace(classname); // MyClass
}

Forward declaration in Javascript

Background
I'm building a javascript based application that works differently on mobile and desktop devices. However, except for the DOM manipulation, most code is common between both platforms, so I have structured all files like:
* foo.core.js
* foo.mobile.js
* foo.web.js
And hoping to leverage object oriented techniques to write cleaner code.
Problem:
I have two JavaScript files, with classes
File 1:
function ClassA()
{}
ClassA.prototype.foo = function(){};
GreatGrandChildA.prototype = new GrandChildA(); // this is where the error is
function GreatGrandChildA ()
{}
File 2:
ChildA.prototype = new ClassA();
function ChildA () // ChildA inherits ClassA
{}
GrandChildA.prototype = new ChildA()
function GrandChildA () // GrandChildA inherits ClassA
{}
Normally, in a language like C++, I would forward declare GrandChildA right in File 1. I would like to know how to do it in Javascript
Edit:
If I make a single file containing all four classes - in the same order in which they are loaded, the example works exactly as expected:
http://jsfiddle.net/k2XKL/
Simple logic for unordered js file loading:
File1:
// ClassB: inherite from ClassA
(function ClassB_Builder() {
if(window.ClassB)return; // ClassB is already defined;
if(!window.ClassA) { // ClassA is already not defined;
setTimeout(ClassB_Builder,0); // shedule class building
return;
}
ClassB=function() {
}
ClassB.prototype=new ClassA;
ClassB.prototype.constructor=ClassB; // can be important for inheritance!!!
})();
File2:
// ClassA: base class
(function ClassA_Builder() {
ClassA=function() {
}
})();
// ClassC: inherite from ClassB
(function ClassC_Builder() {
if(window.ClassC)return; // ClassC is already defined;
if(!window.ClassB) { // ClassB is already not defined;
setTimeout(ClassC_Builder,0); // shedule class building
return;
}
ClassC=function() {
}
ClassC.prototype=new ClassB;
ClassC.prototype.constructor=ClassC; // can be important for inheritance!!!
})();
I assume that on your HTML page, you import File 1 and then File 2.
In File 1, you should see exception because "GrandChildA" is undefined. The function declaration is not done because File 2 has not loaded yet.
In File 2, you're being able to do:
ChildA.prototype = new ClassA();
function ChildA () // ChildA inherits ClassA
{}
because the Javacript runtime hoisted your named function "ClassA" before the code executes until ChildA.prototype = new ClassA();
Please read more about function hoisting and should you be doing it in such situation at http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
The most sane way to accomplish what you want, is to make 2 separate versions of your source code. You're going to want to minify, obfuscate your code and merge all the source files anyway, so it would make sense to create a build script (python would be a great language for a simple build script) that you configure to merge mobile specific files into one (plus the files that both versions share) and non-mobile specific files into another file (and shared files also). In addition you could later add automatic obfuscating and gzipping. Then you can serve the appropriate source version to the appropriate client.
As mentioned in the comments, the requested functionality is not possible.
This is not only a technical problem but also an indication that
the application is not structured appropritately - the design should be improved.
Now, there is a kind of a circular dependency that shoul be avoided.
For comparison you mention that you would solve it in C++ by a forward declaration
of the superclass. But this is also not possible. In C++,
in order to declare a subclass you need to include the file with the
declaration of the superclass. And you cannot solve the problem when there are circular dependencies.

Categories