my rails applications (all 2.3.5) use a total mix of inline javascript, rjs, prototype and jquery. Let's call it learning or growing pains. Lately i have been more and more infatuated with unobtrusive javascript. It makes your html clean, in the same way css cleaned it up.
But most examples i have seen are small examples, and they put all javascript(jquery) inside application.js
Now i have a pretty big application, and i am thinking up ways to structure my js. I like somehow that my script is still close to the view, so i am thinking something like
orders.html.erb
orders.js
where orders.js contains the unobtrusive javascript specific to that view. But maybe that's just me being too conservative :)
I have read some posts by Yehuda Katz about this very problem here and here, where he tackles this problem. It will go through your js-files and only load those relevant to your view. But alas i can't find a current implementation.
So my questions:
how do you best structure your unobtrusive javascript; manage your code, how do you make sure that it is obvious from the html what something is supposed to do. I guess good class names go a long way :)
how do you arrange your files, load them all in? just a few? do you use content_for :script or javascript_include_tag in your view to load the relevant scripts. Or ... ?
do you write very generic functions (like a delete), with parameters (add extra attributes?), or do you write very specific functions (DRY?). I know in Rails 3 there is a standard set, and everything is unobtrusive there. But how to start in Rails 2.3.5?
In short: what are the best practices for doing unobtrusive javascript in rails? :)
I do not think there is one best practice, but I'll let you know what I do.
I have a series of js files each for with their own purpose in the public/javascripts/ directory. Some examples could be utility.js chat.js shopping_basket.js and so on.
I use asset packager and define one big fat collection for all my general use functionality and another for admin only functionality. Round trips to the server cost way too much. I basically include all the js in on first page load minified into one blob (in general)
I allow basic $(document).ready hooks inline in the pages, and keep them really short.
Data that my js files needs to access is rendered inline with the page. (Usually in the DOM, sometimes as vars - Eg. var xyz = 100)
I will usually develop my controllers with javascript off (and make sure it all works), then I turn it on and sprinkle a few if request.xhr? where needed.
Keep in mind, Rail 3.1 introduces a built-in best practice, see: http://guides.rubyonrails.org/asset_pipeline.html - on a personal note I have had performance and configuration issues with the new pipeline, however many others have had great success with it.
I recently documented how I have been managing javascript in Ruby on Rails. I basically break things down into many small, granular files, each with an appropriate namespace and then merge them all into a single file for production using asset_packager.
I found this post while trying to solve the same problem, but none of the existing solutions struck me as the right one. I wrote up my approach here. I love Rails' convention over configuration, so I wanted the same approach to including Javascripts that are applicable only to a particular action page. If nothing else, it's at least another approach to add to your options.
Related
I realize this may not be the right place to ask this question so feel free to send me elsewhere. I am looking to internationalize a set of apps that have strings in a combination of java, tsp and javascript files. We have some use of resource bundles in a. few of the java apps but I am looking for a unified approach for all to both reduce the number of translation files and provide a single point of reference for them. I have yet to stumble upon a solution that is not specific to one or the other.
What I have thought of so far:
Database-driven - this would achieve the two stated objectives but, unless I am missing something, would result in a lot of db calls and likely performance degradation.
External files - this is the most feasible approach as I can read from a shared location. The only part I am struggling with is how to organize them so as to make it possible to load all the tags for, say, a single page together.
I would recommend the "External files" approach... decouple your translation files from your code... this would help your localization process a lot.
For i18n you might read this article (focus JavaScript but not only) ...
I would recommend looking into a i18n lib that is ready to be used in different frameworks, i.e. i18next
There is some java based lib too: i.e. i18next-android
As said in the beginning, you should not only consider that you have to instrument your code (i18n) to get your app/website translated. You should think about the process too - how will you solve continuous localization, how you keep track of progress, etc...
For a translation management+ system you might eg. have a look at locize it plays well with all json based i18n frameworks and in the core has a very simpe api... and provides a lot more than traditional systems...
What is the best way to deal with multiple client side templates?
I noticed that if I keep them in my "mother" html file, it soon gets bloated with stuff, so I thought that maybe it would be better if I just put them in separate js files and load them one by one.
Another idea of mine was to avoid putting them separately as templates, but rather write them as strings and sort of couple them with the backbone.js views which are going to use them. I know that this would bring a lot of negative from designers, web developers, and software engineers in general, but for the projects I am working on, this seems like a very speedy way to develop because I have logic and layout at the same place. Plus, by reverse engineering, I proved that a bunch of prominent web services are doing the same so ...
One option is to use RequireJS, which includes a 'text' plugin for templates.
You can then use the r.js optimizer to combine all of these (plus JS modules, if you go that route) into a single file.
The optimizer can be run either as part of your build process, or in-process if you're using node.js.
You can have them in separate files, but combine into one file on a server side.
And take a lot of negative from me for your idea to keep templates in strings :). It might work until they are simple, but when they get more complex it gets badly, because html structure is not so obvious, so it is harder to write css and so on.
As #stusmith said, require.js is a good option.
also, take a look at the boilerplate's examples
http://backboneboilerplate.com/
https://github.com/thomasdavis/backboneboilerplate/blob/gh-pages/js/views/backbone/page.js
cheers
I've seen a few ways that you can make a javascript file include other javascript files, but they all seem pretty hacky - mostly they involve tacking the javascript file onto the end of the current document and then loading it in some way.
Why doesn't javascript just include a simple "load this file and execute the script in it" include directive? It's not like this is a new concept. I know that everyone is excited about doing everything in HTML5 with javascript etc, but isn't it going to be hard if you have to hack around omission of basic functionality like this?
I can't see how it would be a security concern, since a web page can include as many javascript files as it likes, and they all get executed anyway.
The main problems with the current inclusion system (ie, add additional script tags) involve latency. Since a script tag can insert code at the point of inclusion, as soon as a script tag is encountered, further parsing has to more-or-less stop until the JS downloads and is executed (although the browser can continue to fetch resources in parallel). If the JS decides to run an inclusion, you've just added more latency on top of this - now you can't even fetch your scripts in parallel.
Basically, it's trying to solve a problem that doesn't exist (since JS can already tack on additional script tags to do an inclusion), while making the latency problem worse. There are javascript minifiers out there that can merge JS files; you should look into using those instead, as they will help improve latency issues as well.
Actually, YUI 3 solves this problem beautifully. Feel free to check out the documentation: http://developer.yahoo.com/yui/3/yui/#use (that's the specific Use function which does this magic). Basically it works like this:
You define modules
When you create the core YUI object with YUI(), you specify which modules your code needs
Behind the scenes, YUI checks if those modules are loaded. If not, it asynchronously loads them on the page.
I've also read that the jQuery team's working on something similar (someone back me up here).
As to the philosophical argument that it'd be nice if this was built in, I think that may be a good feature. On the other hand, the simplicity of javascript is nice too. It allows a much lower point of entry for beginning programmers to do their thing. And for those of us that need it, great libraries like YUI are getting better every day.
the requirejs project attempts to solve this problem, please see for example
http://requirejs.org/docs/why.html
(I don't use it yet, though)
I've used RJS in the past for RoR projects and felt terribly constrained by what it could do. However, using Javascript alone felt/feels ugly and hack-y. This is particularly true when writing Javascript that manipulates Rails automagically generated from variable names. I haven't seen much talk about RJS in the blogosphere recently. Is RJS being used in new RoR projects or have people decided that it's not effective? Is it still being actively developed and its function-coverage expanded? I'd appreciate some insight into the current state of affairs.
So, who's using RJS (and how is it working out for you) and who's using javascript?
I recommend writing straight javascript. I believe that - yes - RJS is going out of style. One reason for this is the popularity of the sexy jQuery library. Another is the model of RJS - in that it is a ruby wrapper around javascript, and so for any javascript library you need to use, you will need a corresponding ruby wrapper library, which means more grunt work somebody's going to have to do(and another gem you'll have to depend on). Also, although the idea of making a request and receiving back executable javascript is nice, I believe there are many who don't like this style, or at least don't think it's appropriate for certain situations. I personally have learned javascript and have come to like it a lot, and I recommend you give it a try.
I like using RJS for simple tasks, like:
page["post_#{#post.id}"].replace :partial => #post
page["post_#{#post.id}"].highlight
Yes, you could do this directly with the link_to_remote function, but that just clutters up your view with code, or with an update_page in the controller, but that is ugly.. the rjs allows you to write more clearly understandable code that's uncoupled from any javascript library (since there are things like jrails out there, or you can just override the Rails' methods yourself.)
If you have a really complex javascript function for your application, you'd probably be better served by writing the javascript yourself, since at that point, you won't want to rely on the abstractions that Rails provides.
By RJS, I assume you are referring to RJS templates. The whole concept is that you are generating JavaScript that will be run in a JS eval function in the browser as an AJAX return. How exactly is it that you "felt terribly constrained by what it could do"? You can mix Ruby and JS in the RJS files in a variety of ways, and it isn't any more constraining than other ERB type formats. It's a very powerful way to make AJAX calls do more than update a single <div> (they can even update two <div>s).
I have a feeling you are really meaning to ask about using the JavaScript/Prototype/Scriptaculous Helpers. Is that so?
RJS was never intended to be a flat-out replacement for JavaScript, and you shouldn't decide which tool is right for the job based on what you think you see some other kid doing on the blogosphere.
I personally do not like the js generated by the helpers, so I usually opt to not use them. However, there are times when they are quite convenient.
There is also a Jquery replacement, Jrails, if your not a Prototype fan.
But, I have to agree with NSD. Why would you let what others do ultimately lead your path. If you don't like the way the helpers work or they are not doing it for your project, don't use them. Or if it's missing something, write your own. And perhaps in that, you can ignite some intrest.
As for investing time, it's knowledge.
All of my projects include very similar tasks and quite recently I've been thinking I should write a library to handle most of the heavy lifting so I can write short, simple, easy to read code that interacts with the library to get the jobs done. Looking at other frameworks, specifically jQuery & YUI, they work in different ways. jQuery mostly seems to extend & simplify the DOM using a global object/function whereas YUI uses namespaces and modules. I understand that this is because they have different goals as libraries and each have their merits.
Most specifically, I'm looking for answers to the following questions:
Is it best to use namespaces, eg gui.scrollbar.attach(), or a global method such as $(domObj).attachScrollbar()?
Is it best to include individual parts as seperate js files or as a single js file where components are copied/pasted? I know the eBay Shopping API SDK has many .js files in seperate folders, wouldn't this suffer a significant performance hit?
Is there any other advice you would give to someone looking to create a javascript library?
I've marked as community wiki because I didn't want to risk the question being closed - I'm genuinely seeking advice here.
Thanks
EDIT
I should have originally stated that I'm not re-inventing the wheel, I'm looking to simplify many common tasks between Windows Desktop Gadgets, so I don't need the cross-browser compatibility of other libraries and their core functionality doesn't really apply to what I'm doing. I tried to keep the question general and not specifically relating to desktop gadgets, so that this question would be useful for others.
Simple answer to your question: write your library using an existing one.
I have some javascript files written in jQuery just for such purposes.
More specifically,
If you are going for java-style object oriented-ness, go for namespaces. I prefer the jquery way of writing plugins.
If you are writing your own "toolkit", it would be best to copy and paste the dependencies (minified) into your source code. This way
a. you avoid the overhead you mentioned
b. you prevent unnecessary dependencies creeping up externally.
Cheers!
Concerning your first question, the two options are really the same IMO. Instead of a global object like YAHOO or gui, you have a global function like $. In both cases you have a global variable that holds your namespace.
Is there any reason why you can't use one of the many libraries out there already? This seems like a case of reinventing the wheel. These libraries have been around for years and have already tackled many of the issues that you will surely run into when trying to write your own.
In terms of some of your questions:
This is really a matter of preference IMO. As long as you get your functions out of the global namespace that is the major thing. However, this design choice will drive many others down the line.
It is best to include all core functionality in one file and then to chunk the rest into files that are required for a bit of functionality. You want to keep the number of files down, but you also don't want the user to have to download a lot of stuff that they don't need.
Having said all that, I restate that you should look at using one of the libraries already out there unless you have a very good reason not to. Keep in mind that you will need to test in all old browsers as well as any new browsers that come out.
jQuery, YUI, Prototype, Mootools, extJS are a few of the most popular