a framework for data visualization in a browser-based ...henz/students/tungleh.pdf · mentioned...
TRANSCRIPT
Honours Year Project Report
A Framework for Data Visualization in a Browser-based
Application Platform
By
Tang Tung Leh
Department of Computer Science
School of Computing
National University of Singapore
2007/2008
i
Title Page
Honours Year Project Report
A Framework for Data Visualization in a Browser-based
Application Platform
By
Tang Tung Leh
Department of Computer Science
School of Computing
National University of Singapore
2007/2008
Project No: H041220
Advisor: Dr. Martin Henz
Deliverables:
Report: 1 Volume
Program: 1 CD-ROM
ii
Abstract TiddlyCard is a client-centered browser-based platform for integrating web services.
Built upon established standards such as HTML, XML, JavaScript and CSS, it leverages
on AJAX technologies to provide an environment in which websites and web
applications can be developed and integrated. This project helps to develop a framework
that will enable application developers to display their data with a graphical user interface,
for example, in a form-like manner. The framework should allow data binding from the
user interface to the underlying application, such that any changes on the data on the user
interface should reflect the changes in the application immediately, if not, the minimum
required time for the application to complete the changes.
This framework uses the modified Model-View-Controller (MVC) framework, in which
there is no direct communication between the Model and View, but all communications
passed through the Controller. The Model represents the data of the underlying
application, the View is the graphical user interface and Controller is the tunnel
connecting Model and View, such that any changes in either side will be reflected in the
other side. This forms the data binding mechanism. A single model can be presented by
more than one views, and vice versa.
Subject Descriptors:
D.2.2 Design Tools and Techniques
D.2.13 Reusable Software
D.3.3 Language Constructs and Features
H.5.2 User Interfaces
Keywords:
Model-View-Controller, GUI, Web Toolkit, Forms, Data Binding
Implementation Software:
JavaScript, HTML, DOM, web browsers
iii
Acknowledgement I would like to thank my project supervisor Dr. Martin Henz for his understanding,
patience, guidance and support throughout the entire period of the project. Also, not to
forget Mr. Michael Clark, TiddlyCard lead architect, for initiating the idea of visualizing
data using forms and leads me to look deeper into area required for data binding.
I would like to give thanks to my previous supervisor Dr. Hugh Anderson for his advice
on exploring into data binding in XForms, Mr. Lin Liansen for his support, guidance and
help on HTML DOM, and the TiddlyCard developer community (Mr. Daryl Seah Boon
Leng, Mr. Lek Hsiang Hui, Mr. Zhou Lin and Mr. Tran Khoa Nguyen) for providing the
backend support and infrastructure of TiddlyCard. I am grateful that we all supporting
one another in this community.
I would like to give thanks to my family members, especially my twin brother, Mr. Tang
Tung Ngie, who is completing his Honours Year Project with me, for his ultimate support
and prayers throughout the entire period of the project.
Finally, I would like to give all glory unto my God, whom without I will not be able to
complete this project.
iv
List of Figures Figure 1: Form with batch data binding (BlogSpot Settings page) ...................................2
Figure 2: Example of using Qooxdoo module system......................................................4
Figure 3: Example of UI by Naked Objects ....................................................................9
Figure 4: Example of Naked Objects code..................................................................... 10
Figure 5: A Common MVC Implementation ................................................................. 11
Figure 6: Java Swing Modified MVC Implementation................................................... 11
Figure 7: Another type of modified MVC implementation............................................. 12
Figure 8: Views in views with different controllers ....................................................... 17
Figure 9: Default form generated for Person class ......................................................... 18
Figure 10: Form generated for Author class................................................................... 19
Figure 11: Using Ext JS GUI Library ............................................................................ 22
Figure 12: Changing "Tung Leh" to "Kee Sing" ............................................................ 23
Figure 13: Leaving the Given Name textbox ................................................................. 23
Figure 14: View_1 is built using YUI library................................................................. 27
Figure 15: View1 filled in and corresponding console output ........................................ 28
Figure 16: Views of two models, i.e. Colour manager and Perspective manager ............ 29
Figure 17: Relationship diagram of MVC Implementation ............................................ 34
Figure 18: Summary of actions from Model to Controller to View ................................ 36
Figure 19: Summary of actions performed when a valid update is made at one of the
views............................................................................................................................. 37
Figure 20: Summary of actions performed when an invalid update is made at one of the
views............................................................................................................................. 37
Figure 21: Summary of actions performed for a valid change with many-models-many-
views feature................................................................................................................. 38
Figure 22: A simple form .............................................................................................. 39
Figure 23: Screenshot of Glade from http://glade.gnome.org/screenshots.html .............. 40
v
Table of Contents Title Page......................................................................................................................... i
Abstract ..........................................................................................................................ii
Acknowledgement .........................................................................................................iii
Table of Contents............................................................................................................ v
1 Introduction.................................................................................................................. 1
1.1 TiddlyCard ............................................................................................................1
1.2 Framework for Data Visualization .........................................................................2
1.3 TiddlyCard Module System...................................................................................3
2 Explorations................................................................................................................. 7
2.1 Existing GUI Libraries ..........................................................................................7
2.1.1 Yahoo! User Interface (YUI) ..........................................................................7
2.1.2 Qooxdoo.........................................................................................................7
2.1.3 Dojo................................................................................................................8
2.1.4 Ext JS .............................................................................................................8
2.2 Naked Objects .......................................................................................................9
2.3 MVC Framework ................................................................................................ 10
2.3.1 Java Swing.................................................................................................... 12
3 Design Principles ....................................................................................................... 14
3.1 Convention over Configuration............................................................................ 14
3.2 Separation of concerns......................................................................................... 15
3.3 Reuse................................................................................................................... 16
3.4 Compositionality ................................................................................................. 16
4 Features...................................................................................................................... 18
4.1 Default Form Generation ..................................................................................... 18
4.2 Immediate Data Binding...................................................................................... 21
4.3 Many-Models-Many-Views................................................................................. 25
5 Design and Implementation........................................................................................ 30
5.1 Naïve Design and Implementation ....................................................................... 30
5.1.1 Design .......................................................................................................... 30
5.1.2 Implementation............................................................................................. 31
vi
5.2 MVC Design and Implementation ....................................................................... 33
5.2.1 Design .......................................................................................................... 33
5.2.2 Implementation............................................................................................. 35
6 Recommendations for Future Work............................................................................ 39
6.1 Tools for Building View...................................................................................... 39
6.1.1 Default View for MVC Implementation........................................................ 39
6.1.2 A Form Builder............................................................................................. 39
6.1.3 Import and Export of View into JSON .......................................................... 40
7 Lessons Learnt ........................................................................................................... 42
7.1 Collaboration....................................................................................................... 42
7.2 Programming in JavaScript, HTML DOM and Events ......................................... 42
8 Conclusions................................................................................................................ 44
References .................................................................................................................... 45
Appendix A – Framework API...................................................................................... 48
A.1 FormObject ........................................................................................................ 48
A.2 PropertyChangeEvent ......................................................................................... 49
A.3 IPropertyChangeListener .................................................................................... 50
A.4 PropertyChangeSupport...................................................................................... 50
A.5 AbstractModel .................................................................................................... 51
A.6 AbstractController .............................................................................................. 51
A.7 AbstractControllerM........................................................................................... 53
A.8 AbstractView...................................................................................................... 54
Appendix B – TiddlyCard Module System Features ...................................................... 55
Property, Field, Methods and Access Modifiers......................................................... 55
Implementing Interfaces ............................................................................................ 57
Extending Base Class ................................................................................................ 58
Enumeration.............................................................................................................. 59
Appendix C – A Complete Example.............................................................................. 63
C.1 Model ................................................................................................................. 63
C.2 Controller ........................................................................................................... 64
C.3 View................................................................................................................... 65
1
1 Introduction
1.1 TiddlyCard
TiddlyCard is a client-centered browser-based platform for integrating web services.
Built upon established standards such as HTML, XML, JavaScript and CSS, it leverages
on AJAX and COMET technologies to provide an environment in which websites and
web applications can be developed and integrated. It consists of a client side operating
system that boots within a web-browser and an ultra-thin server side that enables web-
based peer-to-peer computing.
Inspired by both HyperCard (HyperCard, 2008) and the increasingly popular TiddlyWiki
(Ruston, 2007), which allows anyone to create self personal hypertext documents that can
be posted to a Web Server, sent by email or kept on a USB Thumb drive (Ruston, 2007),
TiddlyCard creates a browser-based environment for applications that are client centric,
server supported and platform independent.
TiddlyCard does not depend on any connections to a server but it can automatically
synchronize with the server if connectivity is found. Thus it remains functional with or
without server. Also, because TiddlyCard is a JavaScript or browser-based framework, it
will be platform independent, accessible through desktop computers, mobile phones and
other browser-enabled devices.
When more applications are developed on TiddlyCard, it is necessary to display out the
data or results from the underlying applications. Graphic Component Framework has a
major role for its support on displaying the data or result from any applications running
on top of TiddlyCard and integrating multimedia applications with TiddlyCard. This
project comes under the Graphic Component Framework of TiddlyCard that provides an
easy way to create Graphic User Interface (GUI) for displaying data or result of any
TiddlyCard applications.
2
1.2 Framework for Data Visualization
TiddlyCard is the browser-based platform of this project. Data binding between the data
from applications and the GUI forms the core of this framework, because any changes to
the GUI should be reflected onto an application (from this point, any “application”
mentioned should be treated as application running on top of TiddlyCard). The
application will thus make the adjustment based on the changes. A simple analogy will be
changing the background color of an application. Imagine a GUI contains a color picker
for the user to choose any color from. The user picked one and the application
immediately reflects the background color he picked. This is an example of an immediate
data binding.
Another type of data binding is batch data binding, where a user clicked a “save” or
“submit” button after he/she completed a form. This is usually used in a normal form,
such as acquiring a user’s detail or a configuration page (See Figure 1).
Figure 1: Form with batch data binding (BlogSpot Settings page)
3
This project has two types of implementations that fit for each way of data binding: a
naïve implementation for batch data binding and a Model-View-Controller (MVC)
implementation for immediate data binding. For both implementations, they require a
TiddlyCard object to retrieve data from (also known as (a.k.a.) model).
1.3 TiddlyCard Module System
Since JavaScript 1.7 does not have a native module system, the question arises on how to
design, implement and document composed units of JavaScript code in TiddlyCard. A
module in native JavaScript is done this way:
if (!tc) tc = {};
if (!tc.major) tc.major = {};
if (!tc.major.minor) tc.major.minor = {};
if (!tc.major.minor.tiny) tc.major.minor.tiny = {};
// constructor
tc.major.minor.tiny.MyModule = function() {
…
this._init(arg);
}
tc.major.minor.tiny.MyModule.prototype._init =
function(arg) {
…this…
tc.major.minor.tiny.MyModule.otherMethod(args);
tc.major.other.OtherModule.theirMethod(argg);
}
tc.major.minor.tiny.MyModule.prototype.otherMethod =
function(arg) {…};
// static function
tc.major.other.OtherModule.theirMethod = function(arg)
{…}
4
For a developer who has been programming with object-oriented style, he/she will have
difficulties in understanding these native JavaScript codes. Fortunately, there are existing
JavaScript libraries that provide syntactic sugar for writing a module system in JavaScript.
One such library is Qooxdoo (Qooxdoo Classes, 2008) (see Figure 2).
Figure 2: Example of using Qooxdoo module system
Qooxdoo has a function qx.Class.define to replace the native JavaScript codes:
A TiddlyCard developer, Mr. Daryl Seah Boon Leng, felt that it is necessary to have an
API support for developers to easily construct and document JavaScript codes in an
object-oriented style. He then developed TiddlyCard’s own module system, which all
source codes of this project are all written in.
Using TiddlyCard module system, the first example appears to be:
if (!qx) qx = {};
if (!qx.test) qx.test = {};
qx.test.Cat = function() {…}; // constructor
qx.test.Cat.LEGS = 4; // static attribute
qx.test.Cat.makeSound = function() {…} // static method
5
TiddlyCard module system has an object-oriented style of coding. To define a class,
developers run a JavaScript function, tc.lang.Class.define that accepts a
namespace and the name of the class to be declared as seen from the first example. This
replaces the native JavaScript codes in making a module.
Another example TiddlyCard module system that declaring static fields and methods:
tc.lang.Class.define(tc.major.minor.tiny, “MyModule”)
.CONSTRUCTOR(function() {
…this…
this.otherMethod(args);
tc.major.other.OtherModule.theirMethod(argg);
})
.METHOD(“otherMethod”, function(arg) {…})
.END_CLASS();
tc.lang.Class.defineStatic(tc.major.other, “OtherModule”)
.METHOD(“theirMethod”, function(arg) {…})
.END_CLASS();
if (!tc) tc = {};
if (!tc.major) tc.major = {};
if (!tc.major.minor) tc.major.minor = {};
if (!tc.major.minor.tiny) tc.major.minor.tiny = {};
// constructor
tc.major.minor.tiny.MyModule = function() {
…
this._init(arg);
}
Class name
Namespaces
6
Object oriented programming (OOP) features such as interface, enumerations, abstract
classes, static classes, inheritances and method overriding are all supported. (Refer to
Appendix B – TiddlyCard Module System Features for more features and examples)
In TiddlyCard module system, it supports implementation inheritance (a class can only
extend from a base class, using the keyword EXTENDS) and interface inheritance (a class
can implement any number of interfaces, using the keyword IMPLEMENTS).
There are two ways of declaring attributes for a model: properties or fields. The
advantages of declaring an attribute as property are the type checking and automatic
generation of its accessors during run-time. Suppose there is a property myProperty,
its accessors are getMyProperty (a.k.a. getter; to retrieve the data of this property)
and setMyProperty (a.k.a. setter; to replace the data of this property with a new data).
On the other hand, fields are treated similarly like any JavaScript variables which don’t
have a fixed type, and whom the class will not generate any accessors for. Thus fields can
be date, array or other JavaScript objects, whereas properties can only have a limited set
of types: string, number, boolean and TiddlyCard objects (instances of class declared
with the TiddlyCard module system).
tc.lang.Class.define(qx.test, “Cat”)
.STATIC().FIELD(“LEGS”, 4)
.STATIC().METHOD(“makeSound”, function() {…})
.END_CLASS();
7
2 Explorations
2.1 Existing GUI Libraries
Some explorations on the existing GUI libraries that leverages on JavaScript are done to
collect ideas and inspirations before the actual implementation of the project. There are
four interested GUI libraries written in JavaScript: Yahoo! User Interface (YUI),
Qooxdoo, Dojo and Ext JS.
Open source licenses that these libraries are released under are among:
Berkeley Software Distribution (BSD) (BSD License, 2008)
GNU Lesser General Public License (LGPL) (GNU LGPL, 2008)
Eclipse Public License (EPL) (Eclipse Public License, n.d.)
Academic Free License (OSI, 2006)
2.1.1 Yahoo! User Interface (YUI)
It is an open source JavaScript library that is a set of utilities and controls, written in
JavaScript, for building richly interactive web applications using techniques such as
DOM scripting, DHTML and AJAX (Yahoo! Developer Network, 2008). It is released
under a BSD license, free for all users and its current stable version is 2.5.1.
Some tests are done with YUI to test whether if it can work in TiddlyCard environment.
The tests show that with the correct import of dependencies, YUI can work well. An
application of YUI in TiddlyCard is the current OS-style background of the TiddlyCard
application. A YUI panel is built to show many-models-many-views feature in 4.3 Many-
Models-Many-Views.
2.1.2 Qooxdoo
Qooxdoo is a comprehensive and innovative Ajax application framework and open
source under an LGPL/EPL dual license (Qooxdoo Home, 2008). The current stable
8
version is 0.7.3. Qooxdoo has a build process that able to compiles its entire library with
the JavaScript code a user has written, but this build process isn’t written on JavaScript,
thus other steps are taken in order for qooxdoo to work in TiddlyCard. This library is
currently not popular among the TiddlyCard developers.
2.1.3 Dojo
It is a dual-licensed open source DHTML toolkit written in JavaScript. It is licensed
under the BSD license and Academic Free License (Dojo Toolkit, 2008). Dojo allows a
developer to easily build dynamic capabilities into web pages and any other environment
that supports JavaScript sanely. One can use the components that Dojo provides to make
his/her web sites more usable, responsive, and functional (The Dojo Toolkit, 2008).
However, it is rarely used among the TiddlyCard developers.
2.1.4 Ext JS
In the past, Ext JS extended from YUI. Now, it can stand on its own. It provides an
adapter to YUI so that users can use utilities from both Ext JS and YUI. Ext JS is released
as open source under LGPL license, but have commercial license too (Ext JS, 2006).
Ext JS provides an easy instantiation of basic form elements such as textboxes,
checkboxes and buttons. E.g. a button that has an event handler when clicked.
The constructor of Ext Button takes in a configuration object that the user can specify
which attribute to configure. Ext JS follows the convention over configuration design
principle, which implies that other attributes not defined in the configuration object
during instantiation are set as their default value by convention.
var myButton = new Ext.Button({
text: “Click Me!”,
listener: { click: onMyButtonClick }
});
9
Both constructors in Ext JS and YUI follow the convention over configuration principle.
Compared with YUI, the author recommends developers to familiar themselves with the
convention over configuration principle with Ext JS. YUI has a larger set of utilities and
controls than Ext JS, and closer to HTML DOM. This is good news for those developers
who have been writing their presentation codes in HTML.
When a developer wants to add a tree view, combo box or menu, the author would prefer
YUI to Ext JS. Ext JS has its own data structure, Ext Store, to store the content for these
sophisticated elements, but the author found it is difficult to use Ext Store. One of the
reuse of YUI libraries is to build the OS-style background of the TiddlyCard application.
2.2 Naked Objects
Although this framework targets at Java programming languages, the idea presented by
this framework is not restricted to Java only. The Naked Objects platform auto-creates an
object-oriented user interface (giving you choice of different styles) and the underlying
database (using Hibernate) (Naked Objects Group, 2008). An example of a user interface
built by naked objects is shown in Figure 3.
Figure 3: Example of UI by Naked Objects
Naked Objects framework did not use a Model-View-Controller design choice for it
combines all the three parts into one. A model, such as Claim shown in Figure 3, requires
extending from an abstract class that forms the skeleton. This skeleton could be a group
of classes that provides a default GUI display, attaches actions to the elements displayed
and recognizes prefixes of methods based on some attributes of the model.
10
The project adopted this idea from the Naked Objects framework: setting up skeletons to
provide default methods so that developers can set their models to extend from these
skeletons and able to use these methods. In naïve implementation, a skeleton class helps
to build a default form for the model. In MVC implementation, three skeletons are
providing the backend support for communication between Model and View.
Figure 4: Example of Naked Objects code
From Figure 4, the prefixes of methods based on an attribute are like a tag to tell the
Naked Objects framework what to do with the attribute. For example the method
“hideEmailAddress” hints the Naked Objects UI engine to hide the attribute “email
address” of the model.
This is another idea that is adopted in the naïve implementation. The skeleton class can
recognize two prefixes: ‘label’ and ‘view’. (Refer to 3.1 Convention over Configuration)
2.3 MVC Framework
Trygve Reenskaug, a Smalltalk developer at the Xerox Palo Alto Research Center, is the
founder of MVC framework. He found this in 1979 when he was helping to decouple
data access and business logic from the manner in which it is displayed to the user
(Eckstein, 2007).
The concept, in brief, is that the model represents the data and the methods to obtain and
change these data. It could be use to simulate a real-world process. A view is where one
will define exactly how to represent a model. When there is a change in the data, the view
needs to reflect the changes on its presentation. Lastly, the controller receives actions
11
from the view (e.g. a mouse click), and if there is a change in data by the user on the view,
controller will report this to the model. If the new data is invalid, the model will tell the
view to keep the old one, else the model makes changes to its data. (See Figure 5)
(Eckstein, 2007)
Figure 5: A Common MVC Implementation
MVC framework has been practiced in most GUI programming, such as Java Swing
(Fowler, 2008). There are now many versions of MVC framework, for example Java
Swing’s MVC is a version that the Controller and View are combined into one, known as
Delegate, thus their MVC now becomes a Model-to-Delegate (See Figure 6).
Figure 6: Java Swing Modified MVC Implementation
Another modified MVC implementation is shown in Figure 7 (Eckstein, 2007) where the
controller acts as the mediator between the model and view. When there is a change in
the model, controller will pass the changes to the view, and vice versa. One of its
12
advantages is the easy coupling and decoupling of model or view from the controller.
One can also couple more than one view to a controller, so that a model can be presented
in different number of views.
Figure 7: Another type of modified MVC implementation
Another advantage of this implementation is that when there are two independent views
that share the same data from the model, whenever there is a valid data change in one
view, the other view will get notified regarding the change to the data. This project
actually uses this modified MVC implementation based on the separation of concerns
principle. Refer to 3.2 Separation of concerns.
2.3.1 Java Swing
This is one of the existing GUI libraries for Java that practices MVC implementation.
Although it uses a different MVC implementation from the common MVC or the one
used by this project, it is a good way to look at how Swing’s Model-to-Delegate MVC
implementation comes about (See Figure 6 for the Model-to-Delegate diagram).
At the beginning, implementation of Swing follows the common MVC implementation,
where each component has three parts – model, view and controller. However, the
developer team of Java Swing soon realizes that the view and controller requires a “tight
13
coupling”. They complained that it is difficult to write a generic controller that didn’t
know any details about its view. Hence, the Swing collapsed the view and controller parts
of every component into a single user interface (UI) object.
In the article “Swing Architecture Overview” on “The Inside Story on JFC Component
Design” by Amy Fowler, there’s a declaration that the Swing has a strong MVC lineage
(Fowler, 2008). More details can be found in that article regarding Swing’s modified
MVC implementation, in which they called it separable model architecture.
14
3 Design Principles
3.1 Convention over Configuration
A software design paradigm from Ruby on Rails, Convention over Configuration, has
become popular. It seeks to decrease the number of decisions that developers need to
make, gaining simplicity, but not necessarily losing flexibility (Convention on
Configuration, 2008). One of the project’s objectives is to build a default form display
and it is accomplished in naïve implementation. However, the default form display for
MVC implementation is included in the recommendations for future works due to the
insufficient time to accomplish this.
One may argue for the purpose of a default form display for both implementations, as
there are a lot of non-determinism from the developers whether they like it or not.
However, this is to ensure that a form based on the model is ready to be viewed by the
developer once he/she finished with the model. From there, the developer can make
further configurations to improve or decorate the visualization, or start from scratch.
Moreover, it is not easy to come up with a convention from the author’s point of view.
Thus, the author went for the most common form elements, textbox, for the most types of
data declared in property. He didn’t provide the conventions for attributes declared in
fields.
The reason is that there is no fixed type for fields, and it is hard to determine which
default form elements would be suitable because textbox is ideal for strings, numbers,
Date (probably) and Boolean. However, fields could be an array or an object, which are
hard to be represented by a textbox, a checkbox or any simple form elements.
15
3.2 Separation of concerns
The concern in this project refers to the coupling between a model and its GUI view. A
model should be able to work like a normal class on its own. It should not be concern for
being televised by one or more views, or in another word, should not be concern whether
the views are displaying the correct information. The view, like model, does not need to
worry whether the information it is displaying matches those in model. All these concerns
lie on the controller whose task is to ensure that all views of this model have the correct
information. As the validation of attributes usually found in the model, any updates from
the view are reported to the model for validation via the controller.
Separation of concerns also promotes easy coupling and decoupling among the model,
controller and view. Suppose there is a school database that kept students’ final exam
scores. Depending on the user who is viewing the database, students can only view their
final exam scores which they sat for; teachers can view all the students’ scores that they
has taught; a principal will be able to view the entire database. The database, the model in
this case, has different views for different group levels.
Suppose at one time, the principal is no longer interested to view the entire database, but
pictorial representation of scores for each subject. Thus the previous view that can access
the entire database are decoupled, while a new controller is coupled with the database. Its
task is to collect scores from the database and do some statistics computation before
passing it to a view that draws the pictorial representation based on the information given.
Based on the analogy above to illustrate this design principle, this project chooses to
follow the modified MVC implementation as shown in Figure 7.
With the controller as the mediator between the model and view, it fits the description
above – “All these concerns lie on the controller whose task is to ensure that all views of
this model have the correct information.” This MVC implementation also fits the
requirement for easy coupling and decoupling among the three parts.
16
3.3 Reuse
From the naïve implementation, the author realized that it is very difficult to create
complex form elements with HTML DOM, for example a date picker or a slider. Thus he
decided to import rich and interactive form elements or layouts from the existing GUI
libraries. As the project switches to MVC implementation, the author reused Ext JS to
build the views for the testing and demonstration purposes.
This principle also drives the project to write a library, which other applications can reuse.
An example is the property change classes written for MVC implementation. These
property change classes consist of a specific listener (only listens to property change
event), an event data structure (stores the name of the property that changes and new data
that the property changes) and a support (fires the property change event).
Suppose a developer wants a direct link between his model and view. Thus, he/she could
use these property change classes where his model contains the property change support,
and the view being the listener. When there is a property change event, the support
passed the event data structure to its listeners and listeners will then take appropriate
actions. This is an example of a reuse of these property change classes.
3.4 Compositionality
This principle relates to the view of the MVC implementation. Currently, a view has to
be tailored to the attributes of its model by developers due to the absence of a default
form display with MVC implementation. This principle allows developers to build very
complex views, for example a view in another view. This sub-view, i.e. a view in another
view, could have share the same controller with the view or a different controller.
17
Figure 8: Views in views with different controllers
This usually happens when a model has a relationship with other models. For example
suppose a library book could have only an author. Thus if View A in Figure 8 represents
library book form, then View B could be a read-only view for author. If View E is the
author form, any valid changes on View E, such as the family name of the author, will
reflect on View B and View D if they are displaying the family name of the author
(Model 2).
The views can be represented with a hierarchical structure with a root at the top so that
one can refer to the GUI view easily from the root. Anyone can easily draw a simple
layout of the GUI by inspecting this hierarchy.
View A
View B
View C
Model 1
Model 2
Controller I
Controller II
View D
Controller III
View E
18
4 Features
4.1 Default Form Generation
One of the feature of this project, default form generation is implemented in the naïve
implementation, is able to generate a default form for a model, as simple as just declaring
properties or fields. Suppose there is a simple model named Person, and it has three
properties: name, country and age. The default form generated will look like the one in
Figure 9. Note that form has its field label for country renamed as “Nationality”.
Figure 9: Default form generated for Person class
An extract of source code for the above form is:
The skeleton class for this Person class is tc.ui.form.applib.FormObject. In
Figure 9, the property country is renamed (or configured) in the form to Nationality
tc.lang.Class.define (tc.demo.ui, “Person”)
.EXTENDS(tc.ui.form.applib.FormObject)
.PROPERTY(“name”, “string”)
.PROPERTY(“country”, “string”)
.PROPERTY(“age”, “number”)
.CONSTRUCTOR(function() { this.Super(“Person”); })
.METHOD(“toString”, function() {…})
.METHOD(“labelCountry”, function() {…})
.METHOD(“save”, function() {…})
.METHOD(“reset”, function() {…})
.END_CLASS();
19
by the prefix “label” in labelCountry method. Methods that have the same name as
an attribute of a model after removing the prefix, such as labelCountry, are referred
as attribute-based methods.
Another example showing the second prefix that the skeleton recognizes, the “view”.
Any attribute-based method prefixed with “view” configured the form elements for that
particular attribute.
Figure 10: Form generated for Author class
tc.lang.Class.define (tc.demo.ui, “Author”)
.EXTENDS(tc.ui.form.applib.FormObject)
.PROPERTY(“name”, “string”)
.PROPERTY(“country”, “string”)
.FIELD(“startSince”)
.FIELD(“booksWritten”)
/* other methods */
.METHOD(“labelStartSince”, function() {…})
.METHOD(“viewStartSince”, function(parent) {…})
.METHOD(“viewCountry”, function(parent) {…})
.METHOD(“viewBooksWritten”, function(parent) {…})
.END_CLASS();
.METHOD(“labelCountry”, function() {
return “Nationality”;
})
20
The form element for country shown in Figure 10 is a combo box instead of a textbox
now. The body of viewCountry involves creating the combo box with HTML DOM,
placing options into the combo box and some miscellaneous procedures so that the value
of the combo box can be retrieved easily for saving purpose.
As property has a fixed type, there is a convention form elements for each type of
attributes: textboxes for string and number, check box for boolean values and button for
models that extend from the skeleton of naïve implementation. However, developers are
required to write their view method for fields because there is no convention for attributes
declared in fields. Taking the author class for example, startSince and
.METHOD(“viewCountry”, function(parent) {
var me = this;
var attrParent = document.getElementById(parentId);
var attrInput = document.createElement("select");
attrInput.id = this.getClassName() + "_Country";
var attrTarget = this.getCountry();
var attrHit = false;
var attrChoice = [“UK”, “USA”, “China”];
/* make each element in attrChoice into options and
append it to attrInput, also check if any elements match
the attrTarget. If do, set attrHit = true */
if (!attrHit) {
/* make a new option for attrTarget and append
it to the attrInput */ }
attrInput.value = attrTarget; // to select the
matching choice from combo box based on attrTarget
attrParent.appendChild(attrInput);
this.elementId['Country'] = attrInput.id;
return;
})
21
booksWritten are fields of type date and array respectively. (Refer to 3.1 Convention
over Configuration for the reason)
Naïve implementation supports batch data binding, thus there are “save” and “reset”
button. A click on the reset button restores all the values in the form back to those before
the form is saved. On the other hand, clicking on the save button replace the model’s data
with the data collected from the form. One can add in the next action after saving in the
save method.
The method init from the skeleton class initiates the form, e.g.:
4.2 Immediate Data Binding
Immediate data binding refers to the immediate updating of data between the model and
all its views. This is possible with the MVC implementation because the controller, the
mediator, is entrusted with the task to update all views whenever there is an update in
model, and to report the model whenever there is a change from one of the views. If the
change is valid, the model updates its attribute. When this happens, the controller passes
the new data to all views.
.METHOD(“save”, function() {
/* replace the model’s data with the new data */
/* next action here */
})
/* Person Form */
var aPerson = new tc.demo.ui.Person();
aPerson.init();
/* Author Form */
var nAuthor = new tc.demo.ui.Author();
// setting fields, like name, country, etc.
nAuthor.init();
22
Suppose there are two classes, Author and Library Book. A library book could have been
written by more than one author, for example, a technical book “Professional AJAX
(Programmer to Programmer)”, from Amazon.com, has three authors – N. C. Zakas, J.
McPeak and J. Fawcett. Thus a class diagram would like:
See Figure 11 for an example of the Author Form and Library Book Form
Figure 11: Using Ext JS GUI Library
Note that the contents in the forms are for illustration purpose only. There is a reference
to the author from the library book. Thus there are two views for a single model of class
Author, Tang Tung Leh – the author form and the sub-form in library book form.
Whenever the family name or given name is updated in either form, the other one will
reflect the changes. An example of immediate data binding, changing the given name
“Tung Leh” to “Kee Sing” is shown as a sequence in Figure 12 and Figure 13.
Author LibraryBook *
Author sub-form in library book form
23
Figure 12: Changing "Tung Leh" to "Kee Sing"
Figure 13: Leaving the Given Name textbox
The same result applies when the update is made in the sub-form. This also works for
multiple copies of the author form of this model, and whenever an update is made in any
of the forms, including the sub-form, the changes are reflected in all forms.
In MVC implementation, there are three skeleton classes, i.e. AbstractModel,
AbstractController and AbstractView (Refer to 5.2 MVC Design and
Implementation for their purposes). A brief source code for Author’s model, controller
and view (author form):
Immediate data binding
24
Developers create their view with the method render; add in listeners on form elements
to call the methods in its controller to change the model’s property.
tc.lang.Class.define(tc.demo.ui.library, “Author”)
.EXTENDS(tc.ui.form.AbstractModel)
/* declaration of properties and fields */
/* constructor and methods like normal Java class
* the whole class can work independently */
.END_CLASS();
tc…define(tc.demo.ui.library, “AuthorController”)
.EXTENDS(tc.ui.form.AbstractController)
.METHOD(“changeGivenName”, function(val) {
this.setModelProperty(“GivenName”, val);
})
/* methods similar to changeName to change
* properties in model */
.METHOD(“refresh”, function(view) {…})
/* an optional method */
.END_CLASS();
tc…define(tc.demo.ui.library, “AuthorForm”)
.EXTENDS(tc.ui.form.AbstractView)
.CONSTRUCTOR(function(controller) {
this.Super(controller); this.render();
controller.addView(this);
})
.METHOD(“render”, function() {
/* set this._node with GUI codes*/
})
/* other helper methods or properties/fields */
.END_CLASS();
25
In order to start the author form, the developer creates and links each instance of the three
parts of Author, then invoke method show from the view.
Author form adds itself to the controller because the registration with the controller is
done in the CONSTRUCTOR as shown in the source code of author form –
controller.addView(this);.
4.3 Many-Models-Many-Views
This is another feature supported by the MVC implementation, i.e. a controller can have
more than one models. Separation of concerns mentions that models and controllers
could easily couple and decouple between themselves. Immediate data binding works
even with this feature enabled. However this controller now has more than one model to
report to when there is a change in any views. Only those models that contain the relevant
setter update their attribute. In order to enable this feature, the developer simply replaces
the skeleton for controller with AbstractControllerM (same namespace as the
AbstractController) to substitute the one-model-many-views controller with
many-model-many-views controller.
Note than suppose there are two different models with the same attribute name, and a
single controller registered with both models and a single view. When there is an update
at the view on the attribute, the controller reports the new data to both the models. If the
var a = new tc.demo.ui.library.Author({
fname: “Tang”, gname: “Tung Leh”
});
var b = new tc.demo.ui.library.AuthorController();
var c = new tc.demo.ui.library.AuthorForm(b);
b.addModel(a);
c.show();
26
new data is valid to both models, both the models will update their attributes with the
same data.
Suppose there are two models, ModelA and ModelB, a controller ControllerI and a
view View1. ModelA has attributes background colour (bkgColor) and scheme
(scheme). ModelB has attributes button colour (btnColor), tab button colour
(tabColor) and scheme (scheme).
tc.lang.Class.define(tc.demo.ui, “ModelA”)
.EXTENDS(tc.ui.form.AbstractModel)
.PROPERTY(“bkgColor”,“string”).SET(…).END_PROPERTY()
.PROPERTY(“scheme”, “string”).SET(…).END_PROPERTY()
.CONSTRUCTOR(function() { this.Super();
this.setBkgColor(“Blue”); this.setScheme(“Yahoo”); })
.END_CLASS();
tc.lang.Class.define(tc.demo.ui, “ModelB”)
.EXTENDS(tc.ui.form.AbstractModel)
.PROPERTY(“btnColor”,“string”).SET(…).END_PROPERTY()
.PROPERTY(“tabColor”,“string”).SET(…).END_PROPERTY()
.PROPERTY(“scheme”, “string”).SET(…).END_PROPERTY()
.CONSTRUCTOR(function() { this.Super();
this.setBtnColor(“Green”); this.setTabColor(“Grey”);
this.setScheme(“MSNLive”); })
.END_CLASS();
27
Figure 14: View_1 is built using YUI library
As the models are “hidden” in the system, their actual data will be shown through a
console output. As each model can have different data for a common attribute, for
simplicity, they are not shown on the View1 initially.
Here is an example of how each component can be instantiated:
tc.lang.Class.define(tc.demo.ui, “ControllerI”)
.EXTENDS(tc.ui.form.AbstractControllerM)
.METHOD(“changeBkgColor”, function(val) {…})
.METHOD(“changeBtnColor”, function(val) {…})
.METHOD(“changeTabColor”, function(val) {…})
.METHOD(“changeScheme”, function(val) {…})
.END_CLASS();
var a = new tc.demo.ui.ModelA();
var b = new tc.demo.ui.ModelB();
var c = new tc.demo.ui.ControllerI();
var d = new tc.demo.ui.View1(c);
c.addModel(a); c.addModel(b); // register the models
28
If the developer makes the following changes from View1:
Figure 15: View1 filled in and corresponding console output
The data binding between the View1 and the models actually happened after the
developer left the textbox he/she modified, e.g. after he/she has entered “Purple” into the
textbox for background colour and left the textbox, the immediate data binding took
effect, updating the attribute bkgColor of ModelA. Since the attribute bkgColor is
absent in ModelB, this event doesn’t affect ModelB.
Both ModelA and ModelB have the attribute scheme, hence whenever there is an
update to the scheme from View1, ControllerI will report the event to all its models.
ModelA and ModelB will update their scheme upon receiving the event.
This many-models-many-views feature allows developer to deal with view-centric
application, i.e. Computer Aided Design (CAD) applications. In a view-centric
application, the rendering data of a view is modularize into models. E.g. a configuration
// Default data for attributes
var demoprint = tc.io.stdout.println;
demoprint(a.getBkgColor()); // output “Blue”
demoprint(a.getScheme()); // output “Yahoo”
demoprint(b.getBtnColor()); // output “Green”
demoprint(b.getTabColor()); // output “Grey”
demoprint(b.getScheme()); // output “MSNLive”
29
form for a 3D object, e.g. cube, where it can contain the attributes for the perspective and
colour.
Figure 16: Views of two models, i.e. Colour manager and Perspective manager
In this example, the focus of this application is the 3D object rendered from some data.
These data are stored in various models; two of such are colour manager and perspective
manager. As the data in the configuration changes, such as changing the scheme to
“Maverick Blue”, the 3D object will reflect the change in scheme immediately.
Configurations
Scheme: Shadow:
Rotation: Zoom:
Colour >
Perspective >
30
5 Design and Implementation
5.1 Naïve Design and Implementation
5.1.1 Design
The main objective of naïve implementation is to provide a skeleton so that any objects
that want to be displayed as a form (call these objects as models) can extend the skeleton.
This skeleton should able to provide features for:
• Displaying a default view for models (whether it is a new model or an existing
model)
• Allow developers to overwrite the default view easily
• Saving data from the form to the model (batch data binding)
The skeleton class is designed such that it has a method that can know all the properties
and fields of a model that extends from it. If the developer did not specify any views
he/she would like his model or any attributes of the model to have, then the skeleton class
will supply a default form or form elements for each property and field, based on the
principle Convention over Configuration. Prefixes “view” and “label” allow the
developer to configure the form elements and label for any attribute. To configure the
entire form, the developer can overwrite the method view in his model.
The design of the default form comes from the skeleton and a cascading style-sheet (CSS)
file, which decorates the form. The skeleton also adds in drag and drop feature for the
default form so that it can be dragged around in the browser. The default form should
display all the public properties and fields with accessors of the model. For protected and
private fields, developers can include public method getPrivateField that returns
the data of a private field if they want to display the private field on the form.
31
5.1.2 Implementation
The skeleton class, tc.ui.form.applib.FormObject, is an abstract class that
recognizes the prefixes and engineers the GUI display of a model that extends from it.
(See Appendix A for the API of this skeleton class)
There are two important fields from this skeleton class: elementId and attributes.
The field attributes is an array used to store all the attributes to be displayed on the
GUI from the model. It uses reflection methods to retrieve all the fields with accessors
and public properties from the model.
The field elementId is an object that used to store all “ids” used in the form elements
displayed on the GUI. If it is a default form element, for example a textbox for the
property name, then elementId will contain a pair {Name: Person_Name}. If the
number of form elements for a property is more than one, then the id of the form
elements are stored in an array, i.e. pair {Name: [Person_Name_1,
Person_Name_2]}. By convention, the id for each form elements is <Model
Name>_<Attribute Name>. If developers configure the form elements, they are
responsible to insert their element ids involved into the elementId.
tc…defineAbstract(tc.ui.form.applib, “FormObject”)
.FIELD(“elementId”)
.FIELD(“attributes”)
.PRIVATE().FIELD(“className”)
/* static fields for drag-and-drop (dnd) */
.CONSTRUCTOR(function(className) {
this.__className = className;
this.elementId = {};
this.attributes = [];
/* initializing the static fields for dnd */
})
32
The static fields and methods used for drag and drop feature are enquired from The
JavaScript Reference Series on JavaScript Drag and Drop, written by P. Hunlock, as at
December 2, 2006 (Hunlock, 2006).
The init method does the following two actions:
• Files the public properties and fields with accessors from the model in the field
attributes, and
• Build the default form for the model by running the method view
It will skip the first action if it has initialized before, i.e. the field attributes is not
empty.
The convention view method in the skeleton class, builds the two layers: one for drag
and drop purpose and another for storing contents. It also includes a close button to close
that form. In the inner layer, the default form stores the labels and form elements of
attributes of model in a field set and have a suitable title, as can be seen in Figure 10 in
page 19. These form and form elements are built with HTML DOM, the lowest level of
building widgets in JavaScript.
The save and reset methods are abstract methods, i.e. all models that extend from the
skeleton have to implement. The save method retrieves the data from every form
elements with the help of the field elementId and set the attributes with the data from
the appropriate form elements. The reset method is the reverse, setting the data in each
form element with data of appropriate attributes of the model.
.STATIC().FIELD("savedTarget").STATIC().FIELD("orgCursor"
).STATIC().FIELD("dragOK").STATIC().FIELD("dragXoffset").
STATIC().FIELD("dragYoffset")
.METHOD(“dragHandler”, function(e) {…})
.METHOD(“moveHandler”, function(e) {…})
.METHOD(“cleanup”, function(e) {…})
33
The skeleton can’t provide a convention method for save and reset because there is
no convention whether all ids follow the same pattern <Model name>_<Attribute name>
for all form elements. The developer has the freedom to specify any id and have any
number of form elements for an attribute upon configuration.
5.2 MVC Design and Implementation
5.2.1 Design
There are three skeleton classes in this implementation:
• tc.ui.form.AbstractModel,
• tc.ui.form.AbstractController and
• tc.ui.form.AbstractView.
All models have to extend from AbstractModel because this class brings in the
backend support to fire property change to any registered controllers. Developers are
required to signal a property change event in the setters of the attributes in his/her models.
All controllers have to extend from either AbstractController or
AbstractControllerM (to enable many-models-many-views feature) because they
provides the
• methods to register or remove itself with any AbstractModel(s),
• methods for AbstractView(s) to sign up or drop out,
• methods to listen for property change event from the model(s) and disseminate the
new data from the model to every view that signed up with it
• methods to report changes from the view to the model
Developers are required to write methods that change the attributes of its model, so that
these methods can be used as event handlers in the view.
34
All views have to extend from AbstractView. This is to standardize all views such
that a field, _node refers to the root of the GUI view, and the field controller refers
to the controller it signed up with. For this project, a view can only have one controller as
it is sufficient to implement the immediate data binding.
Developers are encouraged to reuse existing GUI libraries to produce rich and
sophisticated forms in views. The view should not contain any methods from its model
(via controller) due to Separation of concerns.
Property change classes are necessary to support the direction: Model Controller
View. A model takes the role of the property change support, whereas the controller takes
the role of listener. The model will fire a property change event to all its listeners, i.e.
controllers. An event data structure, which contains the name of the updated attribute and
its updated data, is sent to the listeners too. Upon receiving the event, the controllers will
pass the event data structure onto the views.
For View Controller Model direction, event handlers (controller’s methods) are
attached onto events of the form elements in view, e.g. an onChange event is fired when
the content of a textbox is different, this will then invoke a method that reports this new
content to the model.
A relationship diagram shown in Figure 17 depicts what have been described on the
skeleton classes, property change support and property change listener.
Figure 17: Relationship diagram of MVC Implementation
AbstractModel AbstractController AbstractView
Property Change Support Property Change Listener
1 *
1 * 1
35
5.2.2 Implementation
These are the classes implemented: (source codes can be found in Appendix A)
• tc.ui.form.PropertyChangeEvent (the event data structure),
• tc.ui.form.IPropertyChangeListener (property change listener),
• tc.ui.form.PropertyChangeSupport (property change support),
• tc.ui.form.AbstractModel (skeleton class for models),
• tc.ui.form.AbstractController (skeleton class for controllers) and
• tc.ui.form.AbstractView (skeleton class for views).
PropertyChangeEvent is a simple data structure for holding the name of an updated
attribute, its new data and a holder for any extra information the support would like to
include, e.g. the previous data or the source of the event, i.e. the model that first triggers
the event.
IPropertyChangeListener is an interface that listens to property change event
signal from PropertyChangeSupport. The propertyChange method is a compulsory
method that all listeners required to implement.
PropertyChangeSupport is a class that contains a list of property change listeners
and methods to add, remove listeners and fire property change event. It will encapsulate
the updated attribute’s name, the new data and any optional parameters into an event data
structure, i.e. PropertyChangeEvent. Then it will apply the method
propertyChange of all its listeners with this event data structure as its argument.
Following the design, AbstractModel has a property change support, i.e. an instance
of PropertyChangeSupport, and methods that are similar to
PropertyChangeSupport. Its methods are actually calling methods of its property
change support.
36
AbstractController is an abstract class that has an attribute to contain the model,
and a list to contain the views. It has a compulsory propertyChange method, which
simply passes on the event data structure to all views in the list, because it is a type of
property change listener. Apart from the methods that set a model and add or remove
views, other methods are used for writing event handlers for the view.
AbstractView is an abstract class that has two attributes, one for the controller it
registered with, and another for the root of the GUI display (based on the
compositionality, the GUI display should have a root and can be represented in a
hierarchical order). It has an abstract method, modelPropertyChange, which takes
the event data structure from the controller’s propertyChange method. It usually
contains a large if-block that updates any form element based on the property name from
the data structure. Although render isn’t an abstract method, it is usually a de facto
method that developers set the field _node with their presentation code. Developers can
have more than one method to modularize their presentation code, but in the end, they
must put the root or the most top-level of their presentation code in the field _node.
Finally, they also need a method to show the GUI view. A conventional name for such
method, which the author usually uses too, is show.
Figure 18: Summary of actions from Model to Controller to View
Model Controller (1) Fires property change
View_1 View_2
(2) “propertyChange” invoked
(3) Sends the event data structure to all views
(4) “modelPropertyChange” invoked – check property name, and update the content in the correct form element
37
However, when the changes come from one of the views, an event is fired, thus invoking
its event handlers. Suppose there is a textbox, with an event handler attached to its
onChange event. Whenever the content of the textbox is changed, this event is triggered
and the event handler is applied with the new data as an argument.
After the model changes its data, it fires the property change event and the actions
followed through as in Figure 18 (See Figure 19). At this point, all the data in all views
should match the model’s attributes. There could be validation check in the model’s
setters to discard any invalid input. Developers can choose, when there’s an invalid
update, whether to fire a property change event that restores the data in the view to the
previous valid data (See Figure 20).
Figure 19: Summary of actions performed when a valid update is made at one of the views
Figure 20: Summary of actions performed when an invalid update is made at one of the views
The two controllers shown in Figure 19 and Figure 20 are actually the same controller.
View_1 View_2 Controller (1) An invalid update
Model
(2) Calls a model’s setter
Controller (3) Fires property change with old data
(4) Updates all views with the old data
View_1 View_2 Controller (1) A valid update
Model
(2) Calls a model’s setter
Controller (3) Fires property change
(4) Updates all views with the new data
38
With many-models-many-views features, there is a method setModelProperty that
helps to look for the setter of the changed attribute from the list of models. For every
model that has the correct setter, the controller will call that model’s setter.
Figure 21: Summary of actions performed for a valid change with many-models-many-views feature
Thus it is not advisable to have models sharing the same attribute name with many-
models-many-views feature enabled. Suppose there are two models that share the same
attribute name, but have different validation techniques, i.e. a valid data in one model
may be an invalid data in the other model. It becomes unclear whether the views should
update to new data or revert back to the previous data.
View_1 View_2 Controller (1) A valid update
Model_1 Controller
(4) Updates all views with the new data
Model_2 (3) Models that has attributes been updated fires property change with the same new data
(2) Calls all models’ setter
39
6 Recommendations for Future Work
6.1 Tools for Building View
Despite switching from naïve implementation to MVC implementation, there is still a
lack of support for building sophisticated view. Although developers can reuse the
existing GUI libraries, such as YUI and Ext JS, they need time to learn how to use these
libraries before using them. Thus the author hopes for tools that can minimize the time
for building a user-friendly GUI form.
Due to time constrain of this project, the author does not have time to explore into these
tools. However, he would like to recommend some work can be done in future, whether it
could be another Honours project, to improve on this framework to meet the overall
objective – assist developers in visualizing the data of their application with the minimum
time span.
6.1.1 Default View for MVC Implementation
Default form display is available in naïve implementation, but not in MVC
implementation. With the assumption that most developers prefer immediate data binding
than batch data binding, if this feature is included into MVC implementation, naïve
implementation can be totally replaced.
6.1.2 A Form Builder
Normally, when one refers to data visualization, the GUI display should look like a form
where the label on one side and the data on the other side (see Figure 22).
Figure 22: A simple form
Name Age
Title
40
In order to minimize the time in building a view, instead of writing presentation codes, it
will be efficient to have a form builder that can build forms through drag-and-drop. One
such example is Glade, which is a user interface builder, is a tool to enable quick and
easy development of user interfaces for the GTK+ toolkit and the GNOME desktop
environment (Glade, n.d.).
Figure 23: Screenshot of Glade from http://glade.gnome.org/screenshots.html
A form builder doesn’t have to be as complex as Glade (see Figure 23). However, it
should be able to allow developers to create a top-level window, add form elements and
labels onto this panel, and add event handlers to the form elements. Finally, it can output
the presentation code in JavaScript so that it can be copied to the developer’s view to be
render.
6.1.3 Import and Export of View into JSON
JSON stands for JavaScript Object Notation. It is a lightweight data-interchange format,
based on a subset of JavaScript objects. It is easy for humans to read and write, and easy
for computers to parse and generate (Introducing JSON, n.d.). An example of JSON is:
41
An advantage of using JSON over XML in JavaScript is that JSON can be restored into
the original JavaScript object by a single eval() function. However, XML requires parsing
before it can be reinstated into a JavaScript object.
With the introduction of JSON, it will be great if the view can turn its presentation code
that built the GUI display into JSON before exporting it out. Suppose the developer can
make the adjustments on this JSON, which the view can import and display the adjusted
GUI. Thus this gives another option that developers can use to modify their presentation
codes. This import and export feature works best when there is a default form display
feature, because it can be a starting ground for developers to customize in JSON.
{
“a”: “apple”,
“b”: [“boy”, “balloon”],
“c”: {“ca”: “cat”, “ce”: “cell”},
“d”: {“da”: [“dagger”, “dawn”], “de”: “deer”},
“e”: [
{“ea”: “ear”, “ee”: [“eel”, “eek”]}
{“ex”: [
{“exa”: “exalt”, “exe”: “execute},
{“exa”: “examine”, “exi”: “exit”}
], “el”: “elevator”}
],
“f”: [“falcon”, {“fr”: [“fry”, “fridge”]}, “fit”]
}
42
7 Lessons Learnt
7.1 Collaboration
Although this project is an individual-based, being part of a development team gives each
developer to collaborate with one another. Meetings are usually held on Saturday
morning fortnightly during the entire period of the project where developers update one
another on the work they have done throughout the two weeks, e.g. the features they
added to TiddlyCard or any changes made in some API that may affect other developers’
work due to dependencies.
This project depends a lot on the TiddlyCard module system and other methods it offers,
such as the reflection methods. Whenever there is any ambiguity in the API of this
TiddlyCard module system, the author could approach the developer of this system for
guidance. This collaboration is proved beneficial as the author, being the user of this
TiddlyCard module system, can provide feedback to the developer of the module system
and other developers can provide feedback on the framework to the author.
7.2 Programming in JavaScript, HTML DOM and Events
The author did not have any knowledge on web-programming at all before this project
started. JavaScript is a remarkably expressive dynamic programming language
(Crockford D, 2002), which is a very different programming language from Java, C# and
other static programming languages. As there isn’t any type checking in JavaScript, a
variable can refer to anything – string, number, boolean, arrays or objects. The transition
from static programming languages to a dynamic one is not an easy adjustment. Many
often, the author spent more time debugging the JavaScript codes than understanding the
codes.
Although the author has designed websites before, he was not aware of HTML DOM and
events. Thus he had difficulty in understanding and using YUI at the beginning of the
43
project. It is during the naïve implementation that the author exposes to more JavaScript,
HTML DOM and events. By then, he could start using Ext JS for building examples in
MVC implementation.
44
8 Conclusions This project has met its objective in setting up a framework that any developer can build
their application with and immediate data binding is the main feature of this project. As
this project is guided by the design principle Separation of concerns, which many
developers would have in mind, they can adapt to the framework in ease. This project
also contributes the property change classes where developers can reuse for their
application, even if they use it for other purposes, other than data visualization.
The MVC implementation of this project only consists of three skeleton classes that
developers need to know, and extend their models, controllers and views from the
appropriate skeleton. On the other hand, if developers would just like to visualize their
data in a simple form (for example a survey form), they can make their model to extend
from the skeleton class of naïve implementation. A default form will display in front of
them as they call the init method. After that, they can configure the form by overwriting
the conventional methods.
Although this framework hasn’t reached the point where the developers can get a GUI
form up to display its data of application in a snap of fingers, it has taken the first step in
providing the skeletons and the support for immediate data binding. The mechanisms
behind immediate data binding are easy to understand and follow with diagrams Figure
18, Figure 19, Figure 20 and Figure 21 under section 5.2 MVC Design and
Implementation.
For the time being, developers are required to use HTML DOM or learn one of the
existing GUI libraries to build their views from scratch.
45
References BSD License. (2008, March 11). Retrieved March 21, 2008, from Wikipedia:
http://en.wikipedia.org/wiki/BSD_License
Convention over Configuration. (2008, March 19). Retrieved March 26, 2008, from
Wikipedia: http://en.wikipedia.org/wiki/Convention_over_Configuration
Crockford D. (2002). JavaScript: A Survey of the Language. Retrieved March 27, 2008
from JavaScript: http://www.javascript.crockford.com/survey
Dojo Toolkit. (2008, March 7). Retrieved March 21, 2008, from Wikipedia:
http://en.wikipedia.org/wiki/Dojo_Toolkit
Eckstein, R. (2007, March). Java SE Application Design With MVC. Retrieved March 21,
2008, from Java: http://java.sun.com/developer/technicalArticles/javase/mvc/
Eclipse Public License. (n.d.). Retrieved March 21, 2008, from Eclipse:
http://www.eclipse.org/legal/epl-v10.html
Ext JS. (n.d.). Ext JS Library License. Retrieved March 21, 2008, from:
http://extjs.com/license
Fowler, A. (n.d.). A Swing Architecture Overview. The Inside Story on JFC Component
Design. Retrieved March 21, 2008, from Java:
http://java.sun.com/products/jfc/tsc/articles/architecture/
Glade (n.d.). Glade User Interface Builder. Retrieved March 27, 2008, from Glade:
http://glade.gnome.org/
46
GNU LGPL. (2007, June 29). Retrieved March 21, 2008, from GNU:
http://www.gnu.org/licenses/lgpl.html
Hunlock, P. (2006, December 2). JavaScript Drag and Drop. Retrieved December 12,
2007, from The JavaScript Reference Series:
http://www.hunlock.com/blogs/Javascript_Drag_and_Drop
HyperCard. (2008, March 15). Retrieved March 21, 2008, from Wikipedia:
http://en.wikipedia.org/wiki/HyperCard
Introducing JSON (n.d.). Retrieved March 27, 2008from JSON: http://www.json.org/
Naked Objects Group. (n.d.). Retrieved March 21, 2008, from Naked Objects Group:
http://www.nakedobjects.org/home/index.shtml
OSI. (2006, October 31). Open Source Initiative - Academic Free License v3.0. Retrieved
March 21, 2008, from OSI: http://www.opensource.org/licenses/academic.php
Qooxdoo Classes. (2008, Jan 17). qooxdoo >> Classes. Retrieved March 27, 2008, from
Qooxdoo: http://qooxdoo.org/documentation/0.7/class_declaration
Qooxdoo Home. (2008, March 19). qooxdoo >> Home. Retrieved March 21, 2008, from
Qooxdoo: http://qooxdoo.org/
Qooxdoo Manual v0.7. (2008, Feb 10) qooxdoo >> Manual v0.7. Retrieved March 27,
2008 from Qooxdoo: http://qooxdoo.org/documentation/0.7
Ruston, J. (2007, May 16). TiddlyWiki. Retrieved March 21, 2008, from TiddlyWiki:
http://www.tiddlywiki.com/
47
The Dojo Toolkit. (2008, Apr 28). JavaScript Programming with Dojo and Dijit.
Retrieved March 27, 2008 from Dojo: http://dojotoolkit.org/book/dojo-book-0-
9/part-3-programmatic-dijit-and-dojo-0
Yahoo! Developer Network. (n.d.). The Yahoo! User Interface Library (YUI). Retrieved
March 21, 2008, from Yahoo!: http://developer.yahoo.com/yui/
48
Appendix A – Framework API
A.1 FormObject
tc.lang.Class.defineAbstract(tc.ui.form.applib, “FormObject”)
Attributes summary
public field attributes: array <string>
All attributes from the model to be displayed on the form, i.e. public
properties, and fields with getters
static public
field
dragOK: object
For drag-and-drop purpose
static public
field
dragXoffset: object
For drag-and-drop purpose
static public
field
dragYoffset: object
For drag-and-drop purpose
public field elementId : object
All element ids presented in the form for easy retrieval of data from these
elements
static public
field
orgCursor: object
For drag-and-drop purpose
static public
field
savedTarget: object
For drag-and-drop purpose
Constructor Summary
protected tc.ui.form.applib.FormObject (string ClassName)
Only called by sub-classes via this.Super(string ClassName).
Methods Summary
public cleanup(event e) : void
For drag and drop purpose
public close() : void
Close the form
public dragHandler(event e) : void
49
For drag and drop purpose
public getClassName() : string
Retrieve the name of this class
public init() : void
Initialise the form, invoke view method and display the form
public moveHandler(event e) : void
For drag and drop purpose
public reset() : void
Abstract method; Replace the data in the form elements with the current
data from the model
public save() : void
Abstract method; Replace the current data in the model with new data,
collected from the form elements
public view() : void
Builds the form and append form elements based on the items in
this.attributes. Call viewAttrByDefault for default form elements.
public viewAttrByDefault(string attr, string parentId) : void
Create a default form element based on the attr and append it to its parent
whose id is parentId.
A.2 PropertyChangeEvent
tc.lang.Class.define(tc.ui.form, “PropertyChangeEvent”)
Attributes summary
public field newValue : object
public field others : object
Other extra details to pass on apart from the property name and the new
value, .e.g old value, source of this event or timestamp
Default to empty object: {}
public field propertyName : string
Constructor summary
50
public tc.ui.form.PropertyChangeEvent (string propName, object
newValue, object others)
E.g. var a = new tc.ui.form.PropertyChangeEvent (“aProp”, “newData”,
{oldValue: “oldData”, when: newDate(), handler: someFn});
A.3 IPropertyChangeListener
tc.lang.Interface.define(tc.ui.form, “IPropertyChangeListener”)
Method summary
public propertyChange (PropertyChangeEvent evt): void
Invoked upon receiving a property change event
A.4 PropertyChangeSupport
tc.lang.Class.define(tc.ui.form, “PropertyChangeSupport”)
Attributes summary
public field listeners : array
All interested listeners, waiting for any property change event
public field source : object
Constructor summary
public tc.ui.form.PropertyChangeSupport(object source)
Methods summary
public addPropertyChangeListener (IPropertyChangeListener listener) :
void
Adds a new listener to this.listener and there isn’t any duplicate in
this.listener.
protected findPropertyChangeListener (listener) : object
Check if the listener has existed in this.listeners
Returns an object {ans: true, index: i} where i is the index of the listener.
Returns {ans: false, index: -1} if listener does not exist in this.listeners
public firePropertyChange(string propName, object newVal, object
51
others) : void
Forms a PropertyChangeEvent data structure to encapsulates the
propName, newVal and others ({source: this_class, …}). Trigger the
property change event, i.e. passing this data structure to all listeners in
this.listeners
public removePropertyChangeListener (IPropertyChangeListener
listener) : void
Removes the listener from this.listener if it is found in the array.
A.5 AbstractModel
tc.lang.Class.defineAbstract(tc.ui.form, “AbstractModel”)
Attribute summary
public field propertyChangeSupport : PropertyChangeSupport
To support the property change backend
Constructor summary
public tc.ui.form.AbstractModel()
Initialise this.propertyChangeSupport
Methods summary
public addPropertyChangeListener (IPropertyChangeListener listener) :
void
public firePropertyChange (string propName, object newVal, object
others) : void
public removePropertyChangeListener (IPropertyChangeListener
listener) : void
A.6 AbstractController
tc.lang.Class.defineAbstract(tc.ui.form, “AbstractController”)
.IMPLEMENTS(tc.ui.form.IPropertyChangeListener)
Attributes summary
52
public field registeredModel : AbstractModel
The only model this controller receives property change event from
public field registeredViews : array <AbstractView>
The views this controller will inform after receiving a property change
event
Constructor summary
public tc.ui.form.AbstractController()
Methods summary
public addModel (AbstractModel model) : void
See setModel
public addView (AbstractView view) : void
Adds a new view into this.registeredViews and make sure no duplicates
protected findView (AbstractView view) : object
Check if view exists in this.registeredView before. If do, returns an
object {ans: true, index: i} where i is the index of the view in
this.registeredViews. Else, returns {ans: false, index: -1}
public getAllConstants (object clazz) : array <string>
Helper method to facilitate the import of static constants from clazz
public getModelProperty (string propName) : object
Retrieves data from this.registeredModel via a getter of propName. If
getter does not exist, an error message is triggered
public propertyChange (PropertyChangeEvent evt) : void
Disseminates evt to all views in this.registeredViews
public removeModel (AbstractModel model) : void
Set this.registeredModel to null; not listening to any property change
events
public removeView (AbstractView view) : void
Removes a view from this.registeredViews if it existed in
this.registeredViews
public setModel (AbstractModel model) : void
53
Set this.registeredModel to model
public setModelProperty (string propName, object newVal) : void
Calling the setter of the propName in this.registeredModel with the
newVal. Ignore if this.registeredModel does not have such setter
A.7 AbstractControllerM
tc.lang.Class.defineAbstract(tc.ui.form, “AbstractControllerM”)
.IMPLEMENTS(tc.ui.form.IPropertyChangeListener)
Attributes summary
public field registeredModels : AbstractModel
The models that this controller receive property change event from
public field registeredViews : array <AbstractView>
The views this controller will inform after receiving a property change
event
Constructor summary
public tc.ui.form.AbstractControllerM()
Methods summary
public addModel (AbstractModel model) : void
Adds a new model into this.registeredModels and make sure no
duplicates
public addView (AbstractView view) : void
Adds a new view into this.registeredViews and make sure no duplicates
protected findModel (AbstractModel model) : object
Check if model exists in this.registeredModel before. If do, returns an
object {ans: true, index: i} where i is the index of the model in
this.registeredModels. Else, returns {ans: false, index: -1}
protected findView (AbstractView view) : object
Check if view exists in this.registeredView before. If do, returns an
object {ans: true, index: i} where i is the index of the view in
this.registeredViews. Else, returns {ans: false, index: -1}
54
public propertyChange (PropertyChangeEvent evt) : void
Disseminates evt to all views in this.registeredViews
public removeModel (AbstractModel model) : void
Removes a model from this.registeredModels if it existed in
this.registeredModels
public removeView (AbstractView view) : void
Removes a view from this.registeredViews if it existed in
this.registeredViews
public setModelProperty (string propName, object newVal) : void
Calling the setter of the propName in this.registeredModel with the
newVal. Ignore if this.registeredModel does not have such setter
A.8 AbstractView
tc.lang.Class.defineAbstract(tc.ui.form, “AbstractView”)
Attributes summary
public controller : AbstractController or AbstractControllerM
protected node : object
Refers to the root of the hierarchy of the GUI display
Constructor summary
public tc.ui.form.AbstractView(AbstractController/AbstractControllerM
ctrl)
Methods summary
public getNode : object
Retrieves the node
public modelPropertyChange : void
Abstract method; Actions to be taken upon receiving a property change
event from this.controller
55
Appendix B – TiddlyCard Module System Features This appendix shows only those features of the system that are used in this project.
Property, Field, Methods and Access Modifiers
An attribute of a class can be declared as a PROPERTY or FIELD. Property has a fixed
type: string, number, boolean and any TiddlyCard objects (class declared with the
function tc.lang.Class.define). The system will generate getters and setters for
property during run-time. On the other hand, field, like any JavaScript variables, does not
have a fixed type and the system will not generate any getters or setters for field.
Access modifiers are keywords that specify the accessibility of an attribute, e.g. public,
protected and private. These modifiers are applicable to all properties, fields and methods.
Methods are functions that a class can perform actions.
The default access modifier for properties, fields and methods are public, thus it can be
ignored in the code, .e.g. publicProp and publicField are public attributes. For
private attributes, the system adds in two underscores ‘_’ before the field, such as
tc.lang.Class.define(tc.demo.ui, “MyClass”)
.PROPERTY(“publicProp”, “boolean”, false)
.PROTECTED().PROPERTY(“protectedProp”, “number”)
.PRIVATE().PROPERTY(“privateProp”, “string”)
.FIELD(“publicField”, “aString”)
.PROTECTED().FIELD(“protectedField”)
.PRIVATE().FIELD(“privateField”)
.CONSTRUCTOR(function() {
this._protectedField = {a: “a”, b: “b”};
this.__privateField = [1,2,3];
})
.END_CLASS();
56
privateField. The system inserts an underscore before a protected field, such as
protectedField. This applies to methods and properties too. The getters and setters
of the properties are methods of the class too. Thus the system adds one and two
underscores for protected and private methods respectively, such as the getter method for
privateProp, __getPrivateProp, generated during run-time.
The function tc.io.stdout.println is a printing statement that accepts a
parameter to be printed on a console. This is shown in the output.
var a = new tc.demo.ui.MyClass();
if (a.getPublicProp()) // output line 3
tc.io.stdout.println(“publicProp is true”);
else tc.io.stdout.println (“publicProp is false”);
a._setProtectedProp(93);
a.__setPrivateProp(“Hello”);
tc.io.stdout.println(“ProtectedProp: ” +
a._getProtectedProp()); // output line 4
tc.io.stdout.println(“PrivateProp: ” +
a.__getPrivateProp()); // output line 5
tc.io.stdout.println(“Public – Protected – Private
fields : ” + a.publicField + “ - ” + a._protectedField.a
+ “ - ” + a.__privateField[0]); // output line 6
a.publicField = new Date();
if (a.publicField.constructor == Date) // output line 7
tc.io.stdout.println(a.publicField);
else tc.io.stdout.println(“Failed to set a.publicField”);
57
Implementing Interfaces
TiddlyCard module system supports multiple interface inheritance, i.e. a class can
implement more than one interface. An interface contains only the method signature and
classes implementing this interface should fulfill the contract by writing the body of the
method. It is conventional to start with an ‘I’ for interface.
Since the interface ICrawlers are in the same namespace as Baby, TiddlyCard
module system allows the class need not specify the full namespace.
tc.lang.Interface.define(tc.demo.ui, “IPerson”)
.METHOD(“shout”).METHOD(“talk”)
.END_INTERFACE();
tc.lang.Class.define(tc.demo.ui, “Baby”)
.IMPLEMENTS(tc.demo.ui.IPerson, “Crawlers”)
.PROPERTY(“name”, “string”)
.CONSTRUCTOR(function(n) { this.setName(n); })
.METHOD(“shout”, function() {
tc.io.stdout.println(this.getName() + “: I’m
crying!”); })
.METHOD(“talk”, function() {
tc.io.stdout.println(this.getName() + “:
Speaking my own baby language”); })
.METHOD(“crawl”, function(step) {
tc.io.stdout.println(this.getName() + “ has
crawled “ + step + “ steps”); })
.END_CLASS();
tc.lang.Interface.define(tc.demo.ui, “ICrawlers”)
.METHOD(“crawl”)
.END_INTERFACE();
58
Extending Base Class
TiddlyCard module system supports single implementation inheritance, i.e. a class only
extends from a class. A final class (declared with function
tc.lang.Class.defineFinal) cannot be extended by any other classes, whereas
an abstract class (declared with function tc.lang.Class.defineAbstract) is
required to be extended by classes because this class cannot be instantiated. This project
uses abstract class for developing skeleton classes for the framework.
var baby = new tc.demo.ui.Baby(“Alvin”);
baby.shout(); baby.talk(); baby.crawl(5); // outputs
tc.lang.Class.define(tc.demo.ui, “Staff”)
.PROPERTY(“name”, “string”)
.PROPERTY(“duty”, “string”)
.CONSTRUCTOR(function(n) { this.setName(n); })
.METHOD(“toString”, function() {
return “My name is “ + this.getName() + “, I am
a/an “ + this.getDuty() + “ in school”;
})
.METHOD(“speech”, function() {
tc.io.stdout.println(“I love this school”);
})
.END_CLASS();
59
A subclass, i.e. class that extends another class, e.g. Teacher, inherits all attributes and
members of Staff. It can override methods that existed in Staff too, e.g. speech.
Enumeration
Enumeration is a set of items with unique identifiers, each mapping to an integer value.
The items in the enumeration can be type-checked for safety and a property can be
assigned to be an enumeration type.
Suppose the developer wants to restrict the subject to History and Chinese, and school
duty to Admin, Teacher and Cleaner. The developer will create the enumeration
tc.lang.Class.define(tc.demo.ui, “Teacher”)
.EXTENDS(“Staff”).PROPERTY(“subject”, “string”)
.CONSTRUCTOR(function(n) { this.Super(n);
this.setDuty(“teacher”); })
.METHOD(“speech”, function() {
tc.io.stdout.println(“I love to teach “ +
this.getSubject()); })
.END_CLASS();
var tch = new tc.demo.ui.Teacher(“Danny”);
tc.io.stdout.println(tch.toString()); // output line 3
tch.speech(); // output line 4
var stf = new tc.demo.ui.Staff(“Chan”);
stf.setDuty(“Cleaner”);
tc.io.stdout.println(stf.toString()); // output line 5
stf.speech(); // output line 6
60
Subject and SchoolDuty, and then set the type of property subject in Teacher
and duty in Staff to the new enumerations.
In order to use these enumerations, the full namespace has to be specified, e.g.
tc.demo.ui.Subject.History or tc.demo.ui.SchoolDuty.Teacher.
Some modifications are done to the previous example, Staff – Teacher source codes.
tc.lang.Class.define(tc.demo.ui, “Staff”)
.PROPERTY(“name”, “string”)
.PROPERTY(“duty”, “tc.demo.ui.SchoolDuty”)
.CONSTRUCTOR(function(n) { this.setName(n); })
.METHOD(“toString”, function() {
return “My name is “ + this.getName() + “, I am
a/an “ + this.getDuty().toString() + “ in school”; })
.METHOD(“speech”, function() {
tc.io.stdout.println(“I love this school”); })
.END_CLASS();
tc.lang.Enum.define(tc.demo.ui, “Subject”)
.ADD(“History”).ADD(“Chinese”)
.END_ENUM();
tc.lang.Enum.define(tc.demo.ui, “SchoolDuty”)
.ADD(“Admin”).ADD(“Teacher”).ADD(“Cleaner”)
.END_ENUM();
61
Properties subject and duty now accept parameter of type tc.demo.ui.Subject
and tc.demo.ui.SchoolDuty. If the parameter passed to the setters is not the
required type, it will incur an error message. Moreover, it is a good practice to check if
the properties subject or duty are empty before calling toString method.
tc.lang.Class.define(tc.demo.ui, “Teacher”)
.EXTENDS(“Staff”)
.PROPERTY(“subject”, “tc.demo.ui.Subject”)
.CONSTRUCTOR(function(n) { this.Super(n);
this.setDuty(tc.demo.ui.SchoolDuty.Teacher); })
.METHOD(“speech”, function() {
if (this.getSubject()) tc.io.stdout.println(“I
love to teach “ + this.getSubject().toString());
else tc.io.stdout.println(“I love to teach!”);
})
.END_CLASS();
tc.lang.Class.define(tc.demo.ui, “Teacher”)
.EXTENDS(“Staff”)
.PROPERTY(“subject”, “tc.demo.ui.Subject”)
.CONSTRUCTOR(function(n) { this.Super(n);
this.setDuty(tc.demo.ui.SchoolDuty.Teacher); })
.METHOD(“speech”, function() {
tc.io.stdout.println(“I love to teach “ +
this.getSubject().toString()); })
.END_CLASS();
62
The next output will show an example without setting the subject Paul the teacher is
teaching.
The difference between this output and previous output is at line 2, “I love to teach”
instead of “I love to teach History” because the developer did not specify at subject for
Paul the teacher.
var tch = new tc.demo.ui.Teacher(“Paul”);
tc.io.stdout.println(tch.toString()); // output line 3
tch.setSubject(tc.demo.ui.Subject.History);
tch.speech(); // output line 4
var stf = new tc.demo.ui.Staff(“Felix”);
stf.setDuty(tc.demo.ui.SchoolDuty.Cleaner);
tc.io.stdout.println(stf.toString()); // output line 5
stf.speech(); // output line 6
63
Appendix C – A Complete Example This appendix shows the walkthrough and complete source codes for making a model, a
controller, a view and how to get the form to display on the browser. The example this
appendix will work on is the Author class, tc.demo.ui.library.Author.
C.1 Model
An optional step that a developer could take is to have a static class that keeps all the
attribute names as constants, so that they can be used by the models, controllers and
views.
To write the model, the developer has to remember to extend the class from
AbstractModel, fire property change in all setters and include this.Super() in
the constructor to initialize a property change support for each instance.
Since there are a lot of repetitions among the code, these repeated codes will be skipped.
For properties, the developers are required to configure their setters, so that property
change is fired when there is a successful update. However, for fields, one has to write
his/her own accessors for them.
tc.lang.Class.defineStatic(“tc.demo.ui.library”,
LR_Author)
.FINAL().FIELD(“FAMILY_NAME”, “FamilyName”)
.FINAL().FIELD(“GIVEN_NAME”, “GivenName”)
.FINAL().FIELD(“NATIONALITY”, “Nationality”)
.FINAL().FIELD(“ISGF”, “IsGF”)
.FINAL().FIELD(“BIRTH_DATE”, “BirthDate”)
.FINAL().FIELD(“DEATH_DATE”, “DeathDate”)
.END_CLASS();
64
C.2 Controller
As most codes for the Model Controller View transition has been taken care by the
skeleton class, AbstractController, AuthorController only requires including methods for
event handler for the views.
tc.lang.Class.define(tc.demo.ui.library, “Author”)
.EXTENDS(tc.ui.form.AbstractModel)
.PROPERTY(“familyName”, “string”)
.SET(function(val, oldVal) {
this.firePropertyChange(
tc.demo.ui.library.LR_Author.FAMILY_NAME,
val);
return val;
}).END_PROPERTY()
/* Repeat this for givenName, nationality and isGF,
with the correct LR_Author constant */
.FIELD(“birthDate”).FIELD(“deathDate”)
.CONSTRUCTOR(function() { this.Super(); })
.METHOD(“getBirthDate”, function() {
return this.birthDate; })
.METHOD(“setBirthDate”, function(val) {
if (val instanceof Date) {
this.birthDate = val;
this.firePropertyChange(
tc.demo.ui.library.LR_Author.BIRTH_DATE,
val);
}
})
/* Repeat this for deathDate */
.END_CLASS();
65
The refresh method helps to obtain all the data from the registered model and passed
it on to the views upon their initialization. It is an optional method, but the author found it
realistic, i.e. if the model has already contain some data in its attributes, its form should
show these data. The function getAllConstants returns an array of
PropertyChangeEvent data structure-like object, i.e. containing the name of
attribute found in the model and its value. It is as if the model has fired property change
events for all its attributes.
C.3 View
This is the most difficult part of all because the developers are required to build a GUI for
their model. The author reused Ext JS GUI libraries to build the form. It is important for
tc.lang.Class.define(tc.demo.ui.library,
“AuthorController”)
.EXTENDS(tc.ui.form.AbstractController)
.METHOD(“changeFamilyName”, function(val) {
this.setModelProperty(
tc.demo.ui.library.LR_Author.FAMILY_NAME,
val);
}
/* Repeat for changeGivenName, changeNationality,
changeIsGF, changeBirthDate and changeDeathDate with the
correct LR_Author constants */
.METHOD(“refresh”, function(view) {
var allEvt = this.getAllConstants(
tc.demo.ui.library.LR_Author);
for (var i = 0; i<allEvt.length; i++)
view.modelPropertyChange(allEvt[i]);
})
.END_CLASS();
66
the developers to extend their class from AbstractView and keep the root of GUI
hierarchy in the attribute _node.
The show method is an optional method because the form could have been displayed
after the render method is called. The attribute _node refers to the root of the GUI
hierarchy. Developers are required to refer to libraries’ API to check out the method for
displaying the top-level windows.
Method modelPropertyChange is the function that handler any property change
events from the controller, i.e. the registered model of the controller has updated one of
its attribute. This method involves checking the name of the attribute that has updated,
locate the form element on the form relates to this attribute and update the data in this
form element if the new data is different from the data in the form element.
tc.lang.Class.define(tc.demo.ui.library, “AuthorForm”)
.EXTENDS(tc.ui.form.AbstractView)
.CONSTRUCTOR(function(ctrl) {
this.Super(ctrl); this.render();
ctrl.addView(this);
})
.METHOD(“modelPropertyChange”, function(evt) {…})
.METHOD(“render”, function() {…})
.METHOD(“show”, function() {…})
.END_CLASS();
.METHOD(“show”, function() {
this._node.show();
})
67
.METHOD(“modelPropertyChange”, function(evt) {
if (evt.propertyName ==
tc.demo.ui.library.FAMILY_NAME) {
var newValue = evt.newValue;
var comp =
this._node.getComponent(0).getComponent(0);
if (comp.getValue() != newValue)
comp.setValue(newValue);
} else if (evt.propertyName ==
tc.demo.ui.library.GIVEN_NAME) {
/* Same code as above except getComponent(1) */
} else …
/* Repeat this for nationality, isGF, birthDate and
deathDate. If evt doesn’t match all these, then it is
ignored */
})
.METHOD(“render”, function() {
var me = this;
this._node = new Ext.Window({
layout: ‘fit’, title: ‘Edit Author’,
width: 300, height: 350,
items: {
xtype: ‘fieldset’, title: ‘Author Detail’,
autoHeight: true, autoWidth: true,
layoutConfig: {labelSeparator: ‘’},
items: [{…},{…},{…},{…},{…},{…}]
}
});
})
68
The View Controller Model transition is initiated by the change event of all the
form elements in the view. The function for each change event has three parameters, the
source, the new data and the previous data, thus the view is only interested in passing the
new data to a method from controller to change the model’s attribute, e.g.
changeFamilyName method.
items: [{
xtype: ‘textfield’, fieldLabel: ‘FamilyName’,
name: ‘familyName’, listeners: {
change: function(w,n,o) {
me.controller.changeFamilyName(n);
}
}}, {
/* repeat familyName code for givenName and
nationality */
}}, {
xtype: ‘datefield’, fieldLabel: ‘Date of Birth’,
name: ‘birthdate’, listeners: {
change: function(w,n,o) {
me.controller.changeBirthDate(n);
}
}}, {
/* repeat birthDate code for deathDate */
}}, {
xtype: ‘checkbox’, fieldLabel: ‘Given Family’,
name: ‘isGF’, listeners: {
change: function(w,n,o) {
me.controller.changeIsGF(n);
}
}}
]
69
Developers need to declare the model, controller and view, link them up before
displaying the form.
In order to see the immediate data binding, the developer can change any of the attributes
above. Suppose the developer inserts April 9, 1945 for the Date of Birth. The console
output display the update to the model.
var a = new tc.demo.ui.library.Author();
a.setFamilyName(“Robinson”); a.setGivenName(“Fred”);
a.setNationality(“American”);
var b = new tc.demo.ui.library.AuthorController();
b.addModel(a);
var c = new tc.demo.ui.library.AuthorForm(b);
c.show();