Can Express.js render different routes on same 'res' object? - node.js

Can I have the following config in route/index.js ?
exports.PageA = function(req, res) {
...
...
if(req.method == 'GET') {
if (condition1) {
//PageA has 2 .js files
res.render('PageA', { title: 'A', layout: false});
}
else {
//PageB has 2 + 2 .js files
res.render('PageB', { title: 'B', layout: false});
}
}
else {
res.render('PageC', { title: 'B', layout:'some_other_layout' });
}
};
Case: mywebsite.com/PageA renders correctly when condition1 passes (with all scripts loaded and executed correctly)
Issue : But when condition1 fails, I get PageB rendered, javascripts in PageB.ejs are rendered but not executed, say, on $document.Ready().
Strangely if I 'Refresh' the already rendered PageB in browser, javascripts are then executed correctly.
As a piece of info: I use defer="defer" tag in all "< script >..."
What am I missing here?

Your problem is entirely on the client side. Attribute "defer" supported only in Internet Explorer and Firefox at this moment. I think your problem is that the scripts are loaded in the wrong sequence. Check your browser console for errors. When you re-load a page, the scripts are loaded from the browser cache. It's faster. Therefore, the error may not appear in this situation.

Related

Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.7.9/$injector/moduler

Am getting the above error in console on loading my application. My controller looks as below.Am new to angular so any help would be appreciated
Am trying to export the datatable into excel here. I think the issue is here angular.module('myApp','datatables', 'datatables.buttons'])
What is the correct way to include them in the module?
ViewCtrl.js
angular.module('myApp',['datatables', 'datatables.buttons'])
.controller('ViewCtrl', function($scope, DTOptionsBuilder, DTColumnDefBuilder) {
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withPaginationType('full_numbers')
.withDisplayLength(2)
.withDOM('pitrfl')
.withButtons([{
extend: 'excelHtml5',
}
]);
vm.dtColumnDefs = [
DTColumnDefBuilder.newColumnDef(0),
DTColumnDefBuilder.newColumnDef(1).notVisible(),
DTColumnDefBuilder.newColumnDef(2).notSortable()
];
});
Verify the console loads. If the console.log does not show and you still get the inject error, then your problem is likely the datatables and datatables.buttons. Verify that these files are added to your index.html file prior to this file.
angular.module('myApp', ['datatables', 'datatables.buttons'])
.controller('ViewCtrl', function ($scope) {
console.log("Code of awesomeness");
});
If you find that you do see the console.log("Code of awesomeness"); Then your $inject issue is DTOptionsBuilder, DTColumnDefBuilder. Verify spelling.

Nested define doesn't load dependency on localhost

I have the following simple structure:
index.html
...
<script src="static/js/lib/require.js" data-main="static/js/main"></script>
</head>
...
static/js/main.js
requirejs.config({
baseUrl: 'static/js',
paths: {
m: 'modules'
}
});
require(['m/test01'], function(test01) {
console.log(test01.print());
});
static/js/modules/test01.js
define(['m/test02'], function(test02){
return {
print: function() {
return 'test01 and '+ test02;
}
};
});
static/js/modules/test02.js
define(function() {
return 'test02';
});
Now when I open index.html directly (file:///index.html) all goes well. The script loading works and "test01 and test02" is logged in the console.
However, if I'm opening via xampp (localhost/requiretest/index.html) the loading of test01.js goes well, but for test02.js I get this error in the console (Firefox):
NetworkError: 404 Not Found - localhost/01-test-grunt/static/js/test02.js
(removed "http://" before localhost for stackoverflow)
As you can see the 'modules/' part is missing in the URL.
Anyone got any idea what might be going on?
NOTE: It does work when I change baseUrl to 'static/js/modules', but I can't do this because of my grunt buildprocess. Anyway, I assume other paths won't be loaded either, so is this a bug or am I doing something wrong?

Loading jwplayer in Durandal

I want to use jwplayer on a Single Page App built using Durandal framework. The idea is to create a persistent audio player, unaffected by the application's navigation. But I haven't been able to load jwplayer in Durandal.
I've successfully loaded jwplayer on a simple html file using Require.js. But this method doesn't seem to work on Durandal (which also uses Require.js).
This is my code on shell.js:
define(['jwplayer/jwplayer','durandal/plugins/router','durandal/app'], function (jwplayer,router,app) {
jwplayer.api('player').setup({
width: '320',
height: '40',
sources: [{
file: "rtmp://127.0.0.1:1935/vod/mp3:sample_1.mp3"
},{
file: "http://127.0.0.1:1935/vod/sample_1.mp3/playlist.m3u8"
}]
});
return {
router: router,
activate: function () {
...
}
};
});
And inside the shell.html I have this code: <div id="player">loading player...</div>
This is the error message I get:
Uncaught TypeError: Cannot read property 'id' of null jwplayer.js:37
It seems that the player element is unrecognizable inside a Durandal module. What caused this problem? How do I add a jwplayer inside a Durandal module?
As you already figured out, it looks like the player element isn't recognized when the code is executing. When the module is loading for the first time, the DOM definitely isn't ready. It may not even be ready during the activate() callback function. The right time to setup the jwplayer is probably in the viewAttached() callback.
You can read more about the viewAttached callback here in the Composition Callbacks section: http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks/
Something like this:
define(['jwplayer/jwplayer','durandal/plugins/router','durandal/app'], function (jwplayer,router,app) {
return {
router: router,
activate: function () {
...
},
viewAttached: function(){
jwplayer.api('player').setup({
width: '320',
height: '40',
sources: [{
file: "rtmp://127.0.0.1:1935/vod/mp3:sample_1.mp3"
},{
file: "http://127.0.0.1:1935/vod/sample_1.mp3/playlist.m3u8"
}]
});
}
};
});

RequireJS does not run data-main script before loading required modules

My project includes the following files:
./index.html
./js/main.js
./js/vendor/require.js
./js/viewmodel/vm.js
The index.html has the following relevant snippet:
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
</script>
The js/main.js file is as follows:
var root = this;
define('jquery', ['http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.js'], function () { return root.$; });
define('ko', ['http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js'], function (ko) { return ko; });
The js/viewmodel/vm.js file...
define(['jquery', 'ko'],
function($, ko) {
return {
subject: 'world',
greeting: 'hello'
}
}
);
When you open a browser to index.html, then the browser tries to load a file called js/ko.js instead of using the module defined in main.js. It seems like the js file pointed to by the data-main attribute is not guaranteed to run before dependency resolution. This does not seem correct to me since one purpose of the data-main js file is to define require configuration (i.e. path, shim, etc). I am using require v2.1.2.
This works perfectly fine if I copy the contents of my main.js file into the script block in index.html. By "perfectly fine" I mean that it resolved ko to be a module and finds the appropriate CDN link to resolve ko instead of trying to download ./js/ko.js.
to use the data-main attribute for configuring your whole application, it is necessary that it is the single entry point for all your code.
your 2nd script block breaks this requirement by providing a 2nd entry point. since these entry points will resolve independently of each other (and asynchronously), you cannot rely on one to affect the other.
to resolve it, refactor your code in a way that provides a single entry point to your application and do your configuration via this entry point.
That's because requirejs sets the async. Attribute on the script.
The boolean async attribute on script elements allows the external
JavaScript file to run when it's available, without delaying page load
first.
This means that both scripts are loaded and evaluated parallel, so none of the two scripts can access methods or functions from the other one.
If you want to define requirejs variables in one script you mustn't load that script with require js.
For me there are three possibilities how you can solve that problem:
Add the content of main.js to your page (as you mention)
Load the main.js file without requirejs as normal script
Define the require config before loading the scripts (link to requirejs docu )
I had the same problem. The architecture of the site that i was working was components that was loading asynchronous at each part of the page.
Each component has its own html, css, and js code.
So, my solution is to keep a guard function for all the required dependency code, to protect them from running before the main javascript file:
index.html
<head>
<script type="text/javascript">
window.BeforeMainGuard = {
beforeMainLoadedFunctions: [],
hasMainLoaded: false,
guard: function( func ) {
console.assert( typeof func === 'function' );
if( this.hasMainLoaded ) {
func();
}else {
this.beforeMainLoadedFunctions.push( func );
}
},
onMainLoaded: function() {
for( var i = 0; i<this.beforeMainLoadedFunctions.length; ++i ) {
var beforeMainLoadedFunction = this.beforeMainLoadedFunctions[i];
beforeMainLoadedFunction();
}
this.beforeMainLoadedFunctions = null;
this.hasMainLoaded = true;
}
};
</script>
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
window.BeforeMainGuard.guard( function() {
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
});
</script>
</head>
js/main.js
require.config({
// your config
});
require( [ 'AppLogic' ], function( AppLogic ){
AppLogic.Init();
window.BeforeMainGuard.onMainLoaded();
} );

phantomjs and requirejs

codes in file main.js is like this:
phantom.injectJs("libs/require-1.0.7.js");
require.config(
{
baseUrl: ""
}
);
require([], function(){});
when i run "phantomjs main.js" in the commandline, requirejs doesn't work well in the main.js. I know how to use requirejs in the page running in the browser(including phantomjs' way: page.open(url, callback)), but not like above. I tries using requirejs like the main.js, it is a popular problem, i think. Thank you!
I just struggled for some time. My solution is not clean, but it works, and I'm happy with that due to the unfinished api documentation from phantomjs.
Wordy explanation
You need three files. One is your amd phantomjs test file which I'll call "amd.js". The second is your html page to load which I'll name "amd.html". Finally the browser test which I called "amdTestModule.js".
In amd.html, declare your script tag per normal:
<script data-main="amdTestModule.js" src="require.js"></script>
In your phantomjs test file, this is where it gets hacky. Create your page, and load in the 'fs' module. This allows you to open a relative file path.
var page = require('webpage').create();
var fs = require('fs');
page.open('file://' + fs.absolute('tests/amd.html'));
Now since requirejs loads files asynchronously, we can't just pass in a callback into page.open and expect things to go smoothly. We need some way to either
1) Test our module in the browser and communicate the result back to our phantomjs context. Or
2) Tell our phantomjs context that upon loading all the resources, to run a test.
#1 was simpler for my case. I accomplished this via:
page.onConsoleMessage = function(msg) {
msg = msg.split('=');
if (msg[1] === 'success') {
console.log('amd test successful');
} else {
console.log('amd test failed');
}
phantom.exit();
};
**See full code below for my console.log message.
Now phantomjs apparently has an event api built in but it is undocumented. I was also successfully able to get request/response messages from their page.onResourceReceived and page.onResourceRequested - meaning you can debug when all your required modules are loaded. To communicate my test result however, I just used console.log.
Now what happens if the console.log message is never ran? The only way I could think of resolving this was to use setTimeout
setTimeout(function() {
console.log('amd test failed - timeout');
phantom.exit();
}, 500);
That should do it!
Full Code
directory structure
/projectRoot
/tests
- amd.js
- amdTestModule.js
- amd.html
- require.js (which I symlinked)
- <dependencies> (also symlinked)
amd.js
'use strict';
var page = require('webpage').create();
var fs = require('fs');
/*
page.onResourceRequested = function(req) {
console.log('\n');
console.log('REQUEST');
console.log(JSON.stringify(req, null, 4));
console.log('\n');
};
page.onResourceReceived = function(response) {
console.log('\n');
console.log('RESPONSE');
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response, null, 4));
console.log('\n');
};
*/
page.onConsoleMessage = function(msg) {
msg = msg.split('=');
if (msg[1] === 'success') {
console.log('amd test successful');
} else {
console.log('amd test failed');
}
phantom.exit();
};
page.open('file://' + fs.absolute('tests/amd.html'));
setTimeout(function() {
console.log('amd test failed - timeout');
phantom.exit();
}, 500);
amd.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script data-main='amdTestModule.js' src='require.js'></script>
</body>
</html>
amdTestModule.js
require([<dependencies>], function(<dependencies>) {
...
console.log(
(<test>) ? "test=success" : "test=failed"
);
});
console
$ phantomjs tests/amd.js
amd test successful
you are misunderstanding webpage.injectJs()
it's for injecting scripts into the page you are loading, not into the phantomjs runtime environment.
So using .injectJs() is making requirejs load up into your page, not into phantomjs.exe.
That said, phantomjs's runtime environment has an aproximation of commonjs. RequireJs will not run on there by default. If you felt especially (VERY) motivated, you could attempt porting the require-shim made for nodejs, but it doesn't work out of the box, and would require an incredibly deep understanding of the runtimes. for more details: http://requirejs.org/docs/node.html
a better idea:
probably you should make sure you have commonjs versions of your javascript you wish to run. i personally write my code in typescript so i can build for either commonjs or amd. i use commonjs for phantomjs code, and amd for nodejs and browser.

Resources