Duplicating the <g:tab> element of GWT's TabLayoutPanel - gwt

I've found the GWT tab panels clunky for the styling I need to do, so I'm trying to make my own, simple tab panel. Basically an HTML5 <nav> element for tabs and a DeckPanel to display the content. Let the use figure out the rest with CSS3.
The GWT TabLayoutPanel has these "special" tags it uses to define the contents of a tab:
<g:TabLayoutPanel>
<g:tab>
<g:header>Tab Title</g:header>
<g:OtherWidget>Tab contents</g:OtherWidget>
</g:tab>
</g:TabLayoutPanel>
I'm referring to <g:tab> and <g:header>. I see these type of tags used in various places but I have no idea how to create them. Looking at the TabLayoutPanel source, I see that it has an add method that expects two widgets, and from that it puts one widget (the contents) into a panel for display and another (the header) into an instance of TabLayoutPanel.Tab. But I have no idea how to duplicate this kind of functionality.

In GWT 2.1 there's the UiChild attribute. It's quite cool.
#UiChild public void addTabDef(Widget page, String title) {...}
The title parameter will be filled with an attribute of the same name in the tabdef tag, like so:
<v:tabdef title="Tab one"><g:Label>Page one.</g:Label></v:tabdef>
Edit: to be clear, tabdef isn't defined anywhere as a class; the desired behaviour during parsing is defined by UiChild attribute.

To use custome tags for you widget like <g:tab> and <g:header> you need to create a custom ElementParse and register it with the UiBinderWriter. Unfortanatly there is no simple way of doing this yet without editing the sourcecode for gwt.
Usefull links:
A link to the issue of not being able to create custom ElementParser
TabLayoutPanelParser

Related

Getting an element defined in a core:html by its ID

I used this line to define a canvas element in my view.xml:
<core:HTML content="<div class="wrapper col-6"><canvas id="
myChart"width="800"height="400"></canvas></div>">
</core:HTML>
Now I want to get the element in the controller but the typical this.getView().byId("myChart") doesn't seem to work even though the site successfully loads a canvas with the ID.
Is there a way to get those types of elements defined inside a core:HTML tag for the controller?
If not, is there a different way to create a canvas or other HTML elements so that I can refer to them with an ID / use them in the controller?
The element created in this way is not 'registered' in UI5 framework like the other controls. byId() only checks the internal register.
You can use jQuery or standard JavaScript to fetch the element though, like $('#myChart') or document.querySelector('#myChart').
You will find the code for this in Core.js or Core-dbg.js.
Like Jorg said, byId is for retrieving controls. So if you were to put an id on the HTML control, you could retrieve that control and then call getDomRef() on it to get the outermost element, which in your example would be the div. If you'd further only put the canvas inside the HTML control, you'd get that.
If you're accessing the id of the canvas directly, like Jorg suggested, you'll run into trouble if you're going to use the view twice inside a page, because the id of the canvas isn't unique anymore.
There is a third and IMHO preferable option, that is to use html directly inside the view. First you'll need to declare a namespace for it, like
xmlns:html="http://www.w3.org/1999/xhtml"
preferably right on your View element.
Then you can write html directly in your xml view like this:
<html:div class="wrapper col-6">
<html:canvas id="mycanvas" width="800" height="400"></html:canvas>
</html:div>
This way you're getting a proper (unique) id for your canvas and can access it as part of the view's dom with this.getView().getDomRef("-mycanvas"). Note the extra leading dash, because of internal id generation inconsistency in UI5. Also note that getDomRef() is considered protected, but I doubt it will change. Finally, remember that you can only get a domref for rendered controls, so you'll probably want to access it from an afterRendering event.

ZK framework - no content in include

We have a tabbox whose tabpanels use include to include content:
<tabpanels height="100%">
<tabpanel>
<include src="#load(vm.myTabUrl)" />
</tabpanel>
...
</tabpanels>
Once in a while in production, the content of the include is not displayed. This behavior seems to be random and we don't know how to replicate it.
When it happens, the generated html contains a <div> for the include which only contains another empty <div> with class z-tmp:
ZK doesn't show any errors while rendering and neither does the javascript console. Also there are no failed http (zkau) requests. Any ideas?
ZK Client Engine is responsible for conversion of ZUL to HTML at client side.
ZK has a huge in-built component support compared to HTML. But the things that are displayed on Client side will be HTML itself.
We design a page in ZUL and it is converted into HTML in action. ZUL Components are larger than HTML components in number but in the end we get HTML components only with some changes in their structure.
How the ZUL page reconstructed to HTML page ?
ZUL page are converted to Div, input, anchor mostly.
ex: Groupbox
(ZUL) --> Multiple Div (HTML)
The ID of the DOM components are dynamically generated after conversion like z_p5,z_g3 and the ID
i.e given in ZUL page can be added at AID of the Component.
The DOM component can be allowed to have multiple styles separated
by spaces.
The Widget name is added to the component style as z-widget along
with our regular styles mentioned in ZUL page. The ZK Component name is added as z-widget in the style attribute of generated HTML DOM Component. As you have already seen that z-include is added in the style attribute of Div element in the above screenshot after generation
of page.
Coming to the Actual problem,
Open the AfterCompose method of the ViewModel of this page.
Assign myTabUrl directly with another ZUL page path and Notify it with
postNotifyChange method from below.
BindUtils.postNotifyChange(null, null, ClassName.this, "myTabUrl");
May be Variable is not properly assigned or Notifying the variable may be missed which caused this problem. If possible post the ZUL and VM code here if problem still not resolved after this trial.

gwtbootstrap always applies to all elements

I want to use GWT bootstrap for my application, so I added the jar to the classpath and inherited it in app.gwt.xml and it is working so far (I am new to Bootstrap).
So far I haven't used UIBinders for the layout and if in any way possible would like to leave it that way as I have a very dynamic UI which is generated programmatically and I have little experience with UIBinders. However for the elements that I want to use from gwtbootstrap I have created UIBinders (such as headings and buttons).
The problem is that not only the elements I create with UIBinders using the gwtbootstrap elements look like gwtbootstrap elements, but all elements on the page.
A simple example: it makes no difference whatsoever if I create a Heading like this using a bootstrap element
<b:Heading size="2">Hello GWT Bootstrap</b:Heading>
or like this using standard HTML
<h1>Hello GWT Bootstrap</h1>
both look like a GWT Bootstrap heading. The same applies for all other elements, so any element on the page is styled by gwtbootstrap, even if I don't want it to and I can't find a way to control this.
That's because gwt-bootstrap injects the bootstrap.css into your GWT app and bootstrap.css defines default styles for standard HTML elements like <h1>, etc.
If you don't want bootstrap to override the default styles there are several solutions:
Modify the bootstrap.css in the gwt-bootstrap library file and remove the styles that you don't want
Create a separate css file that sets the styles for the specific HTML elements back (using !important)
Extends gwt-bootstraps CssResources and pass a custom css file.
Solution 3 is probably the cleanest one.

how to create a master page or a page which is in common to all the views using gwt mvp

Hi I am new to GWT MVP pattern. I am from asp.net background and currently I am working on GWT and I am asked to create a Master page which has the menu items which should be in common to all the views. Initially I created a sample mvp project using https://developers.google.com/web-toolkit/articles/mvp-architecture-2 and in that there is navigation from one view to another. How do I maintain one view constant and keep changing the other views depending on what menu item we click. Please help
The article you mentioned is from before MVP support added in GWT. It's good at explaining the concept, but the actual implementation is less useful. To continue take a look at the GWT documentation about activities: https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces . There you will also find the solution for your problem. In brief, take a look at the ActivityManager. This manages all activities. On the activity manager you set one widget that will be static for all activities. This widget must have a method setWidget (actually it must implement AcceptsOneWidget). In each of your activity implementations you get this widget via the start method. And by calling setWidget with the specific view for that activity in the start method you set the activity specific view. This is all described very briefly, but you should get the concept if you read the mentioned documentation.
If you are working with UiBinder, your ui.xml file should be like this,
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
</ui:style>
<g:DockLayoutPanel unit="EM">
<g:north size="4">
//Add Logo, menus or what you want to be displayed for all the pages
</g:north>
<g:center>
//Add code for your desired UI. In java code you change the UI by this "flowpanel"
For eg: <g:FlowPanel ui:field="flowpanel" />
</g:center>
</g:DockLayoutPanel>
Then everytime you can clear and add the widgets to be displayed in the view in the <g:center> using your java code like this flowpanel.clear();
flowpanel.add(anyWidget you need).
So <g:north> will be static view and <g:center> will be dynamic view. Now you will get the page as you desired. Since you can change everytime your view on <g:center> only.
Like this you can add <g:east>, <g:west> and g:south> if required.
If you are not working with UiBinder then do everything in your java code as follows,
final DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Style.Unit.EM);
dockLayoutPanel.addNorth(any widget you need, "4"); //NorthPanel
dockLayoutPanel.add(any widget you need); //CenterPanel
Where "4" is the size of the panel, you can change it.
Like this dockLayoutPanel.addWest(any widget you need, "4"); //WestPanel
dockLayoutPanel.addEast(any widget you need, "4");//EastPanel
dockLayoutPanel.addSouth(any widget you need, "4"); //SouthPanel
I hope you got idea now.
You divide your screen into two or more areas, and assign dedicated ActivityMapper and ActivityManager to each zone. For example, one zone can be "menu" with MenuActivityManager, and the other zone "body" with BodyActivityManager.
Here is a good explanation:
http://blog.ltgt.net/gwt-21-activities-nesting-yagni/
Note that there are both pros and cons for using this method. Browsers take milliseconds to render standard html. It may be easier to create a widget mainMenu and include it (best of all, using UiBinder) into every view, rather than deal with two activity managers.

Link-widget GWT - uiBinder

I want to use a link or a button like (a href="..."/>) in GWT with uiBinder.
I found the widget "hyperlink" but I donĀ“t know how I use that.
You should use the Anchor widget.
You can use a sample ClickHandler on it to detect the click event or use the default href with the constructor :
Anchor(boolean useDefaultHref)
You can also use the setter setHref(java.lang.String href)
In UiBinder :
<g:Anchor ui:field="mylink" href="/myurl">The link test</g:Anchor>
EDIT :
To open the link in a new tab, you should use the setTarget(String target) method like the following example :
setTarget("_blank");
Unless you need to programatically do things with the anchor, you can just add the html into the uibinder code directly. In fact, UIBinder is not just a WYSIWYG, but it is a place for you to enter as much native HTML as you can. That makes for leaner and faster web apps.