Building a Rating Widget with Ext Core 3.0 Final and Google CDN
June 10, 2009 by Tommy Maintz
We are very proud to announce the final release of Ext Core under the MIT license. Your feedback was invaluable. Thank you for all the bugs reported and test cases created. For those of you who are new to Ext Core, we suggest you read the previous blog post about the all the features and examples that we released as part of the beta. You can find a list of changes and fixes we made for the final here.
For this post we will leverage the power of Ext by creating and dissecting a useful star rating example. We hope to share some of the general best practices behind creating unobtrusive, reusable code with Ext Core to liven up your pages.
Making a Splash
Including Ext Core on your site is easier than ever. We are honored to share with the community that Ext Core is now available via the Google AJAX Library API. Many thanks to Ben Lisbakken at Google for working with us to make this a reality.//any of these will work ;) <script type="text/javascript" src=".... http://ajax.googleapis.com/ajax/libs/ext-core/3.0/ext-core.js http://ajax.googleapis.com/ajax/libs/ext-core/3/ext-core.js http://ajax.googleapis.com/ajax/libs/ext-core/3.0/ext-core-debug.js http://ajax.googleapis.com/ajax/libs/ext-core/3/ext-core-debug.js
google.load('ext-core', '3'); google.load('ext-core', '3', {uncompressed : true});
Getting Started
Ext Core is a perfect fit for adding behavior to existing HTML. When designing a widget, having a markup structure that provides graceful degradation is an added plus. For this example, we will be using radio buttons. We can "group" the elements to specify which radio buttons are part of the control. It could look something like the following:<div id="rating1"> <input type="radio" name="rating1" value="1" title="Very poor"> <input type="radio" name="rating1" value="2" title="Not that bad"> <input type="radio" name="rating1" value="3" title="Average"> <input type="radio" name="rating1" value="4" title="Good"> <input type="radio" name="rating1" value="5" title="Perfect"> </div>
The API
One of the most important aspects of building reusable code is providing your developers a powerful API. Our aim here is to allow developers to progressively enhance and convert the markup into a star rating with a simple API. In this case we will need the element that wraps around the radio controls, and some optional configuration to customize the behavior of the widget. Following the Ext tradition we will provide these configuration options in the form of an object literal. A possible API for our widget could look like this://Keep it simple new Ext.ux.Rating('rating1', { showTitles: true });
Ext.util.Observable
So now that we know how we want to use our component, lets go ahead and actually look at some details on how to write it! In our previous post we mentioned that Ext Core allows you to write neatly structured object-oriented code. Whenever you want to create a piece of functionality, you should try to bundle it into a separate class. In most cases you will need to be able to listen for events on instances of your class. Ext provides a power class, the Ext.util.Observable class, to springboard your development. This is the same class that almost all classes in Ext JS extend from! Our basic shell for our rating plugin could look something like this:Ext.ns('Ext.ux'); Ext.ux.Rating = Ext.extend(Ext.util.Observable, { // Configuration default options showTitles: true, // Our class constructor constructor : function(element, config) { Ext.apply(this, config); Ext.ux.Rating.superclass.constructor.call(this); this.addEvents( 'change'); this.el = Ext.get(element); this.init() } });
Reaching the stars
It is time to think about the things we need to get our widget working. First we want to replace the radio buttons with our stars, we will need to store the values and titles for each star, we want to create a hidden input to put the current value in and finally we need to set up event listeners to listen for mouse hovers and clicks.init : function() { var me = this; // Some arrays we are going to store data in this.values = []; this.titles = []; this.stars = []; // We create a container to put all our stars into this.container = this.el.createChild({ cls: 'ux-rating-container ux-rating-clearfix' }); // We use DomQuery to select the radio buttons // Then we can loop over the CompositeElement using each this.radioBoxes = this.el.select('input[type=radio]'); this.radioBoxes.each(this.initStar, this); // We use DomHelper to create our hidden input this.input = this.el.createChild({ tag: 'input', type: 'hidden', name: this.name, value: this.values[this.defaultSelected] }); // Lets remove all the radio buttons from the DOM this.radioBoxes.remove(); if(this.disabled) { this.disable(); } else { // Enable will set up our event listeners this.enable(); } }
Creating Stars - using DomHelper and accessing the DOM from Ext Element
initStar : function(item, all, i) { // We use the name and disabled attributes of the first radio button if(i == 0) { this.name = item.dom.name; this.disabled = item.dom.disabled; } // Saving the value and title for this star this.values[i] = item.dom.value; this.titles[i] = item.dom.title; // Now actually create the star! var star = this.container.createChild({ cls: 'ux-rating-star' }); // Save the reference to this star so we can easily access it later this.stars.push(star.dom); },
Enable and Select Stars - listening for events, using the target of an event and firing custom events
enable : function() { // ... some code missing here ... // We will be using the technique of event delegation by listening // for bubbled up events on the container this.container.on({ click: this.onStarClick, mouseover: this.onStarOver, mouseout: this.onStarOut, scope: this, delegate: 'div.ux-rating-star' }); }, onStarClick : function(ev, t) { if(!this.disabled) { this.select(this.stars.indexOf(t)); } }, select : function(index) { // ... some code missing here ... else if(index !== this.selected) { // Update some properties this.selected = index; this.value = this.values[index]; this.title = this.titles[index]; // Set the value of our hidden input so the rating can be submitted this.input.dom.value = this.value; // the fillTo() method will fill the stars up until the selected one this.fillTo(index, false); // Lets also not forget to fire our custom event! this.fireEvent('change', this, this.values[index], this.stars[index]); }
Filler Up - dom manipulation (adding classes)
fillTo : function(index) { var cls = 'ux-rating-star-on'; // We add a css class to each star up until the selected one Ext.each(this.stars.slice(0, index+1), function() { Ext.fly(this).addClass(cls); }); // And then remove the same class from all the stars after this one Ext.each(this.stars.slice(index), function() { Ext.fly(this).removeClass(cls); }); }
We won't discuss all the details since most of it is pretty straightforward, but the final product should give you a general idea of how to use the basic functionality available in Ext Core to tie together all the missing pieces.
Wrapping it up
In this example we used the following cross-browser compatible functionality available in Ext core:- Classical Inheritance Class System
- Observable Class
- DomQuery
- DOM manipulation and traversal
- Event handling
- Markup generation
Ext Core makes it fun to write code, and helps you create clean, well-structured classes using a set of cross-browser abstractions on the existing browser API's. For those of you who want to use it or are just interested in seeing the completed work, we have included a version of the widget in the Ext Core Final build. You can see the working widget embedded in the post below:
The example page illustrating this widget can be found here.


Posted on June 11th, 2009 at 1:03 am
Very nice and exciting.
Posted on June 11th, 2009 at 2:16 am
Air API document will be nice.
Posted on June 11th, 2009 at 2:50 am
Great article Tommy!
Thanks Ben Lisbakken for adding ext-core to the Google Ajax Libraries API.
Issue 233 can be closed: http://code.google.com/p/google-ajax-apis/issues/detail?id=233
Posted on June 11th, 2009 at 3:40 am
Great work! Glad to see Ext Core join in ajax libs family of Google CDN.
Posted on June 11th, 2009 at 5:42 am
It’s nice
Posted on June 11th, 2009 at 5:56 am
Thank you Tommy!
Nice Example and gratulation to the stable version.
Posted on June 11th, 2009 at 6:31 am
Cool… adding it to extjs.tv build two now… nice.. really nice.
Posted on June 11th, 2009 at 7:22 am
Yes! What great news – ExtJS Core rocks!
Posted on June 11th, 2009 at 7:26 am
Awesome post Tommy.
Posted on June 11th, 2009 at 8:45 am
Looks good but does not seem to work on chrome
Posted on June 11th, 2009 at 8:57 am
@Ian
I tested it on Chrome v2.0.181.1, works pretty good!
Posted on June 11th, 2009 at 9:53 am
I don’t see the details related to Google CDN in this blog post.
Was it forgotten or do I have to understand what the title mean directly?
Boub
Posted on June 11th, 2009 at 10:37 am
@Boubalou – read the part in the beginning of the post – Making a Splash.
Awesome work Tommy. Very impressive!
Posted on June 11th, 2009 at 10:51 am
Ext rocks as always. Now, it’s part of google API infrastructure, making it even more awesome.
However, just any good widgets, DOM manipulation is only one part. One must also master CSS concepts thoroughly before creating super slick widgets.
Posted on June 11th, 2009 at 11:13 am
Thanks for the great response guys! Turns out Safari/Chrome have an opacity 1 issue, so changed the reset el to get opacity 0.99 which fixed it in both browsers.
Posted on June 11th, 2009 at 12:51 pm
[...] Ext JS公式ブログより。 [...]
Posted on June 11th, 2009 at 4:01 pm
Was the rating example inspired by the GQuery GWT demo at Google IO? or is there a general example that inspired both?
Related, I was actually wondering if Ext GWT contained analogous DOM manipulation code present in ext-core (making it a competitor with GQuery mentioned above) or if it was just the widgets.
Posted on June 11th, 2009 at 7:32 pm
功能很好,很高兴看见Ext Core 加入了Google CDN
Posted on June 11th, 2009 at 8:46 pm
很不错,接下来我会仔细看看 ext.3 带来的更大便利和性能。
Posted on June 11th, 2009 at 10:07 pm
太强了!
Posted on June 13th, 2009 at 7:57 pm
The Tabs demo example is broken in FireFox. The tab contents properly switch, but the tabs-button-panel does not. When you click on a tab, the third tab gets the tab-show class no matter which tab you click on. I’m on FF3 on a Mac, but I’ve also seen this happen on FF on a PC.
It worked O.K in the beta.
Posted on June 14th, 2009 at 5:14 am
@tester – on chrome 2.0.172.31 you do not seem to see the reset button but does show on IE & firefox
Posted on June 14th, 2009 at 11:37 pm
This is why open source is so awesome…
Posted on June 15th, 2009 at 1:01 am
[...] Thanks to all for the requests to add ext-core to our Libraries API, and big thanks to Ext JS for providing their library so openly! For more information, head over to their blog post. [...]
Posted on June 18th, 2009 at 12:26 am
很好!http://www.myext.cn
Posted on June 22nd, 2009 at 11:30 am
hello
Posted on June 27th, 2009 at 5:38 am
kabin üretiminde üreticiyiz.
Posted on July 7th, 2009 at 3:17 am
It looks great.thanks
Posted on July 8th, 2009 at 1:28 pm
Thanks for this tut, it is really good indeed!
Posted on July 9th, 2009 at 1:17 am
Good!!
Posted on July 9th, 2009 at 1:19 am
很好!!!
Posted on July 9th, 2009 at 3:11 pm
Great little widget guys, can’t wait to see the final version!
Posted on July 13th, 2009 at 12:23 am
I was swindled on craigslist by some jerkwad using a wireless number. Jerkwad was shocked when I got his addy info and paid a visit lol!
Phone Search
Posted on July 14th, 2009 at 4:00 am
구글에서 땡겨쓰게끔 지원?
Posted on July 19th, 2009 at 11:22 am
Widget连“渐进增强”的概念都涉及了,例子复杂点些,anyway,谢谢~这是专业的widget,谢谢提供!
Posted on July 21st, 2009 at 10:46 am
http://extjs.com/blog/2008/11/24/extplayer-air-and-ext/#comment-71248
Posted on July 21st, 2009 at 10:58 am
I am grateful to you for this great content.
aöf
Posted on September 11th, 2009 at 6:21 am
amazing
http://www.feneronline.net/video/
Posted on September 14th, 2009 at 6:51 am
Awesome. you did Great!
Posted on September 18th, 2009 at 3:25 am
I’m found some bug. There should be some check in “enable” function, because if function “enable” calls more then one time the code “this.container.on({click: this.onStarClick,…” execute more than one time too. So if user click on star, script has multiply calls of the click event. I resolve this problem by the use of “if(!this.disabled){return;}”, see code:
enable : function() {
if(!this.disabled){return;}
……
P.S. thank you for rating code
Posted on October 7th, 2009 at 2:52 am
hi,
so to make out the rating system i jus need the codes above and that’s all??
Posted on November 11th, 2009 at 3:10 pm
Thanks a lot!!
Posted on November 15th, 2009 at 7:35 pm
looks good, need to try it with Chrome.
Posted on November 21st, 2009 at 7:31 pm
Tried with Chrome – works good.