How can I render a ClickableTextCell as an anchor in a GWT CellTable?
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I've got a CellTable with multiple columns in simple TextCell()s. Two of the columns are 'clickable' via the ClickableTextCell() class, but I want to change how they look. What's the easiest way to get the cell contents to resemble an anchor tag, while still using a cell in the table?
I've tried the following: 1. Implement a custom renderer to add anchor tags 2. Scouring Google looking for hints 3. Ignoring 'my library does it you just have to change your entire framework' links 4. Rolling my head across they keyboard
It's funny how annoying this simple change is turning out to be.
My current thought is to implement a custom AnchorCell type which puts in an Anchor widget instead of whatever it does in the other ones, but I'm not sure what all would need to be done.
Any help is appreciated.
回答1:
As an example:
public class MyClickableCellText extends ClickableTextCell { String style; public MyClickableCellText() { super(); style = "myClickableCellTestStyle"; } @Override protected void render(Context context, SafeHtml value, SafeHtmlBuilder sb) { if (value != null) { sb.appendHtmlConstant("
You can even create your own cell by not extending ClickableTextCell but extending AbstractCell (more powerful but need more explanation). Ask me if you need it!
回答2:
Mentioned solution have the problem, these are no links and stylesheets with a:hover and so on doesn't work.
Here is my solution:
private class SellerName { private final String sellerName; private final Command cmd; private SellerName(String displayName, Command cmd) { this.sellerName = displayName; this.cmd = cmd; } public String getDisplayName() { return sellerName; } public Command getCommand() { return cmd; } }; private class SellerNameCell extends AbstractCell { public SellerNameCell() { super("click", "keydown"); } @Override public void render(com.google.gwt.cell.client.Cell.Context context, SellerName value, SafeHtmlBuilder sb) { if (value != null) { sb.appendHtmlConstant(""); sb.appendEscaped(value.getDisplayName()); sb.appendHtmlConstant(""); } } @Override public void onBrowserEvent(Context context, Element parent, SellerName value, NativeEvent event, ValueUpdater valueUpdater) { if (value == null) return; super.onBrowserEvent(context, parent, value, event, valueUpdater); if ("click".equals(event.getType())) { if (value.getCommand() != null) value.getCommand().execute(); } } };
It creates a real anchorcell which is clickable :)
回答3:
It would seem that your first instinct (implementing a custom renderer) is way easier:
SafeHtmlRenderer anchorRenderer = new AbstractSafeHtmlRenderer() { @Override public SafeHtml render(String object) { SafeHtmlBuilder sb = new SafeHtmlBuilder(); sb.appendHtmlConstant("") .appendEscaped(object).appendHtmlConstant(""); return sb.toSafeHtml(); } };
And then:
Column anchorCol = new Column( new ClickableTextCell(anchorRenderer)) { @Override public String getValue(YourThingy object) { return object.toString(); } };
回答4:
This is what you need:
public class ClickableSafeHtmlCell extends AbstractCell { /** * Construct a new ClickableSafeHtmlCell. */ public ClickableSafeHtmlCell() { super("click", "keydown"); } @Override public void onBrowserEvent(Context context, Element parent, SafeHtml value, NativeEvent event, ValueUpdater valueUpdater) { super.onBrowserEvent(context, parent, value, event, valueUpdater); if ("click".equals(event.getType())) { onEnterKeyDown(context, parent, value, event, valueUpdater); } } @Override protected void onEnterKeyDown(Context context, Element parent, SafeHtml value, NativeEvent event, ValueUpdater valueUpdater) { if (valueUpdater != null) { valueUpdater.update(value); } } @Override public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) { if (value != null) { sb.append(value); } }
And then usage:
Column nameColumn = new Column( new ClickableSafeHtmlCell()) { @Override public SafeHtml getValue(YourProxy object) { SafeHtmlBuilder sb = new SafeHtmlBuilder(); sb.appendHtmlConstant(""); sb.appendEscaped(object.getName()); sb.appendHtmlConstant(""); return sb.toSafeHtml(); } }; nameColumn.setFieldUpdater(new FieldUpdater() { @Override public void update(int index, YourProxy object, SafeHtml value) { Window.alert("You have clicked: " + object.getName()); } });
回答5:
This is actually quite simple, but it's amazing how many wrong and convoluted answers there are on Google, and seemingly no correct ones! Anyway, here's the code:
private Column
Change object to whatever it is you're trying to render in the table then run this method when creating the column, easy!
回答6:
If you take a look to the clickableTextCell html code generated by gwt you will see something like (taken from gwt showcase)
Click Robert
So I will recommend u doing something like:
ClickableTextCell cell = new ClickableTextCell(); cell.addStyleName("yourStyle");
and in you style.css do whatever you want.
.yourStyle div{ text-decoration:underline; }
回答7:
It is essentially a hack to use appendHtmlConstant. Simply using toString of the Anchor or its element or passing a HTML string violates the concept behind SafeHtml entirely.
In my opinion a proper SafeHtmlTemplates should be used to tackle unreadable and unsafe string concatenation of HTML. Similar to:
Then you can use GWT.create on it and interpolate the arguments properly.
Second part is that reading the HTML string of a widget could be optimized out. I was extending AbstractCell and had this method:
/* do not dare to copy - considered broken */ @Override public void render(final Context context, final String value, final SafeHtmlBuilder sb) { final Anchor anchor = new Anchor(); anchor.setText(value); sb.appendHtmlConstant(anchor.getElement().toString()); }
I just experienced a case where the anchor cell was working fine in superdev mode, but compiling it (probably with more aggressive optimization settings) and then deploying it manually led to an entirely empty cell with no changes in code reproducibly across several systems. Using the template mechanism described above made it work properly (GWT 2.7).
回答8:
First things first - each GWT CellTable Column is just a stack of Cell(s), as our need is to make each Cell look like an anchor which can listen to Click event lets provide ClickableTextCell as argument to Column.
Column col = new Column(new ClickableTextCell()) {};
2nd - override "render()" method in your Column instance and build your HTML template that you want, here our need is creating an anchor.
3rd - as we are using ClickableTextCell, it serves as Click Event source. We need to provide ClickEvent listener, we do that by overriding "onBrowserEvent()" method.
@Override public void onBrowserEvent(Context context, Element elem, Customer customer, NativeEvent event) { if ("click".equals(event.getType())) { Window.alert("ID is : " + customer.getId()); } }
Complete Code snippet :
Column col = new Column(new ClickableTextCell()) { @Override public String getValue(final YourObj yourObj) { return yourObj.getX(); } @Override public void render(Context context, YourObj yourObj, SafeHtmlBuilder sb) { sb.appendHtmlConstant("" + yourObj.getX() + ""); } @Override public void onBrowserEvent(Context context, Element elem, YourObj yourObj, NativeEvent event) { if ("click".equals(event.getType())) { Window.alert("ID is : " + yourObj.getId()); } } };