Modules and HTML

36 views
Skip to first unread message

Jeff Bolle

unread,
Mar 19, 2007, 10:49:27 AM3/19/07
to Google Web Toolkit
I hate to bring this up again, but it seems every discussion on
modules devolves into one of application structure. Let me say right
off the bat, if I can do what I would like to do without multiple
modules and HTML pages I'd love to. However, here is my design
problem:

Main page (dataApp.html, loaded as a single module, single entry
point) is the main application I am running.

In a variety of views I would like to give the user the option of
"popping out" the current data detail view, much the same way that
GMail allows you to pop out the e-mail composition window. I would
like to retain the full and normal use of the classes and
functionality in the popout window. Basically, I want to load a
class, ExternalViewer, in the popout window. I am not looking for a
panel within the root window, but a true separate browser window.

Any help or pointers as to where to read would be much appreciated.

Thanks in advance,

Jeff

Dan Morrill

unread,
Mar 19, 2007, 12:44:48 PM3/19/07
to Google-We...@googlegroups.com
Hi, Jeff!

I suspect that the reason for module discussions always coming down to multiple HTML pages is that there is simply no way to do what you are trying to do without multiple HTML pages.

The problem is that in JavaScript, window.open() requires a URL.  You can give it a blank URL, but if you do then some browsers treat that as a document loaded from a different domain, and then prevent you from accessing its contents.  This is a show-stopper, and prevents us from reliably setting innerHTML, "exporting" classes or data from the parent window into the child window, or even from driving the child window from JavaScript code running in the parent.

The only way to achieve multiple browser windows is to call window.open() with a URL pointing to an HTML page, so that the browser loads the page from the same site as the parent host and therefore grants access to the new window's internals.  Since you have to load a second HTML page anyway, the most natural solution is to simply have that HTML file load its own GWT module and begin running.

So, we are sort of led by the nose to this situation where multiple JS windows must have multiple HTML files, and multiple HTML files might as well each load a GWT app.  Hopefully that explains why we keep citing this as the best solution for your situation.

All that remains is establishing a way to pass messages between the two GWT modules running in the two windows.  There are several different ways to do this; I can follow up with some details if you are interested.

- Dan

Jeff Bolle

unread,
Mar 19, 2007, 1:15:34 PM3/19/07
to Google Web Toolkit
Dan,

Thanks, that is what I had learned from reading the previous
discussions. I guess my question then becomes how do I associate
multiple HTML pages with one GWT app? I assume this has to be done
with multiple modules and multiple entry points. I think I may have
had this solution working, but the development environment didn't seem
to work well, ie, it would only compile and run one module/entrypoint
at a time and for me to test if it is actually working both need to
work at the same time.

I am hesitant to load my entire application again and do a check to
see if it is running in the popup window, as it is rather huge (my
gwtOutput folder is 5.62MB).

After passing the initial object to display in the popup window, most
of the client interaction takes place over an RPC link. Thus, I'm not
too worried about sending messages back and forth between the two
windows. I would think from the perspective of development and
maintenance, having everything in the same application and accessing
the same set of common widgets would be optimal.

The list of things I'm stuck on:
1. Setting up GWT to handle multiple entrypoints and having one of the
modules load the other one
2. Sending the initial data item to the new window to be popped out.
3. Having the development and build environments handle the
interaction of multiple modules smoothly for testing.

Jeff

Dan Morrill

unread,
Mar 19, 2007, 2:16:01 PM3/19/07
to Google-We...@googlegroups.com

Hi again, Jeff!

On 3/19/07, Jeff Bolle <jbo...@gmail.com> wrote:
I think I may have had this solution working, but the development environment didn't seem
to work well, ie, it would only compile and run one module/entrypoint
at a time and for me to test if it is actually working both need to
work at the same time.

Well, it can definitely be made to work in hosted mode, but it can be a little... quirky.  Before we go there, though, I have an alternate suggestion that you may find easier to set up.

Before I get to your actual questions, I think it might be useful to provide some background first.  Specifically, how this notion of a GWT Module relates to the bootstrapping process.  Forgive me if you've already worked through all this -- I'm writing this as much for other interested readers as for your specific question. :)

A Module in GWT really just boils down to some metainformation about some Java classes.  Its primary purpose is to tell the GWT tools where to find the Java classes that make up an application, which classes are "EntryPoints" to the module, and what the module's name is.

This information is consumed by the bootstrapping process, as well (or more accurately, it's "baked in" to the JavaScript generated by the compiler.) Each Module amounts to a separate GWT application, and (except in a few exotic cases) has its own bootstrap phase.  Each Module, however, can specify multiple EntryPoints.

An EntryPoint, of course, is a class implementing the EntryPoint interface, and defining the onModuleLoad() method.  When the Module loads, each entry point's onModuleLoad() is executed.  This means that if you wanted to, you could have 5 EntryPoints in a single Module, where each does some portion of the overall work.  Most applications have a single EntryPoint, but they can have more.

So, if you have a GWT module named Foo (and defined in a Foo.gwt.xml file) in a parent window, then to implement a child window, you can either:
  • Write a new module called Bar that has a different entry point but may share classes with Foo
  • Add a second entry point class to Foo that implements your child window behavior
The first approach (which I believe is the one you're currently considering) will result in two totally independent applications, with duplication of any classes shared between the two.  If your app is large and the two windows have lots of shared classes, this may be a problem.

The second approach, though, will load the same module all over again in a different window.  Since most of GWT's files are static, this will mean that they will be cached by the browser and so the child application should load quickly.  The only obstacle here is that all EntryPoint classes will be fired whenever the module loads, meaning that your child EntryPoint will be called when the parent loads, and the parent EntryPoint will be called when the child loads.

Fortunately, this is easy to surmount.  One way to do it is to structure your HTML like this:
<html>
<body>
<div id="parent"> <!-- change to id="child" for the child HTML file -->
</div>
</body>
</html>

Meanwhile, your parent's onModuleLoad would do a RootPanel.get("parent") and your child's would do a RootPanel.get("child").  That method returns null if the requested ID is not present in the page, giving you an easy way to test for the mode in which your Module has been called.  Your parent and child host HTML pages then just set the appropriate 'id'.  The parent EntryPoint does nothing if the mode is child, and vice versa.

So in other words, you can structure your single Module to have a separate EntryPoint for each possible window that can appear.  Then, you just have to add a small hook to each onModuleLoad() to have it test for whether it should actually do anything.

The only other thing to be aware of here is that even though they loaded from the same files, the two GWT application instances in the two windows will be entirely separate -- as if you'd run the same C program twice.  That is, they won't share Java static members, and so on.  You'll have to keep that in mind when designing your EntryPoints, and possibly build some infrastructure to communicate between the browser windows, if you need to do so directly.  (It might be possible to do everything you need to via RPC/server calls.)


Hopefully that all made sense.  If you'd like to see a small toy example of this technique, I'd be happy to post one.

All that said, here are my answers to your specific questions:


The list of things I'm stuck on:
1. Setting up GWT to handle multiple entrypoints and having one of the
modules load the other one

If your individual windows are large and have class sets that are highly orthogonal (that is, few shared classes) then multiple modules are probably the way to go.  Otherwise, it's probably more efficient to go with the multiple EntryPoints method I outlined above.


2. Sending the initial data item to the new window to be popped out.

If your initial data is small, one approach is to make the page launching the child be a JSP (or other dynamic page) and pass the data you need in GET parameters in the URL you pass to window.open().  (The JSP would then embed the data in the page in some fashion that is convenient for your GWT code to access.)  If you have lots of data, you could store the data on the server associated with the browser session, and then when the child EntryPoint loads have it immediately issue an RPC request to fetch that data. 


3. Having the development and build environments handle the
interaction of multiple modules smoothly for testing.

If you go with the multiple-EntryPoint method, this may not be a problem.  If you do decide to go with the multiple-module approach, then there would indeed be some configuration.  However at that point, you are probably better off using the -noserver mode instead of hosted mode's embedded Tomcat.  By that I mean:  I can tell you how to make it work in hosted mode's embedded Tomcat, but it's weird enough that you are probably better off just using your own external server.  (If you would like to know anyway, feel free to ask.  I just figured this email is long enough already. :)


Hope that helped!  Fire away with any questions you still have.

- Dan

Jeff Bolle

unread,
Mar 19, 2007, 2:54:37 PM3/19/07
to Google Web Toolkit
Dan,

Thanks so much for this. You have really helped enlighten me as to
the functional underpinnings of the toolkit.

The solution with multiple entry point and the check for parent or
child is exactly the combination I was looking for. I will use RPC
calls to handle the data transfer (not hard at all in my case as I am
already doing a lot with session management and session user data
persistence).

Thanks for the note about not sharing even static classes, that is
definitely good to know!

Thanks so much for your help on this, I really appreciate it.

Jeff

> - Write a new module called Bar that has a different entry point but


> may share classes with Foo

> - Add a second entry point class to Foo that implements your child

Jeff Bolle

unread,
Mar 19, 2007, 3:28:01 PM3/19/07
to Google Web Toolkit
Dan,

Thanks so much for this. You have really helped enlighten me as to
the functional underpinnings of the toolkit.

The solution with multiple entry point and the check for parent or
child is exactly the combination I was looking for. I will use RPC
calls to handle the data transfer (not hard at all in my case as I am
already doing a lot with session management and session user data
persistence).

Thanks for the note about not sharing even static classes, that is
definitely good to know!

Thanks so much for your help on this, I really appreciate it.

Jeff

> - Write a new module called Bar that has a different entry point but


> may share classes with Foo

> - Add a second entry point class to Foo that implements your child

Dan Morrill

unread,
Mar 19, 2007, 4:31:57 PM3/19/07
to Google-We...@googlegroups.com
Heh... no problem at all, Jeff!

We're trying to get this kind of info moved into the Knowledge Base so it's not trapped in our heads.  We'll get it all in there eventually. :)

- Dan

> your child's would do a RootPanel.get ("child").  That method returns null if

Ian Bambury

unread,
Mar 19, 2007, 5:02:56 PM3/19/07
to Google-We...@googlegroups.com
Jeff,
 
I'm just going to stick an oar in here...
 
There's no reason why you can't have two different HTML pages run the same GWT app (thereby not having to load a different cache.html file) but reacting in different ways.
 
If your standard index.htm page opened another (pop.htm) page and passed it a querystring, then pop.htm could just display the widget you wanted with the data you passed it. This would have to be relatively simple data, of course.
 
You could also have pop.htm go and get data from the index.htm window, or for that matter, great chunks of the DOM. The only problem with that is that you will lose clicklisteners and similar effects and have to rebuild them, since (obviously) the clicklistener isn't all that available in the popped up window.
 
I've tried this and it works. http://write.roughian.com  uses this principle (albeit with iframes) to add to the parent DOM. Above the 3px blue line is the main page, below is in iframes. I'm still adding loads of text to this so it's not all there, but if you go to, say, Act I, and click an item in the side menu ( i.e. in the iframe), it changes a field in the index.htm (parent) frame. It could just as easily fetch data as send it.
 

Jeff Bolle

unread,
Mar 20, 2007, 9:08:48 AM3/20/07
to Google Web Toolkit
Ian,
Thanks for the alternative solution. I implemented the multiple entry
point design pattern yesterday and everything is working exactly how I
would like. It was a relatively quick and painless solution to my
problem. I have a very specific widget with limited functionality and
no need to communicate back to the initial window. Additionally, I
have highly developed session handling code and lots of RPC calls, so,
really, everything in my application happens between the server and
the client (as opposed to client window 1 to client window 2), no
matter which client window is doing the communicating things aggregate
and come back perfectly. The load times aren't bad either, but that
may be a result of gigabit ethernet and relatively quick machines.

Thanks again for the help.

Jeff


On Mar 19, 5:02 pm, "Ian Bambury" <ianbamb...@gmail.com> wrote:
> Jeff,
>
> I'm just going to stick an oar in here...
>
> There's no reason why you can't have two different HTML pages run the same
> GWT app (thereby not having to load a different cache.html file) but
> reacting in different ways.
>
> If your standard index.htm page opened another (pop.htm) page and passed it
> a querystring, then pop.htm could just display the widget you wanted with
> the data you passed it. This would have to be relatively simple data, of
> course.
>
> You could also have pop.htm go and get data from the index.htm window, or
> for that matter, great chunks of the DOM. The only problem with that is that
> you will lose clicklisteners and similar effects and have to rebuild them,
> since (obviously) the clicklistener isn't all that available in the popped
> up window.
>

> I've tried this and it works.http://write.roughian.com uses this principle


> (albeit with iframes) to add to the parent DOM. Above the 3px blue line is
> the main page, below is in iframes. I'm still adding loads of text to this
> so it's not all there, but if you go to, say, Act I, and click an item in

> the side menu (i.e. in the iframe), it changes a field in the
> index.htm(parent) frame. It could just as easily fetch data as send
> it.
>
> Ianhttp://examples.roughian.com

Reply all
Reply to author
Forward
0 new messages