Stack Overflow! I wanted to store variables in another file so that I would load the variables in file 1, and draw the scene in file 2, ex.
closet.js
var message = "Hello there";
drawer.js
draw = function() { text(message, 100, 100); };
So I would do something like that, but instead of importing the files like this;
<canvas data-processing-sources="closet.js drawer.js"></canvas>
I wanted to be able to include them in file 2, sort of like this;
closet.js
var message = "Hello there";
drawer.js
import("closet.js");
draw = function() {
text(message, 100, 100);
};
Is there a way to do this without including them in the HTML file itself?
Thanks in advance :)
Check out this question, which yours might even be a duplicate of. It lists several ways to do this in JavaScript, including using JQuery or dynamically adding the <script> tags to the <head> of your page.
But if you're using the Processing editor, you have another option: use classes by creating a new tab in the Processing editor. For all your purposes, you can treat this as a separate file. So lets say you created a separate Closet tab with a message variable. Your main sketch code might look like this:
Closet c = new Closet();
draw = function() {
text(c.message, 100, 100);
};
I think this is probably the way to go. It seems like you're trying to over-engineer a solution: either include the files in the html (this is what 99% of all JavaScript code does) or use a class (this is what 99% of all Processing code does).
Related
I want to tidy up the js-code used on my php-website to increase the loading speed. For the moment i include in every website the required js-file.
My plan is to merge all js-files into one big one. Not every page uses every js-code, so i started something but don't know if this makes any sense.
I have already read the article One JS File for Multiple Pages but the method of Paul Irish is way to complicated for me (for the moment) as a beginner.
This is my approach:
I create the file core.js and call it on every website like..
<script src="js/core.js"></script>
In core.js i first get the name of the corresponding page.
var path = window.location.pathname;
var page = path.split("/").pop();
var page_name = page.slice(0, -4);
Then i check which site requires which js-script (pseudo-code).
if (page_name == 'xyz'){
execute this code which is only used on this site
}
if (page_name == 'abc' || 'xyz' || 'def'){
execute another code which is used on multiple sites
}
if (page_name == 'ghi' || 'jkl' || 'mno' || 'xyz'){
include jquery for multiple sites
}
...
...
This means a lot of work for me, because i have a lot of js, so i wanted to ask first if this is a good solution to tidy up.
By the way: The js code i place on my website doesn't change often.
Thank you
Misch
A solution for your problem could be something like:
if(selector) {
//run code
}
This runs the code inside the block only if a particular selector exists. This way you don't have to go through all the trouble of getting the name of the page, splitting and slicing the string etc (this is also prone to errors).
So let's say you want to add some innerHTML on some node it will look something like this:
function bar (text) {
alert(text)
}
if(document.getElementById('#foo')) {
bar('#foo exists!')
}
This way bar is only called when a node with id #foo exists.
Split your javascript into sensible groups. You may have an admin section to your site, so have admin.js.
It's also worth noting that most browsers will only download the javascript file once and then cache it. You said that your code does not change very often so you may find that putting it all in one file doesn't actually have that much of an affect.
Lets say you have pages like page1, page2, page3 etc.
Then your core.js will include all the codes of all the pages and then just initialize the code which you want to use
var page1= (function () {
var Init = function (){
//write the codes used by page 1
};
return {
Initialize: function () {
Init();
}
};
})();
var page2= (function () {
var Init = function (){
//write the codes used by page 2
};
return {
Initialize: function () {
Init();
}
};
})();
var page3= (function () {......});
var page = path.split("/").pop();
var path = window.location.pathname;
var page = path.split("/").pop();
var page_name = page.slice(0, -4);
if (page_name == 'pg1'){
page1.Initialize();
}
if (page_name == 'pg2' || 'pg3'){
page2.Initialize();
page3.Initialize();
}
if (page_name == 'pg4' ){
page4.Initialize();
}
To be honest, this is just going to slow down your performance. If your users stay a long time on the website, then one single file reduces a bit of clutter in your code. But, if the user is visiting only a few pages, single file is just extra burden on bandwidth. There is a possibility, most of your users might not even need more than half of your js.
Plus, those extra conditions aren't really helping anyone. So, I would say, don't use single file option.
I have a complex jQuery plugin to write, It does have a lot of html to show on screen and I am supposed to create them. Well, what is the best way to do the job. I can already hard code them for sure , but is there any other elegant method? is there a way to use some kind of templating?. definitely I don't want to have lot more dependency either.
You can put them in an external file(s) and load them when you need but this means plugin users will have to download all your files, instead of a single js file. Another option I used before (not for a plugin though) is to have an object inside your plugin which holds all the html you want. This makes it easier to write the plugin as the html doesn't clutter the plugin code. Also when you need to edit the html, it's in a single place. You can also put your templating code inside this object.
var pi = function() {
var self = this;
self.getNewDiv = function(){
return repo.getDiv();
}
//..... all your plug in code goes here and at the bottom
var htmlRepository = function() {
var divCode = "<div></div>";
this.getDiv = function(){
return divCode;
};
this.getSpan = function(){
return "Span Content";
}
this.getDivWithSpan = function(){
return getSpan().wrap(divCode); //etc
}
};
var repo = new htmlRepository();
}
I have file called common.js and it's included in each page of my site using <script />.
It will grow fast as my sites functionality will grow (I hope; I imagine). :)
Lets example I have a jQuery event:
$('#that').click(function() {
one_of_many_functions($(this));
}
For the moment, I have that one_of_many_functions() in common.js.
Is it somehow possible that JavaScript automatically loads file one_of_many_functions.js when such function is called, but it doesn't exist? Like auto-loader. :)
The second option I see is to do something like:
$('#that').click(function() {
include('one_of_many_functions');
one_of_many_functions($(this));
}
That not so automatically, but still - includes wanted file.
Is any of this possible? Thanks in an advice! :)
It is not possible to directly auto-load external javascripts on demand. It is, however, possible to implement a dynamic inclusion mechanism similar to the second route you mentioned.
There are some challenges though. When you "include" a new external script, you aren't going to be able to immediately use the included functionality, you'll have to wait until the script loads. This means that you'll have to fragment your code somewhat, which means that you'll have to make some decisions about what should just be included in the core vs. what can be included on demand.
You'll need to set up a central object that keeps track of which assets are already loaded. Here's a quick mockup of that:
var assets = {
assets: {},
include: function (asset_name, callback) {
if (typeof callback != 'function')
callback = function () { return false; };
if (typeof this.assets[asset_name] != 'undefined' )
return callback();
var html_doc = document.getElementsByTagName('head')[0];
var st = document.createElement('script');
st.setAttribute('language', 'javascript');
st.setAttribute('type', 'text/javascript');
st.setAttribute('src', asset_name);
st.onload = function () { assets._script_loaded(asset_name, callback); };
html_doc.appendChild(st);
},
_script_loaded: function (asset_name, callback) {
this.assets[asset_name] = true;
callback();
}
};
assets.inlude('myfile.js', function () {
/* do stuff that depends on myfile.js */
});
Sure it's possible -- but this can become painful to manage. In order to implement something like this, you're going to have to maintain an index of functions and their corresponding source file. As your project grows, this can be troublesome for a few reasons -- the 2 that stick out in my mind are:
A) You have the added responsibility of maintaining your index object/lookup mechanism so that your scripts know where to look when the function you're calling cannot be found.
B) This is one more thing that can go wrong when debugging your growing project.
I'm sure that someone else will mention this by the time I'm finished writing this, but your time would probably be better spent figuring out how to combine all of your code into a single .js file. The benefits to doing so are well-documented.
I have created something close to that a year ago. In fact, I have found this thread by search if that is something new on the field. You can see what I have created here: https://github.com/thiagomata/CanvasBox/blob/master/src/main/New.js
My project are, almost 100% OOP. So, I used this fact to focus my solution. I create this "Class" with the name "New" what is used to, first load and after instance the objects.
Here a example of someone using it:
var objSquare = New.Square(); // Square is loaded and after that instance is created
objSquare.x = objBox.width / 2;
objSquare.y = objBox.height / 2;
var objSomeExample = New.Stuff("some parameters can be sent too");
In this version I am not using some json with all js file position. The mapping is hardcore as you can see here:
New.prototype.arrMap = {
CanvasBox: "" + window.MAIN_PATH + "CanvasBox",
CanvasBoxBehavior: "" + window.MAIN_PATH + "CanvasBoxBehavior",
CanvasBoxButton: "" + window.MAIN_PATH + "CanvasBoxButton",
// (...)
};
But make this more automatic, using gulp or grunt is something what I am thinking to do, and it is not that hard.
This solution was created to be used into the project. So, the code may need some changes to be able to be used into any project. But may be a start.
Hope this helps.
As I said before, this still is a working progress. But I have created a more independent module what use gulp to keep it updated.
All the magic que be found in this links:
https://github.com/thiagomata/CanvasBox/blob/master/src/coffee/main/Instance.coffee
https://github.com/thiagomata/CanvasBox/blob/master/src/node/scripts.js
https://github.com/thiagomata/CanvasBox/blob/master/gulpfile.js
A special look should be in this lines of the Instance.coffee
###
# Create an instance of the object passing the argument
###
instaceObject = (->
ClassElement = (args) ->
window[args["0"]].apply this, args["1"]
->
ClassElement:: = (window[arguments["0"]])::
objElement = new ClassElement(arguments)
return objElement
)()
This lines allows me to initialize a instance of some object after load its file. As is used in the create method:
create:()->
#load()
return instaceObject(#packageName, arguments)
I have created a sizable application javascript and jQuery. However my file structure is getting a bit messy!
At the moment I have one large JS file with a if ($('#myDiv').length > 0) { test at the top to only execute the code on the correct page, is this good practice?
There is also a mixture of plain JS functions and jQuery extensions in the same file e.g $.fn.myFunction = function(e) {.
I also have a few bits of code that look like this:
function Product() {
this.sku = '';
this.name = '';
this.price = '';
}
var myProduct = new Product;
Basket = new Object;
My question is for pointers on good practice regarding javascript and jQuery projects.
The code if ($('#myDiv').length > 0) { is not good practice. Instead, make your page specific JS as functions and execute them in the corresponding page . Like this:
var T01 = function(){
// JS specific to Template 01
};
var T02 = function(){
// JS specific to Template 02
};
HTML head of Template 01:
<script type="text/javascript"> $(T01); </script>
Consistency is the golden rule.
You can discuss design patterns back and forth, but if you want to have easily maintainable code where new people can come in and get an overview fairly quickly, the most important part, whatever design patterns you chose, is to have a consistent code base.
It is also the hardest thing to do - keeping your codebase clean and consistent is probably the hardest thing you can do as a programmer, and especially as a team.
Of course the first tip I can give you is to separate the jQuery extensions in their own source files. You can always serve everything together with a minification tool, so you should not worry about performance.
About the code youo mention, it could be simplified to
var Product = {
sku: '',
name: '',
price: ''
}
var myProduct = objectCopy(Product);
var Basket = {};
provided you write a simple objectCopy function which loops through the object own properties and just copies them to a new object (you can make a shallow or a deep copy, according to your needs).
Finally, if you think your code is starting to get messy, you may want to learn some patterns to organize JS code, like the module pattern. Alternatively, if you are familiar with doing this on the backend, you may want to organize your application following the MVC pattern. personal advertisement - I have written myself a tiny library which helps organize your code in this fashion. There are also many other libraries for the same task, often adding other functionality as well.
If you follow the MVC pattern, your page will actually correspond to some action in some controller, and you could just start it with a call like
<script>someController.someAction()</script>
in the head of your document, hence removing the need for the manual check for #myDiv. If you use my library MCV, it will be enough to declare your body like
<body class="mcv:controller/action">
and start the application with
$(document).ready(function() {
mcv.autostart();
});
Yes it's good practice to put as much of your code into a seperate JS file as this could then be compressed before transmission and hence speed up download time. However no you should not have code that looks like
if ($('#myDiv').length > 0) {
on every page. Split your JS code up into manageable functions and call those as-and-when you need to.
I don't see a problem with mixing JS and jQuery functions up in the same file.
I currently have one large external javascript file that is used on the page. I currently wrap the code in a self-invoking function because I have other sections that are loaded using ajax tabs, so I want to avoid naming clashes with those other external js files.
The code in the file is organized like below. I would like to split some of the code inside the plannerTab namespace into smaller files, yet still have it be part of that namespace.
How could I do this? Or, do you guys recommend a different approach? Thanks!
// Document Ready
$(function ()
{
// initializes table
plannerTab.plannerTable.init();
});
var plannerTab = (function ()
{
// All the code for the page is in here. I would like to extract sections
// from in here and put them into their own external files while still keeping
// the namespacing
}();
Update
How could I separate parts from within the plannerTab variable into smaller external js files, and still maintain that they are part of the plannerTab namespace? A small example below.
// Scope: plannerTab.config - Would like to store configuartion into a separate file
var config = {
selectors: {
tableId: '#plannerTable',
addTaskId: '#AddTask',
editTaskSelector: '#plannerTable .edit',
dateFilterSelector: '#plannerTable_TimeFilter li',
deleteTaskClass: '.delete',
searchFilter: '#plannerTable_filter',
selectedDateFilter: 'selected-dateFilter',
taskCellSelector: '#plannerTable .task-col',
taskClass: '.taskId'
},
urls: {
addTaskFormURL: '/Planner/Planner/LoadAddTaskForm',
editTaskFormURL: '/Planner/Planner/LoadEditTaskForm',
deleteTaskURL: '/Planner/Planner/DeleteTask',
getTasksByDateRangeURL: '/Planner/Planner/GetTasksByDateRange',
viewTaskURL: '/Planner/Planner/ViewTask'
}
};
Look at this example (from google)
<script type="text/javascript">
function importScript(url){
var tag = document.createElement("script");
tag.type="text/javascript";
tag.src = url;
document.body.appendChild(tag);
}
window.onload = function(){
// imports go here
importScript("foo.js"); // example
};
</script>
I'm assuming that plannerTab becomes an object return result of the self executing function. If you need to add properties or methods to that object dynamically, you can take a look at jQuery.extend() http://api.jquery.com/jQuery.extend/
You would need to modify the external JS to use the jQuery extend method to add onto existing properties and methods of plannerTab. As long as you keep plannerTab a global variable, you will continue adding to it as you import more external js files.
If you are using the module pattern to maintain private variables in plannerTab, be sure to test how those values behave once you use jQuery.extend().