SmartGWT is a custom library for GWT that wraps the SmartClient AJAX toolkit. It looks impressively comprehensive and the show case is pretty slick. As with ExtJS though, SmartClient (and by extension SmartGWT) is quite large, and so it will take some time to learn how to use it. That’s my disclaimer, or more accurately an excuse for using such a pitiful example in this post. My aim here is just to show you how to get started with Grails and SmartGWT.
Prerequisites
You need Grails installed, unless you’re using Ant or Maven (in which case you need those installed 😉 ). I’ll assume in this article that you’re using the Grails command line, and therefore have a Grails installation.
Working smart
In order to use SmartGWT you need a Grails project, so create one now. I called mine “smart-working” – feel free to ditch that and use another name. Once Grails has worked its magic and created the project, you need to install the marvellous, wonderful, and downright cool GWT plugin (can you tell I wrote it?):
At the time of writing, this command will install version 0.3.2 and present you with a list of GWT-related commands added by the plugin:
grails install-plugin gwt
Plugin gwt-0.3.2 installed Plug-in provides the following new scripts: ------------------------------------------ grails compile-i18n grails create-gwt-page grails run-gwt-client grails create-gwt-module grails compile-gwt-modules grails generate-gwt-rpc
It’s looking good so far, but there’s no reference to SmartGWT in any of those commands. The sad truth is, you have to install it yourself at the moment. Fortunately, that’s pretty easy:
- grab the SmartGWT distribution from Google Code
- extract the zip file
- create the directory <project>/lib/gwt, for example smart-working/lib/gwt
- copy the smartgwt.jar file (in the root of the unpacked zip) to the directory you just created.
Any GWT libraries that you want to use should go into <project>/lib/gwt.
Your first SmartGWT page
SmartGWT is now ready for action. All we have to do is harness its power in our application’s UI. As with normal GWT, the starting point is a module. Let’s create one now:
This will create two files under the src/gwt directory:
grails create-gwt-module org.example.SmartButton
- org/example/SmartButton.gwt.xml
- org/example/client/SmartButton.java
At the moment, these files are only configured for bog-standard GWT, but adding SmartGWT is pretty straightforward. First off, we need to add a line to the XML module file:
<module> <!-- Inherit the core Web Toolkit stuff. --> <inherits name="com.google.gwt.user.User"/> <!-- Add SmartGWT --> <inherits name="com.smartgwt.SmartGwt"/> <!-- Specify the module entry point class. --> <entry-point class="org.example.client.SmartButton"/> </module>
The second step is to use the SmartGWT elements in SmartButton.java:
package org.example.client; import com.google.gwt.core.client.EntryPoint; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Button; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.layout.VLayout; /** * Entry point classes define <code>onModuleLoad()</code>. */ public class SmartButton implements EntryPoint { /** * This is the entry point method. */ public void onModuleLoad() { VLayout main = new VLayout(); main.setWidth100(); main.setHeight100(); main.setLayoutMargin(5); Button button = new Button("Jump!"); button.setAutoFit(true); button.setPadding(5); button.addClickHandler(new ClickHandler() { public void onClick(ClickEvent evt) { SC.say("You first"); } }); main.addMember(button); main.draw(); } }
The above code will create a simple button with the text “Jump!” on it that, when clicked, will display a modal dialog saying “You first”. We still don’t have a page on which to display this button, though, so we’ll have to create one:
This will create a new GSP view that uses our SmartButton module. The Grails GWT plugin currently puts the GSP page, smart.gsp, in the project’s web-app directory, but that’s no longer the appropriate location (since Grails 1.1 I believe). So, you should move the smart.gsp file to the grails-app/views directory.
grails create-gwt-page smart.gsp org.example.SmartButton
As an aside, you can also create GWT views backed by controllers. If you pass a string of the form <controllerName>/<page>.gsp as the first argument, the command will add the <page> view to the named controller, although you will have to manually add the corresponding action. The command will even offer to create the controller if it doesn’t already exist.
Right, the view has been created and it’s even displaying the button, but it’s a bit like a wireframe view of the button. That doesn’t look good. The problem is that the page can’t find the SmartClient skin files because the CSS link is wrong. You’ll probably also notice that the (wireframe) button is overlaying the Grails logo. Argh!
Let’s address the first problem. SmartGWT assumes that your project follows the standard GWT 1.5 layout. This assumption falls flat on its face with a Grails project, though, hence the incorrect CSS link. To fix the issue, we need to tell SmartGWT where the CSS files can be found. How do we do that? Add the following line to your smart.gsp file:
<head> <!-- Integrate with Sitemesh layouts --> <meta name="layout" content="main" /> <!-- --> <!-- Any title is fine --> <!-- --> <title>Example title (change this!)</title> <script>var isomorphicDir = "gwt/org.example.SmartButton/sc/"</script> <!-- --> <!-- This script loads your compiled module. --> <!-- If you add any GWT meta tags, they must --> <!-- be added before this line. --> <!-- --> <script type="text/javascript" src="${createLinkTo(dir: 'gwt/org.example.SmartButton', file: 'org.example.SmartButton.nocache.js')}"></script> </head> ...
Interestingly (or simply annoyingly depending on your take), you need to remove the leading gwt/ from the isomorphicDir value if you’re using GWT 1.6. I don’t know why, but that’s what you have to do.
Update I have discovered that the standard main.css file used by the default Grails layout doesn’t play nicely with SmartGWT. The best option is probably to modify grails-app/views/layouts/main.gsp by removing the link to main.css. Your SmartGWT application will then look as it should!
The second problem relates the the SmartGWT layout that we use in the example. If you create a VLayout, set it’s height to 100% (via the setHeight100() method, and then call the draw() method, the layout takes up the whole page, even if a Grails layout is applied to the view. The solution involves three steps. First, remove the call to setHeight100() in SmartButton.java. Second, replace the line
with
main.draw();
Don’t forget to import the RootPanel class! The final step is to add a div to the body of the host page, smart.gsp:
RootPanel.get("main").add(main);
<body> <!-- OPTIONAL: include this if you want history support --> <iframe id="__gwt_historyFrame" style="width:0;height:0;border:0"></iframe> <div id="main"></div> <!-- Add the rest of the page here, or leave it --> <!-- blank for a completely dynamic interface. --> </body>
If you’re using hosted mode, just refresh the page to see the final product in action! The modal dialog looks a bit off for some reason, but that can probably be fixed by a SmartGWT aficionado.
Update The modal dialog looks off because of the main.css problem mentioned in the previous update. It also seems that you don’t need to remove the call to setHeight100() – that was probably down to main.css as well.
An idiosyncrasy in the GWT plugin
If you use a normal browser to view the SmartGWT page in all its glory, rather than hosted mode, then you may soon notice that the GWT modules are not recompiled by grails run-app when they are modified. This behaviour is intentional: hosted mode reads the module files directly, so there is no reason to incur the extra time penalty involved with compiling the modules on startup. However, for some reason (that I genuinely can’t remember) the compiled JS files have to at least exist, even if they aren’t the latest ones. That’s why the modules are compiled the first time you run the application.
You might think this leaves you in a bit of a pickle if you use a normal browser instead of hosted mode, but you can easily recompile the modules with the grails compile-gwt-modules command.
Variations on the theme
When you inherit the SmartGwt module, your host page is automatically populated with all the required JS and CSS links for the default skin. You can gain a bit more control by inheriting SmartGwtNoTheme, which allows you to specify a different theme in the host page, or SmartGwtNoScript, which allows you full control over the JS files that are included as well as the theme. The showcase example for SmartGWT demonstrates the use of SmartGwtNoScript – note how much more you have to add to the host page!
That’s it for now. I may do more work with SmartGWT in the future. If so, I’ll post anything I find useful.
Just thought I’d say that I really like your blog – looks great and you have some great examples. Also good to have a high quality grails blog – more good tutorials like this please!
Excellent tutorial, thanks for putting this together.
From my experiance its better not working with SmartClient.
1. SmartClient Components are heavier than its competitors.
2. Event handling is pathetic.
3. There is no concept of Core framework to deal with DOM elements and CSS selectors
4. Memory footprint is several times larger than other frameworks.
5. Very very slow in rendering in browser.
6. Not easy to customize.
7. SmartClient Support will show you an example working with 10 elements when you are asking abt a combo loading 100 -200 elements.
8. Coded before 6-7 years back not really able to complete with current javascript frameworks.
It seems that the “main.css” file used by the standard Grails layout messes up SmartGWT. So if you plan to use SmartGWT then don’t use a layout for your host pages, or use a custom one with your own CSS, or empty out main.css.
@peter Thanks for posting this tutorial. This will get a lot of users past those first critical steps! Apologies in advance for wiping some FUD off your blog..
@jd I’m just going to blow up a couple of your obviously incorrect points to show that the rest can’t be taken seriously.
#7. low data volume examples – the reverse is true. Other frameworks show small amounts of dummy data in samples where we show live database connections with high data volume load on demand interactions. You mention 100-200 elements as though that were challenging, how about:
5000 record autocomplete multi-field comboBox:
http://www.smartclient.com/#listComboBox
50,000 record load on demand OLAP datacube:
http://www.smartclient.com/#analytics
SmartClient.com shows higher data volume, more realistic examples than you will find anywhere else.
[various#] Performance. When it comes to the real-world performance of enterprise applications, SmartClient has a very large lead because of Features like Adaptive Filtering, which eliminate unnecessary server and database trips. This is what we focus on because this is what actually matters for end users in a deployed application. Just try it for yourself.
http://www.smartclient.com/index.jsp#adaptiveFilter
#8. SmartClient wasn’t coded “6-7 years back”, it’s been in continuous development for longer than any other RIA technology. That’s why the 7.0 release has 25 major new features, a majority of which you can only get with SmartClient.
http://www.isomorphic.dreamhosters.com/?p=130
We routinely knock other JavaScript frameworks out of head to head comparisons performed by sophisticated enterprises and ISVs. If you want to see the cutting edge, look at how much these samples do, and with what tiny code:
http://www.smartclient.com/#_Featured.Samples_Server.Examples
the problem in main.css is the padding in
td, th {
font: 11px verdana, arial, helvetica, sans-serif;
line-height: 12px;
padding: 5px 6px; /********************* smartgwt problem*/
text-align: left;
vertical-align: top;
}
Thanks Peter! A friend of mine just mentioned SmartGWT to me and I was wondering if it could be used with Grails. Here’s the answer!
I thought others might find this useful, so I posted it to DZone.
Thanks,
Matt
Great thanks for this post! Our company is using SmartGWT / SmartClient for half a year, and I can say this is wonderfully designed solution for presentation layer with strong data handling. Groovy / grails can additionaly empower our apps and make them more flexible.
Thank you so much for making this tutorial – I’ve been looking for something like this so I really appreciate.
PS: You don’t need an excuse for a pitiful example because its far from pitiful. The ‘getting up and running’ part of any technology combination can arguably be the most frustrating and you’ve saved me and I’m sure others a lot of effort.
Hello, Does exist any tutorial to introduction to smartgwt?
Thank’s all!
Victor
One of Smartclient’s strong points is its ability to bind components with data sources on the server and keep them in sync.
But the one thing that scares me is having to hand code a GUI with statements like
VLayout main = new VLayout();
main.setWidth100();
main.setHeight100();
main.setLayoutMargin(5);
I would so much prefer to use a tool like Atlas and its Cappucino / Objective J framework 🙂
But maybe, it’s possible to do similar binding between Capuccino and Grails ? Any one has tried that couple ?
I have a problem with this tutorial.
I try to do it with smartGWT 2.0 + grails 1.1.1.
When I load the SmartGWT library in the xml file::
I compiled the aplication and I get the error:
Compiling GWT modules …
Module: org.example.SmartButton …
[java] Compiling module org.example.SmartButton
[java] [ERROR] Unexpected
[java] java.lang.OutOfMemoryError: GC overhead limit exceeded
[java] at java.util.HashMap.(HashMap.java:209)
[java] at com.google.gwt.core.ext.typeinfo.MetaData.(MetaData.java:45)
[java] at com.google.gwt.core.ext.typeinfo.JRealClassType.(JRealClassType.java:48)
[java] at com.google.gwt.dev.javac.TypeOracleMediator.createType(TypeOracleMediator.java:519)
[java] at com.google.gwt.dev.javac.TypeOracleMediator.createType(TypeOracleMediator.java:472)
[java] at com.google.gwt.dev.javac.TypeOracleMediator.addNewUnits(TypeOracleMediator.java:372)
[java] at com.google.gwt.dev.javac.TypeOracleMediator.refresh(TypeOracleMediator.java:417)
[java] at com.google.gwt.dev.javac.CompilationState.refresh(CompilationState.java:179)
[java] at com.google.gwt.dev.javac.CompilationState.(CompilationState.java:93)
[java] at com.google.gwt.dev.cfg.ModuleDef.getCompilationState(ModuleDef.java:264)
[java] at com.google.gwt.dev.Precompile.precompile(Precompile.java:283)
[java] at com.google.gwt.dev.Compiler.run(Compiler.java:170)
[java] at com.google.gwt.dev.Compiler$1.run(Compiler.java:124)
[java] at com.google.gwt.dev.CompileTaskRunner.doRun(CompileTaskRunner.java:88)
[java] at com.google.gwt.dev.CompileTaskRunner.runWithAppropriateLogger(CompileTaskRunner.java:82)
[java] at com.google.gwt.dev.Compiler.main(Compiler.java:131)
[java] [ERROR] Out of memory; to increase the amount of memory, use the -Xmx flag at startup (java -Xmx128M …)
[java] Java Result: 1
What can I do to avoid the heap space error ?
Is not problem with the memory needed in the aplication. It’s seems a problem loading the module un SamrtGWT.
Thanks.
If you’re using the latest GWT 0.5 snapshot, you can specify your own JVM args settings in BuildConfig.groovy:
I’ve raised a JIRA issue to ensure that I get the default setting (-Xmx256m) back in.
Hi Peter,
Is GWT 0.5 snapshot plugin stable enough yet for GWT version 2.0. We’re hoping to update our GWT app to GWT version 2.0 but are not sure how well the plugin works it yet. We’re hoping to make good use of the new dev mode.
Thanks!
I’m using that version of the plugin with GWT 2.0 without major problems. There are only a couple of minor issues to clear up before a proper 0.5 release.
Hi! I resolve my configuration error with the parameters of the other post, thank you.
Later I’ll update both, SmartGwt library and gwt-plugin.
Now I have a problem with my aplication that merges grails and smartGwt.
My problem is how can I save an edited listGrid items with a grails order (save, update, delete) inside a grails from to the database using a JSON object extracted from the listGrid.
Grails form contains a layer with the listGrid.
How can I get the values with the id for element in the listGrid?
Or get all the elements into an array.
The listGrid hasn’t got any id tags for each property. When you define the ListGrid you set the name of the values but in the view (gsp) there aren’t.
I don’t know if I’m using the correct widget or if it’s another problem.
Thank you.
Hi,
Any chance you can publish a second short tutorial on how to make Grails and Smartgwt talk (maybe using a restful datasource)?
thanks
I am using grails 1.2.2 with gwt 2.0.0
This page helped me a lot to get everything setup. But I for some reason, couldn’t even get the (wireframe) button to overlay the Grails logo!
I did everything as per the tutorial and I see no errors when I run the app. But irrespective of what I try, no ill-placed wireframe button.
Any idea what could be wrong?
Thanks,
V
Spoke too fast!
I got it sorted out. Was just using a very old browser. Don’t ask me why.
Thanks a ton for the tutorial Peter. It all seems to work well.
Peter,
Thanks for a great tutorial. However, I have a question.
We have a full-fledged GRAILS application. But, at a few places we want to use SmartGWT controls.
e.g. Grid and Menu controls.
In your blog above, you mention, main.css messes up SmartGWT. Now, I can’t do away with my main.css from my layout. The whole page (rather app) is dependant on it.
Does that mean SmartGWT is NO-GO for this situation?
Would appreciate some comments/thoughts from you or anyone else following this blog.
regards,
-Piyush
It’s been a while since I played around with this, but if I remember correctly, the styles in the standard main.css that is created with a new Grails application conflict with the standard SmartGWT styles. That doesn’t mean that SmartGWT is a no go, but you may have to do some CSS debugging to fix any styling problems. I suggest that you introduce elements of SmartGWT gradually to a single page and see whether it all looks good or you need to fix something.
I’ve create a plugin support SmartGWT based on your beautyfull plugin GWT.
hello peter,
Now I use the grails-smartgwt-plugin, I have some questions. Can you give some ideas? Thank you very much.
1.About the domain-class in grails. I read some books about the gwt. On the book, it said that we can use gwt with Hibernate, but the POJO must be define in the Client.
In the Grails, the POJO called Domain, such as the Class–User. If just “grails create-domain-class com.test.User”. And the Use.groovy locate grails-app/domain/com/test/, so we can not use the User in the gwt client. Am I right? If I add an expose property to the User.groovy. It works?
How about “grails create-domain-class com.test.client.User”? It works?
I have used the DTO plugin to “expose” domain classes to my GWT client. The plugin can generate the Java classes from your domain classes and it adds some methods to go from DTO -> domain class and back again.
Gilead is an interesting approach that proxies your domain classes, but as far as I can tell, it will only work with Java domain models (using JPA annotations or Hibernate mapping files).
hello peter,
I have a service called org.example.service.UserService.groovy.
package org.example.service
class UserService {
static expose = [ ‘gwt:org.example.service.client’ ]
//static transactional = true
def test() {
println “test!”
return new String(“AAA”)
}
}
I used the command “grails generate-gwt-rpc”, and I got the org.example.service.client.UserService.java and org.example.service.client.UserServiceAsync.java.
In the SmartButton.java I used the client.UserService as flows:
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.example.service.client.UserServiceAsync;
import org.example.service.client.UserService;
…..
public void onClick(ClickEvent evt) {
// SC.say(“You first”);
UserServiceAsync userService = (UserServiceAsync) GWT.create(UserService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) userService;// Note the URL where the RPC service is located!
String moduleRelativeURL = GWT.getModuleBaseURL() + “rpc”;
endpoint.setServiceEntryPoint(moduleRelativeURL);// Call a method on the service!
userService.test(
new AsyncCallback(){
@Override
public void onFailure(Throwable caught){
}
@Override
public void onSuccess(Object result){
SC.say(“You jjjjjjjjj”);
}
}
);
}
});
…
My SmartButton.gwt.xml is:
When I run the “grails compile-gwt-modules”,it said “No source code is available for type org.example.service.client.UserServiceAsync;did you forget to inherit a required module?
No source code is available for type org.example.service.client.UserService;did you forget to inherit a required module?
It take me 2 days for this question? And I can not solve it. Can you tell me the reason?
by the way, now I use grails 1.3.1 and STS 2.3.3M1.
Thank you very much!
My SmartButton.gwt.xml is:
My SmartButton.gwt.xml is:
inherits name=”com.google.gwt.user.User”
inherits name=”com.smartgwt.SmartGwt”
inherits name=”com.smartgwt.tools.SmartGwtTools”
servlet path=”/rpc” class=”org.example.service.UserService”
entry-point class=”org.example.client.SmartButton
source path=’client’
@oriental Your service is in a different package to your module. Try putting UserService directly in the org.example package, i.e. drop the ‘service’ sub-package. If that works, you know the package is the problem.
The package rules for GWT have caused me all sorts of grief in the past. Unfortunately, I’m a little rusty in GWT so I don’t know what the best solution for you is. I think putting the shared classes into org.example.client.service will work. That just means a bit of refactoring after generating the interfaces.
hello,Peter.Thank you.En,I find out the problem–“service is in a diffferent package”,I tried many ways. And one way is just you said “drop the ’service’ sub-package.”
“putting the shared classes into org.example.client.service “–can I understand changing the package “org.example.service.client” to “org.example.client.service”?
Yes, org.example.service.client -> org.example.client.service
As I said, I can’t guarantee that will work, but from memory it should.
It works,very good.it supports sub-package. The pacakge name of SmartButton.java is part of the pakage name of the service.But the order must be correct.So if the service package name –“org.example.service.client” and the SamrtButton package name is “org.example.client”, It will not work,even though config the source path=’xxxxx’ in the SamrtButton.gwt.xml.
hello,peter.
If I do not use the DTO plugin,so the domain class can not use in the gwt client.Such as in a Form, and it hava some Fields,how to package the fields to the server,with the form.SetAction() method or rpc ?
I see “this is used only in the very rare case that a form
is used to submit data directly to a URL. Normal server contact is through RPCManager” from the DynamicForm.java.
can i use the json to package the fields,can I use the rpc?
how to do?
I have some questions, who can give me some advice? Thank you very much.
1>Generally, if we use the data widget of smartgwt(or gwt), such as the ListGrid, the communication manner what we use is ? rpc or dataSource.
2>If we use the dataSource(dataSource.setURL(“http://localhost:xxxxxxxx/getList”)), does the smartgwt support the lazy Loading? Such as in a ListGrid, once the scroll bar move, can the data load automatically form the server?
3>if not support the lazy loading, how to do ? We write some cods in the server to implement it, or make some Pag(Previous,Next)?
4>If I write my code like the http://www.smartclient.com/smartgwt/showcase/#grid_databinding_lg_fields,
and get the data by rpcService. it will be ok? Does it support lazy loading? or make some Page(Previous,Next) by myself.
5>If we submit a Form(such as “id”,”name”,”age”,”sex”), now I have two manners.
a. by the BuildRequest
JSONObject jsonObject = new JSONObject();
jsonObject.put(“name”,new JSONString(form.getValue(“name”).toString()));
…..
request.sendRequest(json.toStirng(),…)
b. by the rpc
User user = new User();
user.setName(form.getValue(“name”).toString())
……
userService.add(user)
……
Generally, which is the better?
6> when we add/delete a record, how the ListGrid automatically refresh? By what manners.
Who can tell me the answer and give some example code? Thank for your help.
@Peter
I’m having troubles using the DTO plugin and GWT when I use the DTO classes in the cleint code I get the following ERROR while compiling or running in debug mode:
No source code is available for type grails.plugins.dto.DTO; did you forget to inherit a required module?
Adding Does not help. What am I missing here?
And how do I go from DTO back to domain class again?
Pingback: My Notebook » Grails and smartgwt
It would be nice if Grails dependency management could be used instead of manually download SmartGWT jar and configure classpath.
This is just a two step config at BuildConfig.groovy:
1) Add SmartGWT mavenRepo
repositories {
// …
mavenRepo “http://www.smartclient.com/maven2”
}
2) Add SmartGwt dependencies:
dependencies {
compile ‘com.smartgwt:smartgwt:2.4’
compile ‘com.smartgwt:smartgwt-skins:2.4’
}
But this don’t work with run-gwt-client hosted mode
This thread:
http://groups.google.com/group/grails-gwt/browse_thread/thread/6a7fc0705fe66a13
suggests the plugin will only work with “lib dir” approach, ignoring Grails dependency management.
Are there any updates about this issue?
Best regards,
For including this in Mac OSX and IntelliJ make sure to check out:
http://buchmann.info/grails-and-gwt-in-intellijs-idea-not-a-valid-gwt-installation-error
I thought I’d let you know that your post was one of the starting points for writing a plugin to SmartGWT. I wanted to get all of it’s server-side features (no DTOs needed, etc). Feel free to take a look: http://blog.isomorphic.com/?p=346
Pingback: Grails and smartgwt « My Notebook
From Spain, thank you very much for this article.
You help me very much.
Regards
@Peter
I tried this tutorial, but am not able to see the button in the page, only Grails logo is displaying. I don’t see any errors in the Eclipse console either. Any help will be greatly appreciated.
I’m running Eclipse v4.2 (Juno), GWT Grails plugin v0.7.1 and SmartGWT Grails plugin v0.2.
Gnanam,
It’s been a while since I worked with this stuff. First, try running the application from the command line rather than Eclipse. Second, try the example without the SmartGWT plugin.
Your problem is probably due to either the SmartGWT plugin or a newer version of the GWT plugin. And don’t forget that GWT itself has gone through many versions itself since this blog post.
Cheers,
Peter
@Gnanam
The smartclient smartgwt plugin only works with Grails versions prior to 2.0. For further info have a look at
http://forums.smartclient.com/showthread.php?t=20142&highlight=grails+smartgwt