Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
TableHelper demo page
[go: Go Back, main page]

TableHelper Demonstration page

All tables below are displayed with the table helper. I'm regularly working on this page, so if you come back and get an error, don't panic, it's just that I'm enhancing the example. Comments and suggestions are welcome at rb at raphinou dot com or on the #rubyonrails IRC channel.

The example data array we use is defined as


  	simple_array = [ [ 1, "Ruby", "http://www.ruby-lang.org"],
			  [ 2, "Python", "http://www.python.org"],
			  [ 3, "Java", "http://www.java.sun.com"],
			  [ 4, "Perl", "http://www.perl.org"],
			  [ 5, "lua", "http://www.lua.org"]
			]

Simple table

We simply put the array in the "array" variable of a hash we pass it to the table method:

	#controller
	@e1 = { "array" => simple_array }

	#view
	<%= table(@e1, "display" => :default) %>

This generates this table:

1 Ruby http://www.ruby-lang.org
2 Python http://www.python.org
3 Java http://www.java.sun.com
4 Perl http://www.perl.org
5 lua http://www.lua.org

with this HTML code

Passing parameters

We can pass parameters to the helper thanks to the TableFields class. We can for example specify the id of the table:

	#controller
	fields = TableFields.new(:table_id => "example2")
	@e2 = { "array" => simple_array , "fields" => fields}

	#view
	<%= table(@e2, "display" => :default) %%>

with of course the same visual result:

1 Ruby http://www.ruby-lang.org
2 Python http://www.python.org
3 Java http://www.java.sun.com
4 Perl http://www.perl.org
5 lua http://www.lua.org

Column headers

Building on the previous examples, we will no add column headers.



	#controller
	#We reuse the TableFields instance, but set a new id
	fields3 =fields.dup
	fields3.table_id = "example3"
	
	#The table fields have to be in an array
	field_names = [ "id", "name", "homepage"]
	
	#and we pass it to the TableFields instance
	fields3.field_names = field_names

	@e3 = { "array" => simple_array, "fields" => fields3}

	#view 
	<%= table(@e3, "display" => :default) %%>


id name homepage
1 Ruby http://www.ruby-lang.org
2 Python http://www.python.org
3 Java http://www.java.sun.com
4 Perl http://www.perl.org
5 lua http://www.lua.org

We would have done this if we passed the field_names to the constructor of TableFields. The accessor has the same name as the symbol used in the constructor.



	#controller
	#The table fields have to be in an array
	field_names = [ "id", "name", "homepage"]

	#and we pass it to the TableFields constructor
	fields_ex4 = TableFields.new(:table_id = "example3", :field_names => field_names)

	@e4 = { "array" => simple_array, "fields" => fields_ex4}

	#view 
	<%= table(@e4, "display" => :default) %%>


id name homepage
1 Ruby http://www.ruby-lang.org
2 Python http://www.python.org
3 Java http://www.java.sun.com
4 Perl http://www.perl.org
5 lua http://www.lua.org

Hiding columns

Don't you think the id coumn should not be displayed? You can list the names of the columns to not be displayed in the hidden_fields Array:



	#controller
	#We reuse the TableFields instance, but set a new id
	fields5 = fields_ex4.dup
	fields5.table_id = "example5"
	
	#The table fields have to be in an array
	hidden_fields = [ "id"]
	
	#and we pass it to the TableFields instance
	fields5.hidden_fields = hidden_fields

	@e5 = { "array" => simple_array, "fields" => fields5}

	#view 
	<%= table(@e5, "display" => :default) %%>


name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

You may wonder why include the column in the data array if it is not going to be displayed. The answer is simple: you can still use the values in this column to build links for example.

Displaying links

We can use a LinkSpec instance to define a link, and this link will be generated in the fields we define with the TableFields instance. Let's start with a static link, i.e. a link to a fixed destination: http://www.rubyonrails.org. The definition of the link is done like this:


	#define the link
	ror_link_spec = LinkSpec.new
	ror_link_spec.href = "http://www.rubyonrails.org"
	
	#and add it to the table definition
	fields_ex6 = TableFields.new(:table_id => "example6", :field_names => field_names)
	fields_ex6.add_link("name", ror_link_spec)
	fields.hidden_fields = ["id"]
	@e6 = { "array" => simple_array, "fields" => fields_ex6}

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

Now, the previous example isn't that useful... Wouldn't it be great to link to the homepage of the language? That's possible! Here's the result:

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

To achieve that result, the table helper calls the method field_value which has 2 parameters: the first one is the name of the column from which to take the value; and the second is the line on which the table helper is working at the time of the call. The internal name of the line on which the helper is working is line. Here's the code needed to generate the table above:


	#define the link
	homepage_link_spec = LinkSpec.new
	#set the href value to call the field_value method, 
	#the second paramter being the current line
	homepage_link_spec.href = %q(field_value("homepage", line))
	#and set href to be eval'd in the context of the line the helper is working on
	homepage_link_spec.eval_href=true
	
	#The rest is like the previous examples:
	fields_ex7 = TableFields.new(:table_id => "example7", :field_names => field_names)
	fields_ex7.add_link("name", homepage_link_spec)
	fields_ex7.hidden_fields = ["id"]
	@e7 = { "array" => simple_array, "fields" => fields_ex7}

The table helper and Ruby on Rails

The table helper being a Ruby on Rail component, it also makes it easy to generate links to Runy on Rails controllers. I defined another controller, language_details which displays details of the language whose id is passed in the URL. We can easily generate a link to that controller, passing the id of the language. Here's the code:


	#define the links
	#homepage
	homepage_link_spec = LinkSpec.new
	homepage_link_spec.href = %q(field_value("homepage", line))
	homepage_link_spec.eval_href=true
	
	#link to the details controller
	details_link_spec = LinkSpec.new
	
	#set rails controller and action we link to
	details_link_spec.controller = "language_details"
	details_link_spec.action = "display"
	
	#params are parameters passed in the url, available in @params in the controller
	details_link_spec.params = { "id" => %q(field_value("id", line))}
	
	#Say that the parameter id has to be evaled in the context of the current line in the table helper
	details_link_spec.set_param_eval("id")
	
	#rails_parameters are any rails parameters passed to url_for
	details_link_spec.rails_parameters = { :controller_prefix => "rails"}
	
	#we need to pass a reference to the current controller to have url_for usable in the helper
	fields_ex8 = TableFields.new(:table_id => "example8", :field_names => field_names, :controller => self)
	
	#add the two link specs, each for one field.
	fields_ex8.add_link("homepage", homepage_link_spec)
	fields_ex8.add_link("name",details_link_spec)
	
	#Hide the id field
	fields_ex8.hidden_fields = ["id"]
	
	@e8 = { "array" => simple_array, "fields" => fields_ex8}	

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

Sorting

It is possible to sort the data displayed. To that end, the header of the column by which value we want to order the display becomes a link. By clicking that link you order the data displayed by the values in that column. Here's an example to sort our data by the name column. I set 2 tables side by side, to show you can reorder one table without loosing the order of the other tables (example9 is left, example10 is right).

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org
name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

This is achieved with this code (we reuse the links defined above):


	#we need to pass a reference to the current controller to have url_for usable in the helper
	#we tell the helper that the column "name" should be a criteria for sorting
	#the headers_rails_parameters is necessary in this case because I run this demo as a servlet 
	#behind an apache proxy forwarding all request to /rails to the servlet. 
	#In normal operations this should not be necessary. It shows however how you can pass
	# any url_for parameters 
	fields_ex9 = TableFields.new(:table_id => "example9", :field_names => field_names,  \
	   :controller => self,  :headers_links => ["name"],  :headers_rails_parameters =>{:controller_prefix => "rails" }  )
	#by default, all params are put in the generated links. This is useful to keep the sort orders of
	# other tables on the same page eg.
	#In our case, it is not necessary to pass it over to the next controller.
	details_link_spec.set_rails_parameter(:overwrite_params, {"sort_example9" => nil}  )
	
	fields_ex9.add_link("homepage", homepage_link_spec)
	fields_ex9.add_link("name",details_link_spec)
	fields_ex9.hidden_fields = ["id"]
	
	#we tell the helper to manage the sorting. If we want to manage it ourselves, for example in 
	#the SQL queries we issue, we can 
	# leave this to false (which is the default value)
	fields_ex9.manage_sorting = true
	@e9 = { "array" => simple_array, "fields" => fields_ex9}	
	
	fields_ex10=fields_ex9.dup
	fields_ex10.table_id="example10"
	fields_ex10.headers_links = ["name","homepage"]
	@e10 = { "array" => simple_array, "fields" => fields_ex10}	
	

Styling with CSS

It is possible to set header, row and field CSS classes, possibly based on the data values displayed. Let's start with the headers. I want the color header to be yellow for the name column and green for the homepage column. I first define the corresponding classes in my stylesheet:


.yellow {
	background-color : yellow;
}
.lightgreen {
	background-color : lightgreen;
}

To set the class of an element in the table, we use a class builder, a Proc object that will be called by the table helper to determine what is the class of the element. The header_class_builder takes 2 arguments that correspond to the TableFields instance, and the field name corresponding to the header the helper works on. We thus have to define a Proc object that takes 2 arguments:

	header11_builder = lambda { |fields,field_name|
		css_class=""
		if field_name =="name"
			css_class = "yellow"
		elsif field_name =="homepage"
			css_class = "lightgreen"
		end
		css_class
	}
	#and pass it to the TableFields instance
	fields_ex11.header_class_builder = header11_builder

Here's the result we get

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

We can use that technique to give a special css class to the header of the column we use to sort. In this example I give the yellow class to the header of the column used to sort data (in real life it would rather be sort_active or something like that I guess):


	fields_ex12=fields_ex11.dup
	fields_ex12.table_id="example12"
	header12_builder = lambda { |fields,field_name|
		css_class=""
		if @params["sort_#{fields.table_id}"] and @params["sort_#{fields.table_id}"]== field_name
			css_class = "yellow"
		end
		css_class
	}
	fields_ex12.header_class_builder = header12_builder
	@e12 = { "array" => simple_array, "fields" => fields_ex12}	

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

In the same way, we can assign css class to rows. I want even rows to have a white background, odd rows a yellow background. HEre's the code


	row13_builder = lambda { |fields,line, line_number|
		css_class=""
		if line_number.remainder(2)!=0
			css_class = "yellow"
		end
		css_class
	}
	fields_ex13=fields_ex12.dup
	fields_ex13.table_id="example13"
	fields_ex13.row_class_builder = row13_builder
	@e13 = { "array" => simple_array, "fields" => fields_ex13}	

and here's the result (row numbers start at 0):

name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

Setting row ids

You can in the same way set row ids. The reason I implemented it is that I had a long table displayed and wanted to go back to that row when I had triggered an action on it. Here's how you do it:


	rowid14_builder = lambda { |fields,line|
		"#{fields.table_id}_#{line[0]}"
	}
	fields_ex14=fields_ex12.dup
	fields_ex14.table_id="example14"
	fields_ex14.row_id_builder = rowid14_builder
	@e14 = { "array" => simple_array, "fields" => fields_ex14}	

And here's the result. I added the links manually.

row with id table14_1--row with id table14_3--row with id table14_5
name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org
Java http://www.java.sun.com
Perl http://www.perl.org
lua http://www.lua.org

Modifying fields before display

You can also modify the value of the fields before they get displayed. This can be used to turn a value of 1 or 0 in true or false, or for translation in different languages. In this example I will display all language names in uppercase. First the code:


	fields_manipulator15 = lambda { |value|
		return value.upcase
	}
	fields_ex15=fields_ex12.dup
	fields_ex15.table_id="example15"
	fields_ex15.manipulated_fields = [ { "field_name" => "name", "manipulation" => fields_manipulator15 }]
	@e15 = { "array" => simple_array, "fields" => fields_ex15}	

then the result:

name homepage
RUBY http://www.ruby-lang.org
PYTHON http://www.python.org
JAVA http://www.java.sun.com
PERL http://www.perl.org
LUA http://www.lua.org

Navigation links for long tables

If you have long tables to display, it's often convenient to display them on separate pages with navigation links (just like Google returns their search results). It's very easy to achieve that result with the table helper. The only implementation for now requires you to pass the whole array to display, and the helper manages itself the display. That means you cannot, for the moment, limit a SQL query to just resturn the rows you want to display (like Mysql and Postgresl accept the LIMIT # OFFSET # directives in a query). That's a limitation that will be lifted as soon as the need shows up, which should be really soon actually.

But let's go on with the example. I configure the table to only display 2 rows per page. That way, 3 navigation links will be displayed. Each link is in a span of class table_navigation_link for links to other pages than the one currently displayed, and of class table_active_navigation_link for the (inactive) link of the current page. Here's the code:


	fields_ex16=fields_ex12.dup
	fields_ex16.table_id="example16"
	#activate the display in several pages
	fields_ex16.manage_page_display=true
	#set the number of rows paer page
	fields_ex16.rows_per_page=2
	
	@e16 = { "array" => simple_array, "fields" => fields_ex16}	

and here's the result. Note that you can still order the rows, and that you stay on the page you were on even if you change the sort order. You can also change the number of rows per page with parameters passed in the URL

3 rows per page
5 rows per page
name homepage
Ruby http://www.ruby-lang.org
Python http://www.python.org