I want to add a button to the HeaderSpan of ListGrid in SmartGWT. I tried using the 'HeaderSpan.setAttribute((String property, Object value)) method but it did not work. Below is the example I tried with:-
ListGrid countryGrid = new ListGrid();
HeaderSpan ident = new HeaderSpan("Identification", new String[]{"countryCode", "countryName"});
ident.setAttribute("control", new Button("Test"));
countryGrid.setHeaderSpans(ident);
countryGrid.draw();
Please help!
Finally I found the way to add button to a HeaderSpan. Below is the code (Have omitted import statements for brevity):-
public class AdvancedListGrid extends ListGrid {
public void setHeaderSpanButtons() {
this.getAttribute("headerSpans");
NodeList<Element> list = this.getElement().getElementsByTagName("td");
int length = list.getLength();
for(int index = 0; index < length; index++) {
Element element = list.getItem(index);
if(element.getInnerHTML().toString().equals("Identification")) {
element.setInnerHTML(null);
element.insertFirst(createHeaderSpanContents());
}
}
}
private Element createHeaderSpanContents() {
HLayout hLayout = new HLayout();
Button button = new Button("+");
button.setHeight(20);
button.setWidth(20);
button.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event) {
SC.say("Why did you click me?");
}});
Label title = new Label("Test Title");
title.setWidth(70);
title.setHeight(20);
hLayout.addMember(button);
hLayout.addMember(new LayoutSpacer());
hLayout.addMember(title);
return hLayout.getElement();
}
}
The client class will call the AdvancedListGrid.setHeaderSpanButtons() method to add buttons to the header span. Of course you can customize the method to meet your needs.
I'm testing it, as I need to put a Calendar in a HeaderSpan. Thanks for sharing your idea, it's of great help, although it took a while to set the correct imports.
A note : the setHeaderSpanButtons() method will only work if the datasource of the ListGrid is set. If it's not, no header at all is shown.
An improvement : you can add a break in the loop, no need to loop the whole NodeList:
if(element.getInnerHTML().toString().equals("Identification")) {
element.setInnerHTML(null);
element.insertFirst(createHeaderSpanContents());
break;
}
A question : what is the purpose of this line:
this.getAttribute("headerSpans");
And finally, it doesn't work for me - the span stays always as text "Identification". Any suggestions?
Thanks.
Did you test it on IE? I tested in FF and it works fine, but I have problems when clicking around my app in IE. As far as I read, it is due to the mix of GWT and SmartGWT. So I guess it's better to use a ToolStrip like in this example: http://www.smartclient.com/smartgwt/showcase/#grid_appearance_preferences
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.smartgwt.client.widgets.events.DrawEvent;
import com.smartgwt.client.widgets.events.DrawHandler;
import com.smartgwt.client.widgets.grid.ListGrid;
public class AdvancedListGrid extends ListGrid {
public AdvancedListGrid() {
// Create the HeaderSpan with title "Identification"
addDrawHandler(new DrawHandler(){
@Override
public void onDraw(DrawEvent event) {
insertCalendar();
}});
}
public void insertCalendar() {
for(Element element : DOMUtils.getElementsByTagName("td")) {
if(element.getInnerHTML().equals("Identification")) {
createCalendar(element);
}
}
}
public void createCalendar(Element element) {
DOMUtils.removeAllChildNodes(element);
// Create the SmartGWT calendar object. Say the object cal.
element.setInnerHTML(cal.getInnerHTML());
}
}
class DOMUtils {
public static void removeAllChildNodes(Element element) {
NodeList<Node> childList = element.getChildNodes();
for(int childIndex = 0; childIndex < childList.getLength(); childIndex++) {
element.removeChild(childList.getItem(childIndex));
}
}
public static Element[] getElementsByTagName(String tagName)
{
JavaScriptObject elements = getElementsByTagNameInternal(tagName);
int length = getArrayLength(elements);
Element[] result = new Element[length];
for (int i=0; i<length; i++)
{
result[i] = getArrayElement(elements, i);
}
return result;
}
private static native JavaScriptObject getElementsByTagNameInternal(String tagName)/*-{
return $doc.getElementsByTagName(tagName);
}-*/;
private static native int getArrayLength(JavaScriptObject array)/*-{
return array.length;
}-*/;
private static native Element getArrayElement(JavaScriptObject array, int position)/*-{
return (position>=0 && position<array.length?array[position]:null);
}-*/;
}
Here's doing it without JSNI or DOM:
This grid updates contents of the second span header with dynamic content when datasource is loaded.
Alternately, you could use "onDraw" instead of "dataArrived", if the contents are static
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.grid.HeaderSpan;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
public class MyGrid extends ListGrid {
private HeaderSpan oneHeaderSpan = new HeaderSpan("span one", new String[] { "a", "b", "c" });
private HeaderSpan twoHeaderSpan = new HeaderSpan("span two", new String[] { "d", "e", "f" });
final private static String ONE_SPAN_ID = "span1";
final private static String TWO_SPAN_ID = "span2";
public MyGrid() {
setID("MyGrid");
setHeight100();
setWidth100();
setDataSource(MyDS);
setHeaderSpans(oneHeaderSpan, twoHeaderSpan);
oneHeaderSpan.setAttribute("spanId", ONE_SPAN_ID);
twoHeaderSpan.setAttribute("spanId", TWO_SPAN_ID);
setHeaderHeight(50);
addDataArrivedHandler(new DataArrivedHandler() {
@Override
public void onDataArrived(DataArrivedEvent event) {
Canvas headerSpans = Canvas.getById(getID() + "_headerSpan");
// getPeers() did not work for IE
for (Canvas peer : headerSpans.getParentCanvas().getChildren()) {
if (peer.getAttribute("spanId") != null && peer.getAttribute("spanId").equals(TWO_SPAN_ID)) {
peer.addChild(createHeaderSpanContents(event));
}
}
}
});
}
private Canvas createHeaderSpanContents(DataArrivedEvent event) {
// Your favorite Canvas here:
Button button = new Button();
button.setLayoutAlign(Alignment.CENTER);
button.setHeight100();
button.setWidth100();
button.setTitle("+");
return button;
}
}
Using headerSpans.getParentElement().getChildren()) also works if you are on version of smartgwt preceding 4.1d