local script variables in nocache.js

58 views
Skip to first unread message

bconoly

unread,
Feb 2, 2011, 8:16:52 AM2/2/11
to Google Web Toolkit
Hey All,
I'm using GWT in portlets and I've run into a unique circumstance
where I have an instanceable porltet being placed multiple times on
the same page. Currently the url that I use to make my RPC calls is
set as a global variable in the page and with 2 or more instances on
the same page they overwrite each other allowing only one to work.

I had an idea of pulling the nocache.js file into my velocity
template so I could place the url variable in it so it is scoped
locally but I need it as part of the compile. Is there any way I can
place a variable into the nocache.js that will be local to each
instance of the script running? And if so, how do I get access it
inside the GWT execution context?

Thanks in advance,
Brett

bconoly

unread,
Feb 3, 2011, 8:35:20 AM2/3/11
to Google Web Toolkit
If it helps any I need the following:

nocache.js:
this.resourceUrl = "$resourceUrl";

GWT jsni:
/**
* Returns the resource url set in nocache.js after it has been
replaced by the template.
*/
private native String getResourceUrl /*-{
return resourceUrl;
}-*/

Thanks

Colin Alworth

unread,
Feb 3, 2011, 11:13:00 PM2/3/11
to google-we...@googlegroups.com
In your *.nocache.js content, you say you will have 'this.resourceUrl = "content-replaced-by-velocity";' – what is 'this' in this context? If it is the shared window that all the portlets use, they will each overwrite the resourceUrl property. If each portlet will use a different module, you could use modulename to set and access this data. This could look something like
window.MyModuleName.resourceUrl = "$resourceUrl"
and then access it in your native method with
return $wnd[@com.google.gwt.core.client.GWT::getModuleName()()].resourceUrl;


If I have misunderstood and each portlet is in its own iframe, then your native call just needs to say 'return $wnd.resourceUrl;' to correctly reference the window object that the resourceUrl was set in.

Hope this helps,
Colin

Brett Conoly

unread,
Feb 4, 2011, 8:17:39 AM2/4/11
to google-we...@googlegroups.com
Unfortunately that won't work, the portlets aren't in their own frames but they're loaded twice.  And the problem with using module name to distinguish them is that they both have the same module name but different resourceUrls.  The only solution that I think may work is having velocity replace a local JS variable in the nocache.js.
Thanks

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Colin Alworth

unread,
Feb 4, 2011, 10:03:09 AM2/4/11
to google-we...@googlegroups.com
Actually, this suggests that another fix will work better, and will improve overall performance. Loading the exact same module twice onto the same page means loading the same nocache.js, which will try to trigger the same iframe to be loaded with the actual module's contents, which will then execute the exact same code – Why not just do this once, and write the module to expect to be loaded twice? This way, the module will expect to run multiple times, and will expect to have multiple elements to write content into, as well as matching resourceUrls.

Also: the default IFrameLinker that GWT uses is set up in such a way as to not load the iframe until everything else on the page has loaded. If you are using a different linker, there might be other issues here, but I believe that *.nocache.js is the IFrameLinker's way of doing things.

Something like this: in your page js, build up a map from divid to resource url
var appResources = {'portletContainerId1':'http://resource.com/url1','portletContainerId2':'http://resource.com/url2'};
...
<div id='portletContainerId1'></div>
...
<div id='portletContainerId2'></div>

Then, in your java code, loop through all keys in $wnd.appResources, init'ing the app for each div and matching url. If there is additional info, the map can be string:object, with the object containing your other details.

Depending on how your velocity stuff is wired up, this can also be expressed:
var appResources = {};
...
<div id='portletContainerId1'></div>
<script type="text/javascript">appResources['portletContainerId1']='http://resource.com/url1';</script>
...
<div id='portletContainerId2'></div>
<script type="text/javascript">appResources['portletContainerId2']='http://resource.com/url2';</script>

Your java will look something like this then - instead of onModuleLoad being responsible for bringing up the portlet, let some other method or class deal with that, and let onModuleLoad figure out what has to be done to start the page:
public void onModuleLoad {
  interface PortletHandler {
    void startPortlet(String portletId, String resourceUrl);
  }
  class DemoPortletHandler implements PortletHandler {
    public void startPortlet(String id, String url) {
      Window.alert("Portlet in " + id + " started with url " + url);
    }
  }

  forEachPortlet(new DemoPortletHandler());
}
private native void forEachPortlet(PortletHandler handler) /*-{
  for (var id in $wnd.appResources) {
    handler.@package.client.ThisModule.PortletHandler(Ljava/lang/String;Ljava/lang/String;)(id, $wnd.appResources[id]);
  }
}-*/;

Please note that I am typing this all out freehand, so I might've messed up the jsni signatures, but this should provide a usable link between your page and your code. 

Hope this helps, 
Colin
Reply all
Reply to author
Forward
0 new messages