I have created the PHP side of a modular AJAX/PHP framework and now I am trying to implement the client side.
From my previous experience with modular web applications I know that sometimes multiple instances of one particular module are needed. For example, a web based two player game with page parts for each user.
On PHP side I have assigned a unque ID to each constructed instance of the module and I can pass this UID to the browser but I have no idea how to implement the Javascript side of this module instance.
Modules can be loaded all in one go or loaded separately through AJAX (I am using jQuery).
Now I am using a modular approach that I found in some article, but I can redesign it in some other way if that would help to solve this issue without sacrifising modularity and private/public code separation. For now let's say I have a js file with the following:
//Self-Executing Anonymous Func
(function( MyModule, $, undefined ) {
// My Uid
MyModule.UID = "";
//Public Method
MyModule.onLoad = function() {
alert("Hey, you loaded an instance of MyModule with UID " + MyModule.UID);
};
//Private Methods follow
function somethingPrivate( ) {
}
}( window.MyModule = window.MyModule|| {}, jQuery ));
I am using Smarty for templates. Let's say, I have a simple module template like this:
<div id="{$contents.moduleuid}">
here goes the contents of the module which can be accessed from MyModule Javascript code by using this unique moduleuid
</div>
I have set up the server side so each module automatically appends additional template with Javascript:
<script type="text/javascript">
/*
TODO: here I have access to the {$contents.moduleuid}
But I have no idea what to put here to create a unique instance of MyModule
(also it might need loading js file if it was not loaded yet) and I should also set for
this instance MyModule.UID to {$contents.moduleuid}
and also call MyModule.onLoad for this instance after it has loaded its Javascript.
*/
</script>
I am not experienced with advanced Javascript topics so it is unclear to me how I can create a separate instance of MyModule for each module which gets construced server-side? Is it possible at all to create instances of self-executing anonymous functions? If not, then how can I implement and clone Javascript objects with separated private/public code?
My recommendation is to keep the client side and server side loosely coupled. Try to build your modular client application completely with HTML/JS without PHP tricks on it. As I understand, each of your module (or UI component) need to be loosely coupled from the others. In such case there are several other concerns you might need to look for:
How to keep your UI component structure (html), presentation (css) and behavior (JS) self contained (for example in a single folder), so that it can live or die independently
How these self contained components interact with each other
How to manage the configurations/settings of your UI components
Should you be using MVVM or MVC pattern to organize and bind the view to your PHP model
Who decides when to create/show/hide your UI components (for example based on URL for bookmarking)
If your client is a large and complex application, you might need to look for other concerns such as JS optimization, unit testing, documentation, product sub modules, etc.
Have a look at the BoilerplateJS Javascript reference architecture we put forward at http://boilerplatejs.org. It suggests ways to address all concerns I discussed above.
Since you are already using jQuery, you could create a jQuery plugin. The plugin should behave the way you need, and I believe you won't even need a unique ID. Considering each of your module's instance is contained in a div with class module-container, your jQuery code for adding client-side behavior to the divs would be something like this:
$(function(){
// DOM content is loaded
$('.module-container').MyPluginName();
});
The minimal plugin code would be (considering it's in a separate .js file):
(function($){
$.fn.MyPluginName = function() {
// Return this.each to maintain chainability
return this.each(function() {
// Keep a reference to your unique div instance.
var $this = $(this);
// Plugin logic here
});
};
})(jQuery);
If you are using jQueryUI, I also recommend you also look into the "widget factory" (intro, docs), which serves as a base for building powerful, normalized jQuery plugins.
Related
We use DNN and often need to pass a few context specific values (like page id or module-on-page-id) into an AngularJS app. We've developed our own conventions how to do this, but would like to hear from others how they approach this to find a best practice.
So basically the situation is that the server-page has information needed by the JS. Using WebAPI is not an option, as these values are known in the page, but not in a separate request. Things I've seen so far have been:
Use in-view-razor like href="#Tab.TabId/{{...}}" (I don't like this)
Place the values in the ng-init like ng-init="config = { prop1: '#Tab.TabId' }"
Create a separate <script> tag where we generate a module on the fly containing these values so angular.module("config", []).constant('prop1', '#Tab.TabId')
Create a json with razor in the page somewhere and inject all of it as a module into the app using a generic code which does the same as #3, just with cleaner code re-use.
I've seen all these and have also used all. Currently we avoid #1 as we believe it's not good to mix templating languages and because it doesn't allow externalizing parts of the view. So basically we use #2 as for quick-and-simple (and a bit dirty) + #3/#4 for larger projects.
Do you have a better way, or which way would you prefer?
We are using variant #4.
This has the advantage that the JSON defines the exact interface for the config needed by the JS module. And Razor is great to generate URLs using #Url.Action.
we use NewtonSoft and do JSONConvert.SerializeObject(ObjectName) and then pass it over as a Session from the controller and then use #Html.Raw(ObjectName) and its a JSON Object that can be utilized easily in javascript...
I currently have page-specific javascript files that look something like:
$(document).ready(function ()
{
namespace.home.list = {};
namespace.home.list.Update = function ()
{
var element = $(namespace.ElementIds.LIST);
//some code that pulls a list from the server and dumps the data into our element
});
};
By my own convention, this .js file is meant to belong to Controller Home/List (and correspondingly the View Home/List.cshtml).
Furthermore, namespace.ElementIds has a list of Ids that are manually kept in sync with a (nearly) identical .cs file, so that server-generated html creates elements with the same Ids that I reference in my js files.
I am unhappy with this as a solution for keeping my elementId and js namespaces refactor-friendly. Is there a better way?
Currently my javascript is loaded via script tags with src attributes, but I've considered having them in .cshtml files that have nothing but a script tag with some razor markup that would let me define namespaces + elementIds using only my C# classes. I have a feeling this is not a good idea, but I don't actually know why. It would increase my ability to refactor and link my server code to my client code, but what are the drawbacks? Lack of caching? Decreased performance?
Generally you do not want to have that many javascript files linked to your document. Each uses up a round trip's worth of time and overhead in the HTTP Protocol.
What you should do is build/use a system that collects all your JS files in your project and crunches them into one minified js file (or 2-3 if you need lighter loads in places). This will make sure they load quickly and in one go.
Then you link the one file in your document and it doesn't matter what you rename the original js file to. Or where it lives.
As for namespacing, something you should note:
You should probably wrap up most of your modules in a scope to keep from polluting your global namespace, this has the addded benefit of giving you a shortcut for your namespacing mechanism:
;(function($, $namespace) {
var $module = $namespace.list = {};
$module.Update = function ()
{
var element = $($namespace.ElementIds.LIST);
//some code that pulls a list from the server and dumps the data into our element
};
})(jQuery, namespace.home);
This allows you to have private helper functions with useful (generic) names. Since they're only accessible from within that scope and won't conflict with other modules. Additionally this makes sure your jQuery never conflicts with another js library that may take the $ identifier in the global namespace.
Currently I am using a single .js file for a whole project (plus included libraries). Only occasionally I split the file into multiple files (i.e. front vs back end sections). In the file(s) I attach events (and other functionality) inside of a single jQuery ready event handler using jQuery selectors:
$(document).ready(function() {
$('#an_element_on_homepage').click(function() {
// do something
});
// ...
// A lot of similar code here
// ...
$('.elements_on_homepage_and_contact_page').click(function() {
// do something
});
});
This is perfectly fine and working, but on a larger project there could be a lot of code executing unnecessarily as some events are needed only at specific pages or there could be id/class collisions between different pages. What is the best practice to avoid the problems and still preserve easy maintainability of the JavaScript and HTML code?
I can think of 2 solutions:
Split .js file into multiple files and on every page choose only the files needed. However, it could be hard to distribute the event attachments properly and could cause problems in caching the scripts on client side.
Wrap the event attachments in functions and call them from a HTML code only where needed. Something like:
function attachClickOnElementOnHomepage() {
$('#an_element_on_homepage').click(function() {
// do something
});
}
And after in HTML:
<div id="an_element_on_homepage"></div>
<script type="text/javascript">attachClickOnElementOnHomepage();<script>
However, I have a feeling this is also not the best solution possible.
Can you think of another/better solutions?
This is a classical issue of code structure.
Separate your views into widgets (think plugins). If you have models in your app, separate their declaration from the main onReady event, fire events in your model and allow UI widgets to interact with your models.
Mostly, separate your files in order to:
* have a clearer view of your work
* separate concerns, and expose only what is required
For instance, consider that nothing exists appart from what is located in your file. If you do any use of variables that are not declared in-file, consider you've broken the principle of separation of concerns.
As an example:
var myModel = function () {/**...**/};
var myModel.prototype.save = function () {/**...**/}
var myUIElt = function (model) {
this.render(); //Do whatever required
this.bind('onchange', function() { model.update();});
};
With, such, in your onReady callback, you'll have:
$(function() { var elt = new myUIElt(); }); // Much cleaner, huh ? ;)
In the real world, things may be a little more complicated, but the main idea is the one above.
Don't hesitate to ask for more details,
HTH,
Solution 1. is, as you say, not particularly efficient with regards to HTTP roundtrips, although you can probably choose to ignore that concern if you're making an internal application.
Solution 2. just looks like a roundabout way of inline event handler registrations.
The pattern I use is one JS file that has any code I want to reuse as a project-specific "library" – there's rarely enough of it to warrant splitting it up. And one JS file per unit of server-side code – MVC controller, stand-alone Wicket control – that implements only page-specific behaviour, or wires up to the reusable code. This file is usually named after the controller.
The advantages:
There's clear association of what JS behaviours happen where
You get rid of inline Javascript in pages – I dislike it if only because it makes setting JS breakpoints a chore
If you combine your JS libraries, you only include 2-3 script files on any given page, of which only one isn't reused on every single page
Less risk of conflicts where a selector that's too broad could match elements on a different page than it was intended to and attach unintended behaviour to them.
The JS code is still reasonably straightforward - scripts included on pages. No need to devise a module structure.
A possible downside is that some code may be repeated between the page-specific scripts, but that's the cost of separating mechanism from policy. This mostly happens to me for trivial code like setting up jQuery UI buttons or Chosen selectboxes; since they share a common theme, my solution was to roll these up into a single JS file for "ui enhancements".
You could also look into tooling that will combine fine-grained maintainable javascripts into easier to load ones as a build step; for a large project where the performance gains matter, the effort in maintaining this might not be overkill. The specifics would depend on what your other tooling is, a fallback solution could be as simple as a shellscript that calls the command-line version of jsmin.
you can organize your code in modules with init function defined inside each module
and then call the moduleName.init() function only if needed element is present on currently loaded page
something like
var homePageModule = {
init: function() {
$('#an_element_on_homepage').click(function() {
});
anotherFunction();
},
anotherFunction: function() {
//do something
}
};
//check for elements
$(function() {
if ($('#an_element_on_homepage').length) {
homePageModule.init();
}
});
P.S.: or use classes and instantiate them accordingly to element presence
If it's goint to be a large web project then i would recommend you Backbone.
I want to push my Django project with some JavaScript/jQuery. To make it right from the beginning on I'd like to know, which way of organizing the .js-files ist the optimal one.
For loading one big file includes less overhead than loading many small ones and also because it looks cleaner in the code I considered to make one global .js-file and include that with the base.html (from which every template inherites). However, the result would be, that JavaScript would try to assign all the event-binings, even if the elements which the events should be bind to aren't in the current document. With all the jQuery-selectors which then would have to do their work that can't be too efficient. From earlier web-development experience I know that one can do something like if(location.href == '/some/url/') { (JavaScript code) ... }. That seems not practicable for me in this case, for with changing URLs, I'd have to change the URLconf and the .js-file (while using reverse() and {% url %} to prevent that elsewhere). I guess there is no possibility to make use of the named URLs here?
Has anyone an idea how to organize the JavaScript without having a file for every single template on the one hand and without killing performance unnecessarily?
I don't know that this question is specific to Django - similar issues come up managing Javascript in all sorts of systems.
That said, I usually try to tier my Javascript files, so that truly global scripts and libraries are included in one file, scripts specific to a section of the site are included in a set of section-specific files, and scripts specific to a single page are included in yet another site of page-specific files (or in inline code, depending on the context).
Django has good support for this approach, because you can tier your templates as well. Include the global script in your base.html template, then create a mysection-base.html template that inherits from base.html and just adds the Javascript (and CSS) files specific to that section. Then subpages within that section can inherit from mysection-base.html instead of base.html, and they'll all have access to the section-specific scripts.
I find django-compressor invaluable as it automatically compresses and minifies your JavaScript and CSS pre-deployment. It even automatically handles SASS, LESS and CoffeeScript if they float your boat.
Apps from http://djangopackages.com/grids/g/asset-managers/ may help.
You use modular javascript.
Choose your packager of choice (mine is browserify) that packages all your modules into one package that you minify and gzip. You send this file to the client and it is cached.
This means you have all your code cached, minimize HTTP requests and stay lean and efficient.
And since you have modular code you just load your code as you would normally.
Personally I would use some form feature detection to load modules. You can choose to feature detect on almost any feature (some css selector, routes, url segments).
Feature detection would look like this :
var Features = {
"class": "name",
"class2": "name2",
"dynamic-scroll": "dynamic-scroll",
"tabstrip": "tabstrip",
...
}
for (var key in Features) {
require(Features[key]);
}
Where as routing with davis would look like
Davis(function() {
this.get("blog", function(req) {
require("blog")(req);
});
this.get("blog/:post", function(req) {
require("blog-post")(req);
});
this.get("shop", function(req) {
require("shop")(req);
});
...
});
Alternatively you can try an event driven architecture. This means each module binds to events
// some-module
mediator.on("blog-loaded", function() {
// load in some libraries
// construct some widgets
mediator.emit("blog-ui-build", widgets);
});
And you would need some bootstrapping in place to kick off the event loop. Feel free to look at an EDA demo
When building webapps with MVC web framworks like Django, Kohana, Rails and the like, I put together the application without JS-driven components initially, and then add them afterwards as "improvements" to the UI.
This approach leads to non-intrusive JS, but I don't have a good "standard" way of how to go about organizing the JS work. Most of the JS I write in apps like these are 10-30 line JQuery snippets that hook into some very specific part of the UI.
So far I often end up inlining these things together with the part of the UI they manage. This makes me feel dirty, I'd like to keep the JS code as organized as the python / php / ruby code, I'd like for it to be testable and I'd like for it to be reusable.
What is the best way to go about organizing JS code in a setup like this, where we're not building a full-blown JS client app, and the main meat is still server side?
I am also very interested in what other people have to say about this. The approach I've taken is to use object literal notation to store the bulk of the function, and store these in one file included on all pages (the library)
uiHelper = {
inputDefault:function(defaulttext){
// function to swap default text into input elements
},
loadSubSection:function(url){
// loads new page using ajax instead of refreshing page
},
makeSortable:function(){
// apply jQuery UI sortable properties to list and remove non javascript controls
}
}
Then I include a .js file on any page that needs to use the library that ties the elements on that page to the function in the library. I've tried to make each function as reuseable as possible and sometimes the event binding function on the page calls several of my library functions.
$(document).ready(function(){
$('#mybutton').live('click',uiHelper.loadSubSection);
//more complicated helper
$('#myotherbutton').live('click',function(){
uiHelper.doThisThing;
uiHelper.andThisThing;
});
});
edit: using jsDoc http://jsdoc.sourceforge.net/ notation for commenting for these functions can produce documentation for the 'library' and helps keep your code easy to read (functions split by comments).
The following question is along similar lines to your own - you should check it out...
Commonly accepted best practices around code organization in JavaScript
When dealing with JS code, you should first analyze whether it will be used right away when the page loads. If it's not used right away (meaning the user must do something to invoke it) you should package this into a JS file and include it later so the load time is perceived faster for the user. This means that anything that the user will sees should go first and JS related to the functionality should be imported near the end of the file.
Download this tool to analyze your website: http://getfirebug.com/
If the JS code is small enough, it should just be inline with the HTML.
Hope that helps a bit.
For quick little user interface things like that I put everything into a single javascript file that I include on every page. Then in the javascript file I check what exists on the page and run code accordingly. I might have this in UIMagic.js for example. I have jQuery, so excuse those jQuery-isms if they aren't familiar to you.
function setupMenuHover() {
if ($("li.menu").length) { // The page has a menu
$("li.menu").hover(function() { ... }, function() { ... });
}
}
$(setupMenuHover);
function setupFacebookWizbang() {
if (typeof FB != "undefined") { // The page has Facebook's Javascript API
...
}
}
$(setupFacebookWizbang);
I've found this to be a sane enough approach.
My preferred method is to store inline javascript in it's own file (so that I can edit it easily with syntax highlighting etc.), and then include it on the page by loading the contents directly:
'<script type="text/javascript">'+open('~/js/page-inline.js').read()+'</script>'
This may not perform well though, unless your templating library can cache this sort of thing.
With Django you might be able to just include the js file:
<script type="text/javascript">
{% include "js/page-inline.js" %}
</script>
Not sure if that caches the output.
If you are still worried about being 'dirty', then you could check out the following projects, which try to bridge the server/client side language mismatch:
http://pyjs.org/ (Python generating JavaScript)
http://code.google.com/webtoolkit/ (Java generating JavaScript)
http://nodejs.org/ (JavaScript all the way!)