Play Framework - Defining my Javascript file within a function - javascript

I'm using the Play Framework and am trying to define a javascript file within a function in another javascript file (the reason being that I don't want these functions to be usable outside of the container function).
So I have two javascripts files, ./public/javascripts/main.js, ./public/javascript/custom.js.
From my html pages (index.scala.html) I define this as follows:
<script src="#routes.Assets.at("javascripts/main.js")"></script>
Using "#routes...." doesn't work in main.js, so I tried adding the following:
$.getScript("public/javascripts/custom.js", function(){
alert("Script loaded and executed.");
});
I've tried a variety of paths but it always says it can't find it.
Any idea how to do this in Play please? Looked through as much documentation as I can and nothing is there...
Any help would be brilliant!
Thank you.
Kind Regards,
Gary Shergill

Make sure you have the following declaration in your routes file:
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
Then the following should work:
$.getScript("/assets/javascripts/custom.js", function(){
alert("Script loaded and executed.");
});

Try to use Javascript Routing mechanism. As described here
Define javascriptRoutes
import play.api.mvc._
object Application extends Controller {
def javascriptRoutes = Action { implicit request =>
import routes.javascript._
Ok(
Routes.javascriptRouter("jsRoutes")(
javascript.Assets.at
)
).as("text/javascript")
}
}
Update your .routes file
GET /routes controllers.Application.javascriptRoutes
Include it into the page:
<script type="text/javascript" src="#routes.Application.javascriptRoutes"></script>
And then use jsRoutes variable in your javascript:
$.getScript(jsRoutes.controllers.Assets.at('javascripts/custom.js').url, function(){
alert("Script loaded and executed.");
});

Related

How to configure a start up javascript-only project with multiple files in VSCode

I'm doing a javascript course with FCC and use VSCode as my code editor. But to date, all my js code was contained in a single file. Obviously for any meaningful js development I need to create a collection of js files that work as a single unit.
To start exploring this I have a very simple setup of two js files, test-01.js and test-02.js, where test-01.js contains a call to a function which is defined in test-02.js. I first want to do this without any HTML or CSS files. Although that will also be a future requirement.
The first file test-01.js:
//test-01.js
let returnStr = "";
console.log("This is the calling program");
// Now call the function in test-02.js
returnStr = Display(10);
With future project complexity in mind, the second file test-02.js is in a sub-folder from the first file. .\folder-02\test-02.js:
//test-02.js
function Display(param = 0) {
console.log("This is the program called with parameter: ", param);
return "Back from Display";
};
I've unsuccessfully tried importing the function Display() from test-01.js into test-02.js.
I've unsuccessfully tried finding ways to modify files like:
package.json
jsconfig.json
setting.json
launch.json
I've unsuccessfully tried looking for sample projects on github and elsewhere.
I've unsuccessfully looked for answers in StackOverflow.
All to no avail. This should be a no brainer which should have been described in the vscode documentation but I cannot find it there. By now I have tried so many things that I've probably screwed up my development environment. I hope someone can help me out and point me in the right direction to resolve this.
Many thanks, Thomas.
JavaScript modules are the way to go when importing methods from one .js file and calling them in another .js file. There are many different ways to import and use modules in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
Here is an example for your situation:
First, lets import the main JavaScript file into the html document:
<head>
<!-- type="module" is necessary -->
<script type='module' src="test-01.js" defer></script>
</head>
Next, lets define the 'Display' function in folder-02/test-02.js:
function Display(param = 0) {
console.log("This is the program called with parameter: ", param);
return "Back from Display";
};
export default Display //exporting it to be imported into another js file
Lastly, lets set up test-01.js to import and call the previously defined function:
import Display from './folder-02/test-02.js';
let returnStr = "";
console.log("This is the calling program");
// Now call the function in test-02.js
returnStr = Display(10);

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'

Accessing a function from another javascript file

I have 2 Javascript files, a main.js which loads first and then a secondary.js which loads afterwards. What I am trying to do is create a global function in main.js which can be utilized on the pages where secondary.js is loaded.
Here's what I have in main.js:
var doSomething;
doSomething = function() {
//things to do
}
And then in my secondary.js:
var result = doSomething();
However, this is returning doSomething is not defined. I searched SO and found similar questions but was not able to find a solution that worked for me.
You are getting doSomething is not defined because doSomething is being created after secondary.js has been loaded, so it's not available and you are getting a reference error.
You need to control the order in which your code is getting executed.
How you accomplish this depends on how you are loading your JavaScript files. For example, let's say you are using script tags in your html file. You can have main.js load after secondary.js like this:
<script src="main.js"></script>
<script src="secondary.js"></script>

Using jQuery and RequireJS at start of processing

I often start my JavaScript apps like this:
jQuery(function($) {
... code for the app ...
});
I'm just starting to use RequireJS, and will start the app like this:
define(['jquery'], function($) {
... code for the app ...
});
Now, as I don't want the app to start processing until all the HTML has been loaded, I've combined the two like this:
require(['jquery'], function($) {
$(function($) {
... code for the app ...
});
});
Is that the way to do it?
The RequireJS documentation touches on this and offers has a slightly more convenient option:
require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});
Note that you will need to download the domReady plugin, and if you have a very complex page you may wish to use the "explicit function call" method that they also show... Although then it looks an awful lot like what you're already doing with jQuery.
So the main diferences between define and require in this scenario is, one declare a module and the second one call this defined module, then if it is not loaded, the browser download the js library.
To take control about when your require files will download, you need to use the domReady plugin.
You need to put the js library at you require.config, I usually put at the same directory as declared at the baseUrl property, for example:
require.config({
baseUrl: "js/lib",
paths:{
filter:"../src/filter",
addPanel: "../src/edit-panel"
}
}
I put the domReady.js at the js/lib/ folder.
So, then you can use the require method at any place of you html file:
require(['jquery!'], function ($) {
});
Note that I use the symbol ! to indicate that this library is load after the completely page load.
As the box at the top of the page, my question is answered here:
Requirejs domReady plugin vs Jquery $(document).ready()?
The other answers here essential repeat what's in the above link. But, thanks!

Calling methods in RequireJs modules from HTML elements such as onclick handlers

I'm changing a project from an "old" browser-style module structure to a "new" browser-or-server-side-javascript module structure with require.js.
On the client I'm using an offsite hosted jQuery, so I started from the example they give in the "use priority config" technique of the README:
<title>My Page</title>
<script src="scripts/require.js"></script>
<script>
require({
baseUrl: 'scripts',
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min',
jqueryui: ...,
...
... // bunch more paths here
},
priority: ['jquery']
}, [ 'main' ]);
</script>
This is actually working all right. But I'd like to export functionality from main to the HTML webpage itself. For instance:
<a class="button" href="#" onclick="MyApi.foo();">
<img src="foo.png" alt="foo" />Click for: <b>Foo!</b>
</a>
Before fitting into the AMD module pattern, I'd exposed functionality from my various files by creating a dictionary object in the global space:
// main.js
var MyApi = {};
jQuery(document).ready(function($) {
// ...unexported code goes here...
// export function via MyApi
MyApi.foo = function() {
alert("Foo!");
};
});
But I don't know what the right approach in require.js is. Is it okay to put in the HTML more require statements inside of <script> tags, and then name modules so that it can be used from within the webpage? Or should this always be done dynamically inside of main.js, like $('#foobutton').click(...)?
One benefit from using AMD is to drop the need for namespaces. Trying to create them again with RequireJS will go against the patterns AMD promotes.
With regard to using main.js, this is only really appropriate when you have a single page app and all your code be reference from one place. You're free to make additional calls to require and load other modules as you need them.
Using your example from above, you could approach it this way:
foo.js
define(['jquery'], function($) {
// Some set up
// code here
// Return module with methods
return {
bar: function() {
}
}
});
page.js
require(['foo'], function(foo) {
// jQuery loaded by foo module so free to use it
$('.button').on('click', function(e) {
foo.bar();
e.preventDefault();
});
});
Then in your page request the page.js file with require.
Using your example above:
require({
// config stuff here
}, [ 'page' ]);
Or loading it in the page further down:
<script>
require(['page']);
</script>
Some additional points
Using the pattern above, page.js could easily require many other
modules to load other page related functionality.
Where before you would attach members to your global namespace, you
now split that code into separate modules that can be re-used on
any page. All without reliance on a global object.
Using require this way to attach events to your DOM elements will
most likely rely on the DOM Ready module provided by RequireJS
You can also set the reference on javascript's window class.
At the bottom of the application module window.MyApi = MyApi;
<a class="button" href="#" onclick="MyApi.foo();"></a>
putting onclick="" inside your markup feels dirty -- mixing presentation with content. I'd recommend you add a <script> block and put the require in it, and once inside the callback, and inside another inner $(document).ready() if necessary then wire up your event handlers in the normal way: $('#node').click(...). If you can do this generically enough that it's applicable to multiple pages, then put it inside an external file that is minified, combined, and cached. But typically these things end up being page-specific, so a <script> tag at the bottom of the page is a good solution to avoid yet another external resource request.
Another solution is just use code like that (of course requirejs must be added to the page):
<input type="button" onclick="(function() { require('mymodule').do_work() })()"/>

Categories

Resources