Wednesday, August 13, 2008

Ext JS with Rails in Twitter

Since there had been a lack of time and courage to overcome the obstacle lately to author new blog posts, I decided to do mini posts instead. And to add a little more social flavor to that, I'll post them to my new twitter account: http://twitter.com/extjswithrails
So, follow me or write me via the @ thing. See you in twitter!

P.S. Posts on this blog might follow, too, though.

Friday, June 27, 2008

Ext.ux.RowWithCellSelectionModel

I recently published another Ext JS extension at http://github.com/steffen/ext.ux.rowwithcellselectionmodel/ I want to let you know about.

Ext.ux.RowWithCellSelectionModel

This Ext JS extension enables the user to activate the editor of an editable cell in an Ext.grid.EditorGridPanel through a double click, to navigate through the cells via the cursor keys and select one or multiple rows through the mouse or through the cursor keys, if no cell is currently selected.
In summary, this selection model is a combination of the two built-in selection models Ext.grid.RowSelectionModel and Ext.grid.CellSelectionModel.
I created it out of the need to be able to add, edit and delete records in an EditorGridPanel. To delete one or multiple records, the user needs to select one or multiple rows which is not possible when using the default Ext.grid.CellSelectionModel.


Installation

Either
git clone git://github.com/steffen/ext.ux.rowwithcellselectionmodel.git
or download the files from http://github.com/steffen/ext.ux.rowwithcellselectionmodel/tarball/master
and put them in a public accessible folder.
Include the RowWithCellSelectionModel.js file in the header of your html page after the Ext JS files.



Usage

new Ext.grid.EditorGridPanel({
ds: your_data_store,
cm: your_column_model,
sm: new Ext.ux.RowWithCellSelectionModel()
});


Alternatives

There exists another extension called Ext.ux.grid.RowAction by Jozef Sakalos, aka Saki, which enables you to add
icons with actions to grid rows. You can't delete multiple records at once, but it's worth a look. See http://rowactions.extjs.eu/ for more infos.

Friday, June 13, 2008

Ext.form.FieldSet and Ext.layout.CardLayout

This post is a note to myself and maybe to some others, since I today searched for the second time for a solution for a misbehavior (bug) in Ext JS when using an Fieldset inside a Panel which belongs to a Panel with a CardLayout.
When I set the Panel with the Fieldsets as the active item via panel_with_card_layout.getLayout().setActiveItem('form_with_fieldsets_panel') everything was shown/rendered besides of the form fields inside the Fieldsets.
After a little debugging and breakpoints fun in Firebug, I decided to search in the Ext JS Forum and luckily found the solution for that problem fast, thanks to the Forum's Google Search.

The solution is that you have to call panel_with_card_layout.doLayout() after setting the active item.

In conclusion, the following two lines should always go together when using FieldSets in a CardLayout:
panel_with_card_layout.getLayout().setActiveItem('form_with_fieldsets_panel');
panel_with_card_layout.doLayout();

Here's the note from an Ext Support Team member regarding this problem, which notes that there is another solution when you are using the Ext.TabPanel (which has the CardLayout as default Layout):

This is exactly why layoutOnTabChange was added to tabpanel. Unfortunately this fix wasn't added to card layout, so you'll have to call cardPanel.doLayout(); yourself after cardPanel.render('showcard');
Quote from http://extjs.com/forum/showthread.php?p=156627


Luckily, this is one of the rare bugs you'll run in when working with Ext JS. Pretty much everything else works as expected. :-) After all, a Friday the 13th could be worse. ;-)

Saturday, May 31, 2008

Ext.apply and Ext.applyIf

In case you missed it, last weekend Jay Garcia released his third screencast in which he explains Ext.apply.

Here is the video, a short 7 and something minutes long, which is a fresh alternative of reading plain blog posts. :-)





Jay actually mentions a firebug bug which I wasn't aware of but which I encountered just this week after learning about it in his screencast. The bug is that the properties of an object you are inspecting (after clicking on the your object which is printed to your console via console.log(object) or console.info(object)) might not be the actual current ones. The work-around is to print directly the property you want to inspect via console.log(object.property).

If you're a little confused about the defaults (third) parameter of Ext.apply, then just think of it as you would write the the following

Ext.apply(receiver, defaults);
Ext.apply(receiver, source);

// is the same as
Ext.apply(receiver, source, defaults);


Also note that there is an Ext.applyIf method (without a third parameter) which only assigns properties/attributes to the receiver object if they aren't existing in the receiver object yet.

And as a small extra here's a real-world example of using Ext.apply which I implemented this week:

onBeforeLoad: function(store, options) {
options.params = options.params || {};
this.cleanParams(options.params);
var params = this.buildQuery(this.getFilterData());
if (store.lastOptions && store.lastOptions.params) {
options.params = Ext.apply(store.lastOptions.params, options.params);
}
Ext.apply(options.params, params);
}

I'm overwriting here the onBeforeLoad method from the excellent Ext.ux.GridFilter extension which is executed every time before the store is loading.
So if you load the store the first time via store.load({params: {start: 0, limit: 50}}), it will resend these parameters when the store is reloaded after you changed your filter values or after you manually executed store.load() after you saved changes to your EditorGridPanel for example. Moreover, the lastOptions params will be overwritten when you switch to the next page via your PagingToolbar, which calls something like store.load({params: {start: 50, limit: 50}}).

Monday, May 26, 2008

More Rails 2.1 changes that target JSON and therefore Ext JS

Two days ago I posted about Rails 2.1 changes that make living with Ext JS easier. Today I discovered (via Jörg Battermann) a tutorial about using Rails 2.1 (see Part 1 and Part 2).
The tutorial shows two new config options that target JSON, especially the to_json method: ActiveRecord::Base.include_root_in_json and ActiveSupport.use_standard_json_time_format

Here are the respective changesets and some more information on these changes:

Changeset 9202: Tweak ActiveRecord::Base#to_json to include a root value in the returned hash: {post: {title: ...}}

This is almost a nice change. I mean almost because it might help you when feeding your Ext JS forms via a Ext.data.JsonReader, but it'll break your Ext JS grids, when using the Ext.data.JsonReader.

Currently, you do something like the following in your javascript code:

orders_ds = new Ext.data.Store({
reader: new Ext.data.JsonReader({root: 'orders', id: 'id' }, orders_items),
proxy: new Ext.data.HttpProxy({url: orders_path_json})
});

and the following in your controller action:

render :json => { :orders => @orders }

which returns a JSON data in the following format

{"orders": [{"id": 1, ...}, {"id": 1, ...}]}

Well, after you turn on the ActiveRecord::Base.include_root_in_json option, it'll return:

{"orders": [{"order": {"id": 1, ...}}, {"order": {"id": 2, ...}}]}

which cannot be understood by your Ext.data.JsonReader by default.

It would be smarter if the include_root_in_json would differ between a single active record object and a collection of active record objects.
Therefore, if you use render :json => @orders or @orders.to_json, it would return the data in an array without a root for each object, but with the plural name of the model class name as root for the array. Just as I showed in the first JSON data example.
Well, maybe I'll write a patch for Rails for that.

Changeset 9203: Add config.active_support.use_standard_json_time_format setting so that Times and Dates export to ISO 8601 dates.

If you turn on this config option, it will probably also break your Ext JS grids. But you can easily fix that...

Right now you probably have this code in your record layout part when dealing with dates:

{ name: 'release_date', type: 'date', dateFormat: 'Y/m/d' }

Well, your JsonReader assumes that the date format is Y/m/d. But after you turned the use_standard_json_time_format option on, it will return the date in the default JSON date format.
It means you have to change the date format to the following:

{ name: 'release_date', type: 'date', dateFormat: 'Y-m-d' }


Well, these Rails changes are all JSON related changes that come in the soon to be releases Rails 2.1, but which won't really make your life easier with Ext JS. Sorry to disappoint you on that. But Rails is certainly going into the right direction.

Saturday, May 24, 2008

Rails 2.1 changes that make living with Ext JS easier

I just like to point out a few changes of the soon to be released Rails 2.1 which I caught via Chu Yeow's Living on the edge blog series.

Automatically parse posted JSON content for Mime::JSON requests
The most important change is probably the automatically parsing of JSON requests into the params hash.
Here's the example from Chu Yeows's post:

# http request
POST /posts
{"post": {"title": "Breaking News"}}

# controller action code
def create
@post = Post.create params[:post]
end

Similar functionality is also provided by the json_request plugin which I use currently with Rails 2.0.2.

json_escape for escaping HTML entities in JSON strings
In the same post, Chu Yeow is mentioning the addition of json_escape:

json_escape("is a > 0 & a < 10?")
# => is a \u003E 0 \u0026 a \u003C 10?

# or you can use the alias j in your erb/haml templates:
<%=j @person.to_json %>

Right know I can't think of another use as Chu Yeow's example for documenting a JSON api.

Custom JavaScript and stylesheet symbols
You all know javascript_include_tag :defaults, which includes your application.js and prototype files.
Now you can define your own symbols, such as :extjs.

See here for details of this change.
This addition is similar to my little helper I use in my projects which I described in my ext-all.js or ext-all-debug.js post.

Haml 2.0
By the way, because I mentioned haml, today Haml 2.0 was released, which includes a javascript filter. Check out the blog post for more info.

Thursday, May 22, 2008

Rails helpers in Ext JS

Today I needed to truncate a set of strings in Ext JS. Rails has the truncate helper method built in, Ext JS not, which isn't bad since it's pretty easy to write your own little helper in Ext JS.
Update: Diego pointed out that there is actually a truncate method in Ext JS, called ellipsis which can be found in the Ext.util.Format class. I hope this post still makes a little sense, since it's about writing your own helpers in Javascript/Ext JS.

Here's the Ruby code from the Rails core:

def truncate(text, length = 30, truncate_string = "...")
if text.nil? then return end
l = length - truncate_string.chars.length
(text.chars.length > length ? text.chars[0...l] + truncate_string : text).to_s
end

Here's my little Javascript helper:

Ext.apply(String.prototype, {

truncate_length: 30,

truncate_string: "...",

truncate : function(truncate_length, truncate_string) {
truncate_length = truncate_length || this.truncate_length;
truncate_string = truncate_string || this.truncate_string;
var length = truncate_length - truncate_string.length;
return this.length > truncate_length ? this.substr(0, length) + truncate_string : String(this);
}

});

It has the same behavior as the Rails helper. Note that you don't really have to use Ext.apply(), but it helps you to DRY your code, since you can pass an object with multiple methods and attributes to the prototype attribute, instead of writing String.prototype = function() { .. } for each attribute/method you want to add/overwrite.

Creating an extra attribute for truncate_length and truncate_string allows you to easily define your default values for your app. So if you like to append only two dots by default, just add String.prototype.truncate_string = '..' to your code.

While writing this post I actually remember that Prototype JS has the truncate and many other helper methods already built in. But well, writing your own helpers (with the help of Ext JS) can be fun, too. X-D

Here is the Prototype code, just for the sake of comparison:

truncate: function(length, truncation) {
length = length || 30;
truncation = truncation === undefined ? '...' : truncation;
return this.length > length ?
this.slice(0, length - truncation.length) + truncation : String(this);
}

Wednesday, May 14, 2008

Ext JS Events, Observable and DomHelper slides

Want to learn more advanced stuff about how to use Ext JS?
Check out these slides from an Ext JS core developer named Aaron Conran. You might know him from the Ext JS forum.



First a very good and quick introduction to Javascript, where you learn more about strictly (not) equals such as === and !== which you encounter often in the Ext JS code and also some nice to know information about the difference between null and undefined.



The next presentation teaches you about Ext JS Event Handling:




Next a presentation about Ext JS Observable Class which includes a nice example of how to catch all fired events of an object and print them to your firebug console.



Ext JS's Dom helpers should also be checked out!






Thanks Aaron for putting together these very helpful slides!


Wednesday, April 30, 2008

Ordered Attributes

I released my first Ruby on Rails plugin today. It is actually helpful for building Ext JS grids! More on that later in an extra post. Below some information about the ordered attributes plugin (taken from the README file).

Ordered Attributes
This Ruby on Rails plugin provides a way to order ActiveRecord attributes for using them for csv exports or automated
table generation.

Installation
git clone git://github.com/steffen/ordered_attributes.git vendor/plugins/ordered_attributes
or if you are on edge rails
script/plugin install git://github.com/steffen/ordered_attributes.git

Example

class Person < ActiveRecord::Base

attr_order :name, :street, :zip, :city

attr_groups :address => [:street, :zip, :city],
:birth => [:date_of_birth, :place_of_birth], // you can use %w(date_of_birth place_of_birth) as well
:all => [:name, :address, :birth]

end

Use the ordered_attributes method to get the ordered attributes:

Person.ordered_attributes
=> [:name, :street, :zip, :city]

Person.ordered_attributes(:all)
=> [:name, :street, :zip, :city, :date_of_birth, :place_of_birth]

See spec/ordered_attributes_spec.rb for more Examples!

Tuesday, April 22, 2008

Ext JS 2.1 with (more-or-less) first-class REST support released

In case you missed it, yesterday the Ext JS Team released version 2.1 of it's impressive Javascript library.

Besides nice new widgets such as the slider and statusbar, and big performance improvements, the Ext JS library is now supporting the PUT and DELETE http verbs (besides GET and POST) when using their Ext.form.Action class for Ajax Requests. But is that helping us Rails developers? Not really, since most browsers haven't first-class support for PUT and DELETE (yet). Rails uses a work-around for this problem. If you, for example, create a form tag with the PUT method, it creates an hidden form field with name _method and the http verb as value. Therefore you actually have to add this hidden form field in your Ext form manually and continue using POST as method.

Here is their blog post with all infos about this release and other news (such as a new ext js website with more examples!)

Btw, they also show a preview of Ext JS 3.0, which includes a performance-optimized datagrid view. I recently addressed/solved the performance issues in my PrinterGridPanel class included in my PrinterFriendly extension, which is meant for printing and has therefore less view-features.

Tuesday, April 8, 2008

Ext.ux.PrinterFriendly, 0.2

I hope nobody minds if I post some update announcements for my Ext JS extension here in my blog. The next Rails-specific post is coming soon...

Here are the changes for version 0.2:

  • Added config.js file for customized settings

  • Added Ext.ux.PrinterFriendly.ENABLE_SHORTCUTS config option

  • Added Ext.ux.PrinterFriendly.ROOT constant

  • Added x-grid3-cell-first and x-grid3-cell-last class to header cells

  • Added config parameter to printPreview to set config options for the print preview window, i.e. the title

  • Added 'printer-window' id for printer window

  • Added init.js file, which loads dynamically all other required files

  • Added closeText and printText config option to PrinterWindow for localization purposes

  • Added hiding of body until the printing layout gets initiated, this way the user doesn't see the page without the custom printer css, which the user might add in the onPrinting function

  • Removed Ext.PRINTER_FRIENDLY_CSS_URL constant

  • Changed all internal extensions to use Ext.ux.PrinterFriendly namespace

  • Changed name of format parameter from format to _format, since it conflicts with the format parameter in Ruby on Rails

  • Changed loading of printer friendly css file, will be loaded now when loading js scripts, which prevents the user from seeing the page before the css is loaded

  • Fixed error in Safari in addStyleSheet method which caused that onPrinting is not executed

  • Fixed print button for IE, IE is printing the content of the iframe now

  • Fixed css bug in IE, empty cells will be filled with now, so that the css border is shown



The files can be found here.

Friday, April 4, 2008

Ext.ux.PrinterFriendly, 0.1 (Initial Release)

I'm happy to announce the first release of my (first) Ext JS extension.
Here are the facts:

Name
Ext.ux.PrinterFriendly

Version
0.1 (Initial Release)

Summary
Easily build printer friendly layouts and grids for your Ext JS pages.

Features

  • Builds a normal html table (Ext.ux.PrinterGridPanel) based on your data store and column model, which saves a lot of cpu power and memory when printing large data sets. Moreover it shows all rows. (Remember, you can't use ext's pagination or scrolling on paper. ;-))

  • Remembers the state of your grid, such as that hidden columns stay hidden in printer friendly view, keep their column order and keep the row sorting. (This is not really a feature of this extension, it just uses the fabulous Ext.state.Manager, but I think it's important to mention, since this was an important requirement for me.)

  • Completely Javascript-driven, no need for extra server-side coding for printer friendly pages

  • Enables easy debugging of your printer-friendly layout (just add ?format=printerfriendly to your page url to see printer friendly view)

  • Enables adding your custom stylesheet for your printer-friendly format



Source
See attachments on this post (in the Ext JS Forum).

Documentation
http://extjs.com/learn/Extension:PrinterFriendly

Example
See attachments on this post (in the Ext JS Forum).

Feedback
Any Feedback via comments on this post in the official Ext JS forum or in this blog is welcome!

I hope you find this extension as useful as I do! :-D

Regards,
Steffen

Thursday, April 3, 2008

Ext JS Screencast (Sketchcast) about Ext.extend and Ext.override

Jay Garcia from TGD innovations LLC started doing a series of screencasts (or so-called sketchcasts) about Ext JS. Here's his second one about Ext.extend and Ext.override. It's certainly an interesting way of doing a screencast using a (digital) whiteboard.



Check out his Blog at http://tdg-i.com which also includes some nice explained Ext JS examples.

Monday, March 31, 2008

Fitting Ext JS into the Rails architecture

When you start building your first Ext JS page into your Rails application, you certainly will wonder where to put the Javascript code.
Instead of just creating a javascript file such as posts_show.js in your public/javascript directory, here is a more elegant way for adding Ext JS pages to your Rails (2.0.2!) project:

# app/controllers/post_controller.rb

def show
@post = Post.find params[:id]

respond_to do |format|
format.html { render :layout => "extjs" } # *
format.js
end
end

# *) special extjs layout which includes the required extjs files,
# in case you have a different default layout for non-Ext JS pages


# app/posts/show.html.erb

<%= javascript_include_tag formatted_post_path(@post, :js) %>

# app/posts/show.js.erb

Ext.onReady(function(){
// your ext js javascript code here
// because this file is rendered via the erb renderer,
// you can add ruby code such as:
alert('<%= @post.title %>');
});

Thursday, March 27, 2008

Inspecting your Ext.onReady variables

In the Ext JS examples included in the Ext JS package, you'll find usually this code:

Ext.onReady(function(){
..
var store = new Ext.data.SimpleStore({
..
});

var grid = new Ext.grid.GridPanel({
store: store,
..
});
});


Notice the var keyword in front of the declared variables! The var keyword is defining the variables as local variables. They are only existing in the scope of the anonymous function which is passed to the Ext.onReady method.
But what if we'd like to inspect the values of our local variables in firebug? We could set a breakpoint inside our anonymous function which will allow us to inspect these local variables. But it's a little annoying to do that everytime we're working on an Ext page.

Well, we just could remove the var keyword or use this.store. But that would clutter up our global scope which isn't that nice.

Here is a better solution I came up with today:

Ext.screen = {}

Ext.onReady(function(){
var s = Ext.screen;
..
s.store = new Ext.data.SimpleStore({
..
});

s.grid = new Ext.grid.GridPanel({
store: s.store,
..
});
});


With that solution all our local variables can be referenced by Ext.screen.variable in our firebug console, while keeping our global scope clean by using the Ext.screen namespace.

ext-all.js or ext-all-debug.js

To ease the debugging process, the Ext JS package includes the uncompressed javascript files of their library as well.

Here's a small Rails helper to add the Ext JS library files based on your Rails environment:

# app/helpers/application_helper.rb
module ApplicationHelper

... # your other helpers here

def javascript_include_extjs
if RAILS_ENV == "production"
javascript_include_tag "ext/adapter/ext/ext-base.js", "ext/ext-all.js"
else
javascript_include_tag "ext/source/core/Ext.js", "ext/source/adapter/ext-base.js", "ext/ext-all-debug.js"
end
end

end



In your view layout header you just need to call:


<%= javascript_include_extjs %>


Important: Don't forget the ext js css files!

P.S.
You can find some more hints on debugging Ext JS here.

Sunday, March 23, 2008

Sending forms the "old way" with Ext JS

The normal non-AJAX life-cycle of sending a form in Rails is the following:

  1. The user submits the form
  2. The browser is going to the form's action url
  3. The Rails action calls some model methods and sends a redirect to the users browser to a overview page or the created record for example
Here are some code snippets to solve this life-cycle with Ext JS and Rails:

// ext js form

var submit_button = new Ext.Button({
text: "Submit",
handler: function () {
form = this.ownerCt.getForm();
form_as_dom = form.getEl().dom;
form_as_dom.action = form.url;
form_as_dom.submit();
}
})

new Ext.form.FormPanel({
url: "<%= confirm_order_path(@order)%>",
standardSubmit: true, // doesn't do anything in ext js version 2.0.2
items: submit_button
})

# rails controller action

def confirm
order = Order.find params[:id]
order.confirm!
order.save # no error handling in this example

redirect_to order_path(order)
end


The special thing here is, that Ext JS doesn't really support the old-way of sending form data to the browser. But it's actually on their roadmap for the 2.1 release in this spring, which should be out very soon. The above code shows the current "work around" by using the actually DOM object of the form.

For completion and comparison, here the code for doing a form submit via AJAX.

// ext js form

var submit_button = new Ext.Button({
text: "Confirm",
handler: function () {
form = this.ownerCt.getForm()
form.submit({
success: function () {
this.setText("Unconfirm");
form.url = "<%= unconfirm_order_path(@order) %>";
},
scope: this
});
}
})

new Ext.form.FormPanel({
url: "<%= confirm_order_path(@order)%>",
standardSubmit: false, // false by default,
// but doesn't do anything in ext js version 2.0.2
items: submit_button
})

# rails controller action

def confirm
order = Order.find params[:id]
order.confirm!
order.save # no error handling in this example

render :text => "{ success: true }" # ext js converts
# responses to json by default, that means no need
# to send an explicit json header
end

Saturday, March 22, 2008

Discovering Ext JS with Rails

Before I discovered the Ext JS - Javascript Library in November 2007, I was working with Ruby on Rails for almost a year. (I know, pretty late since Rails came already out in 2004, but I was stuck with my PHP Projects.)

From then on, Rails was really helping me to get my models and controllers in order. But what about the view layer? Yes, Rails was helping me here, too. But not as much as on the model and controller level. I like partials, helpers and rjs, but building a nice graphical interface was still a lot of work.

When building graphical interfaces the first thing you need to have is an idea what the user is supposed to do on the interface.

Second, you need to think about the layout and what elements you want to put on the interface (separated in pages or states). In this step, you as an interface developer have so much freedom that you can end up weeks and months moving around elements and pixels on your interface seeking for the best usability and look. Ext JS doesn't really limit your freedom, but it gives you very very helpful guidelines for building nice interfaces, since it has ready-to-use widgets such as grids, panels, buttons, menus and toolbars which can be configured via options to your need. Ext JS is for the client-side of web applications as Ruby on Rails is for the server-side of web applications.

Third, you have to design the interface elements on yourself or by a designer. Ext JS includes nice GUI elements or so-called widgets out-of-the-box. Some may argue the Ext JS theme is very "Windows Vista"-like, but it's gives you at least a beautiful interface right at the beginning which can be customized by you without limits.

Forth, you need to build the interface. Building the interface can be tricky, especially today when everybody is expecting some fancy AJAX, which can be very useful in a lot of cases. Now the fight with Javascript, CSS, ERB, controller actions and cross-browser compatibility is starting. The Rails built-in javascript libraries Prototype and script.aculo.us or additional template engines like Haml or Markaby can help you with this step, but it's still not less complicated.
With Ext JS, you have everything in one library which has a very clean API and documentation. You actually have to use actually HTML or Haml very few times, since you can build the whole interface by Ext JS widgets and layouts which are configured by options in the JSON-Format.

Therefore, the best solution and more and less silver bullet for building web-based user interfaces is for me Ext JS.

I'm starting this blog to document some hints and tipps on using Ext JS together with Ruby on Rails. But this blog is not supposed to be an one-way street. Through this blog I hope to meet other Rails developers that use Ext JS and have their own solutions and tipps. I welcome everybody to use the comments feature or send me an email to s dot hiller at caprireleases dot com.