Let's say I have an Object View original defined in one file View.js :
var View = (function () {
function View() {
}
View.prototype.SubFunc = function() {
}
return View;
})();
Now I want to be able to split in 2 files :
View.js
var View = (function () {
function View() {
}
return View;
})();
and SubFunc.js
View.prototype.SubFunc = function() {
}
Why it doesn't seem to work anymore ? During execution I get this error :
view.SubFunc is not a function
JS files are imported one by one but asynchronously and there is no guarantee that file1 will be loaded before file2.
You can wrap file2 (SubFunc.js) into a document.onload event so that it will be executed when other files are loaded.
document.onload = function(){
View.prototype.SubFunc = function() {
}
}
Related
I would like to use WebAssembly within a web worker.
From my main application, I launch it like this:
let w = new Worker('test.js');
w.onmessage = (event) => { console.log(event); };
w.onerror = (event) => { console.error(event); };
w.postMessage({ message: "Hello World" });
Then, I created a file test.js as follows:
self.Module = {
locateFile: function (s) {
console.log(s);
return s;
}
};
self.importScripts("main.js");
// note: `main.js` is the JavaScript glue file created by emcc
self.onmessage = function(messageEvent) {
console.log(messageEvent); // works!
console.log(self.Module); // works!
console.log(self.Module.ccall("test")); // crashes!
}
I get an error: Uncaught TypeError: Cannot read property 'apply' of undefined. I don't understand why self.Module is undefined, how is that possible?
I have the feeling there is something about the scope of the web worker and WebAssembly that does not work well together.
Thanks for your input!
The problem is that console.log() does not reveal the true state of the object at execution time. Further digging revealed that in fact the object Module was not ready yet.
I cite from: https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html
How can I tell when the page is fully loaded and it is safe to call compiled functions?
Calling a compiled function before a page has fully loaded can result
in an error, if the function relies on files that may not be present
[...]
Another option is to define an
onRuntimeInitialized function:
Module['onRuntimeInitialized'] = function() { ... };
That method will be called when the runtime is ready and it is ok for you to call compiled code.
Adjusting my test.js (worker) file fixes the issue:
self.Module = {
locateFile: function (s) {
console.log(s);
return s;
}
// Add this function
onRuntimeInitialized: function() {
test();
}
};
self.importScripts("main.js");
// note: `main.js` is the JavaScript glue file created by emcc
self.data = {};
// to pass data from the main JS file
self.onmessage = function(messageEvent) {
console.log(messageEvent); // works!
self.data = messageEvent; // save the data
}
// gets executed when everything is ready.
self.test = function() {
// we may safely use self.data and self.Module now!
console.log(self.Module.ccall("test")); // works!
}
I'm working on a Flask app where some data gets passed to a template, and I want to make that data available to multiple instances of an object. Here's what it would look like if I just hardcoded the desired data into my .js file:
var Module = function(selector) {
var targetDiv = selector,
targetData = 'lorem ipsum sit dolor',
show = function() {
$('<p>' + targetData + '</p>').appendTo(targetDiv);
};
return {
show: show,
};
};
$(document).ready(function() {
firstModule = new Module($('#first'));
secondModule = new Module($('#second'));
firstModule.show();
secondModule.show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='first'></div>
<div id='second'></div>
I can't just call a function on an unconstructed Module object, so my next step is to create a static-like ModuleFactory that I can load with data from jinja, and then create Modules from there:
var ModuleFactory = function() {
var targetData = null,
setData = function(data) {
targetData = data;
},
create = function(selector) {
return new Module(selector, data);
};
return {
setData: setData,
create: create,
};
} ();
Then I attempt to call ModuleFactory.setData({{data}}); from a <script> tag in the HTML, and do something like ModuleFactory.create($('#first')).show(); in the .js
But of course because I have to include my .js file before using the ModuleFactory in the HTML, I end up constructing the objects before the factory is initialized.
(Past this point, my workaround attempts stop being relevant to the problem.)
Anyway, what's the correct way of getting data from Jinja to my JS module? There has to be a common pattern or something.
This feels awful, but it works:
Have an object with a runProgram method, which takes the desired data as a parameter, then executes the logic that had previously been inside the document ready function. e.g.
var ProgramRunner = function() {
var runProgram = function(data) {
ModuleFactory.setData(data);
firstModule = ModuleFactory.create($('#first'));
firstModule.show();
};
return {
runProgram: runProgram;
};
};
Then just
<script>
$(document).ready(function() { ProgramRunner.runProgram({{data}}) });
</script>
in the HTML.
(Leaving question open, because I suspect there's a much better way of handling this.)
I'm writing a Protractor test and in my test.step.js file I have
element(by.css('...')).getText().then(function (text) {
expect(text).to.equal('expectedText');
});
This works as expected and passes.
Instead I created a test.page.js file and in there put this.field = element(by.css('...')); and then in my step file had
"use strict"
module.exports = function exampleTest() {
var TestPage = require("...");
var testPage = new TestPage;
...
test.Then(..., function (next) {
testPage.field.getText().then(function (text) {
expect(text).to.equal('expectedText');
});
});
}
then field is undefined. I have also tried adding getText() in the page file, but again get undefined or get told that I can't call 'then' on undefined.
In my mind, this should do exactly the same thing as the first example, but I'm far from an expert with Angular or JavaScript.
test.page.js looks like:
"use strict";
module.exports = (function () {
function TestPage() {
this.field = element(by.css('...'));
}
return TestPage;
});
Hoping someone can shine some light on why this is happening and what I should do instead to be able to put the CSS selector inside a page file for re-use.
Thanks
Your code new TestPage; returns the constructor TestPage, but it's never called.
You could return the class :
function TestPage() {
this.field = element(by.css('...'));
}
module.exports = TestPage;
var TestPage = require("...");
var testPage = new TestPage;
testPage.field.getText().then(...
Or an instance of the class:
function TestPage() {
this.field = element(by.css('...'));
}
module.exports = new TestPage();
var testPage = require("...");
testPage.field.getText().then(...
The way you defined re-usable element locators looks different. I am following some thing like below
Step 1: Define a .js file which should contain the Locator objects and re-usable methods
var Login = {
PageElements: {
emailInput: element(by.css('#email')),
passwordInput: element(by.css('#password')),
loginForm: element(by.css('#form')),
},
doLogin: function doLogin() {
this.PageElements.emailInput.sendKeys('blahblah#email.com');
this.PageElements.passwordInput.sendKeys('blahblah');
this.PageElements.loginForm.submit();
},
};
module.exports = Login;
Step 2: Call these page objects in your test classes.
var LoginPage = require('../pageobjects/LoginPage.js');
it('Scenario1_Login',function(){
LoginPage.PageElements.emailInput.sendKeys('blahblah');
});
More details here
I'm using the single-page app template from https://github.com/volojs/create-template
I tried to make a simple example below.
Problem
ModuleA.js is being loaded twice, once directly from main.js and again from simulator.js which depends also on that module. This is causing two different references to an object (which I thought would only be one, like a singleton). I thought requirejs would not load the same module twice. Being (relatively) new to JavaScript I realize this may be naivete on my part. I'm trying to follow the template.
Here's a simplified version that demonstrates the problem:
www/index.html
<head>
...
<script data-main="app" src="lib/require.js"></script>
</head>
...
www/app.js
// For any third party dependencies, like jQuery, place them in the lib folder.
// Configure loading modules from the lib directory,
// except for 'app' ones, which are in a sibling
// directory.
requirejs.config({
baseUrl: 'lib',
paths: {
app: '../app'
}
});
// Start loading the main app file. Put all of
// your application logic in there.
requirejs(['app/main']);
www/app/main.js
define(function (require) {
var simulator = require('./simulator.js');
var ModuleA = require('./ModuleA.js');
ModuleA.init();
ModuleA.displayList();
ModuleA.update("joe", 99);
ModuleA.displayList();
simulator.start(); // should display the same list
});
www/app/ModuleA.js
define(function () {
var theList = {};
console.log("loading ModuleA");
return {
displayList: function () {
console.log(Object.keys(theList));
},
init : function () {
theList["fred"] = 10;
},
update : function (k, v) {
theList[k] = v;
}
}
});
www/app/simulator.js
define(["./ModuleA"], function (ModuleA) {
return {
start: function () {
ModuleA.displayList();
}
};
});
console output:
loading ModuleA
loading ModuleA
["fred"]
["fred", "joe"]
[]
The empty [] displayed on the last line is (likely) the second copy of the list due to the second loading of ModuleA.
The problem is the module references are not consistent. In main.js it requires ./ModuleA.js whereas in simulator.js it defines ./ModuleA (without the .js filetype).
Making those references identical corrects the behavior such that the module is only loaded once.
I guess I mixed the styles because of the many examples on the web. It kind of seems like a bug that it works this way, but maybe it's a feature?
If you want to share an instantiated singleton object using requireJS, you can do something like this for ModuleA:
define(function () {
console.log("loading ModuleA");
function myList(){
this.theList = {}
}
myList.prototype.displayList = function () {
console.log(Object.keys(this.theList));
}
myList.prototype.init = function () {
this.theList["fred"] = 10;
}
myList.prototype.update = function (k, v) {
this.theList[k] = v;
}
return new myList();
});
I have an object and lets call this object game.Door.
Inside this object I have a method.
openDoor: function() {
game.removeRoom1();
game.viewRoom3();
},
removeRoom1() is in this js file.
viewRoom3() is in another js file.
My HTML:
<script src="js/viewRoom3jsfile.js"> </script>
<script src="js/filewithObject.js"></script>
viewRoom3() is not working unless I put it in the same js file as my object.
Is there any way to have viewRoom3() in another js file?
Further clarification:
filewithObject.js:
var game = game || {};
game.Door = {
openDoor: function() {
game.removeRoom1();
game.viewRoom3();
},
};
game.removeRoom1 = function(){
}
viewRoom3jsfile.js:
game.viewRoom3 = function(){
}
Currently, my viewRoom3() is in the same file as my object and my javascript works.
However, if I move viewRoom3() into a seperate js file, the function stops working.
As i understand it you have something like this:
var Game= {
removeRoom1: function() { return something; },
viewRoom3: function() { return something; }
}
So the function is inside the object. If you want the function to be in another js file other than the object, i suggest you do something like this:
var Game= {
....//object code here
}
//the following can go to another js file
function removeRoom1(obj) { return obj.something; }
function viewRoom3(obj) { return obj.something; }