我必须在GWT中实现的一小段AJAX功能中添加一个表单。在HTML术语中,我想
<label for="personName">Name:</label><input type="text" size="50" id="personName"/>
看来GWT中的Label小部件只是呈现为DIV。
理想情况下,我想点击标签文字以关注相关输入。这是内置的浏览器功能,我不想在标签div上乱七八糟地使用ClickHandlers!
有没有人遇到过这个问题?是作为内置窗口小部件存在,还是被称为其他东西?
编辑:提出以下内容。也许有更好的方法?HTML label = new HTML();
label.setHTML("<label for='"+input.getElement().getId()+"'>"+labelText+"</label>");
答案 0 :(得分:16)
根据大众需求,我向您呈现InputLabel,<label>
+ <input type="text">
小部件:)
这是基于CheckBox类(包含<input type="checkbox">
元素) - 未经彻底测试 - 我将其留给读者;)< / p>
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.LabelElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.ButtonBase;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HasName;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
public class InputLabel extends ButtonBase implements HasName, HasValue<String>, HasChangeHandlers {
InputElement inputElem;
LabelElement labelElem;
private boolean valueChangeHandlerInitialized;
/**
* Creates an input box with no label.
*/
public InputLabel() {
this(DOM.createInputText());
//setStyleName("gwt-CheckBox"); //TODO: add a valid style name
}
/**
* Creates an input box with the specified text label.
*
* @param label the check box's label
*/
public InputLabel(String label) {
this();
setText(label);
}
/**
* Creates an input box with the specified text label.
*
* @param label the input box's label
* @param asHTML <code>true</code> to treat the specified label as html
*/
public InputLabel(String label, boolean asHTML) {
this();
if (asHTML) {
setHTML(label);
} else {
setText(label);
}
}
protected InputLabel(Element elem) {
super(DOM.createSpan());
inputElem = InputElement.as(elem);
labelElem = Document.get().createLabelElement();
getElement().appendChild(labelElem);
getElement().appendChild(inputElem);
String uid = DOM.createUniqueId();
inputElem.setPropertyString("id", uid);
labelElem.setHtmlFor(uid);
// Accessibility: setting tab index to be 0 by default, ensuring element
// appears in tab sequence. FocusWidget's setElement method already
// calls setTabIndex, which is overridden below. However, at the time
// that this call is made, inputElem has not been created. So, we have
// to call setTabIndex again, once inputElem has been created.
setTabIndex(0);
}
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> handler) {
// Is this the first value change handler? If so, time to add handlers
if (!valueChangeHandlerInitialized) {
addChangeHandler(new ChangeHandler() {
public void onChange(ChangeEvent event) {
ValueChangeEvent.fire(InputLabel.this, getValue());
}
});
valueChangeHandlerInitialized = true;
}
return addHandler(handler, ValueChangeEvent.getType());
}
/**
* Returns the value property of the input element that backs this widget.
* This is the value that will be associated with the InputLabel name and
* submitted to the server if a {@link FormPanel} that holds it is submitted.
* <p>
* This will probably return the same thing as {@link #getValue}, left here for magic reasons.
*/
public String getFormValue() {
return inputElem.getValue();
}
@Override
public String getHTML() {
return labelElem.getInnerHTML();
}
public String getName() {
return inputElem.getName();
}
@Override
public int getTabIndex() {
return inputElem.getTabIndex();
}
@Override
public String getText() {
return labelElem.getInnerText();
}
/**
* Gets the text value of the input element.
* <p>
* @return the value of the input box.
* Will not return null
*/
public String getValue() {
if (isAttached()) {
return inputElem.getValue();
} else {
return inputElem.getDefaultValue();
}
}
@Override
public boolean isEnabled() {
return !inputElem.isDisabled();
}
@Override
public void setAccessKey(char key) {
inputElem.setAccessKey("" + key);
}
@Override
public void setEnabled(boolean enabled) {
inputElem.setDisabled(!enabled);
if (enabled) {
removeStyleDependentName("disabled");
} else {
addStyleDependentName("disabled");
}
}
@Override
public void setFocus(boolean focused) {
if (focused) {
inputElem.focus();
} else {
inputElem.blur();
}
}
/**
* Set the value property on the input element that backs this widget. This is
* the value that will be associated with the InputLabel's name and submitted to
* the server if a {@link FormPanel} that holds it is submitted.
* <p>
* Don't confuse this with {@link #setValue}.
*
* @param value
*/
public void setFormValue(String value) {
inputElem.setAttribute("value", value);
}
@Override
public void setHTML(String html) {
labelElem.setInnerHTML(html);
}
public void setName(String name) {
inputElem.setName(name);
}
@Override
public void setTabIndex(int index) {
// Need to guard against call to setTabIndex before inputElem is
// initialized. This happens because FocusWidget's (a superclass of
// InputLabel) setElement method calls setTabIndex before inputElem is
// initialized. See InputLabel's protected constructor for more information.
if (inputElem != null) {
inputElem.setTabIndex(index);
}
}
@Override
public void setText(String text) {
labelElem.setInnerText(text);
}
/**
* Sets the text in the input box.
* <p>
* Note that this <em>does not</em> set the value property of the
* input element wrapped by this widget. For access to that property, see
* {@link #setFormValue(String)}
*
* @param value the text to set; must not be null
* @throws IllegalArgumentException if value is null
*/
public void setValue(String value) {
setValue(value, false);
}
/**
* Sets the text in the input box, firing {@link ValueChangeEvent} if
* appropriate.
* <p>
* Note that this <em>does not</em> set the value property of the
* input element wrapped by this widget. For access to that property, see
* {@link #setFormValue(String)}
*
* @param value true the text to set; must not be null
* @param fireEvents If true, and value has changed, fire a
* {@link ValueChangeEvent}
* @throws IllegalArgumentException if value is null
*/
public void setValue(String value, boolean fireEvents) {
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
String oldValue = getValue();
inputElem.setValue(value);
inputElem.setDefaultValue(value);
if (value.equals(oldValue)) {
return;
}
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
// Unlike other widgets the InputLabel sinks on its inputElement, not
// its wrapper
@Override
public void sinkEvents(int eventBitsToAdd) {
if (isOrWasAttached()) {
Event.sinkEvents(inputElem,
eventBitsToAdd | Event.getEventsSunk(inputElem));
} else {
super.sinkEvents(eventBitsToAdd);
}
}
/**
* <b>Affected Elements:</b>
* <ul>
* <li>-label = label next to the input box.</li>
* </ul>
*
* @see UIObject#onEnsureDebugId(String)
*/
@Override
protected void onEnsureDebugId(String baseID) {
super.onEnsureDebugId(baseID);
ensureDebugId(labelElem, baseID, "label");
ensureDebugId(inputElem, baseID, "input");
labelElem.setHtmlFor(inputElem.getId());
}
/**
* This method is called when a widget is attached to the browser's document.
* onAttach needs special handling for the InputLabel case. Must still call
* {@link Widget#onAttach()} to preserve the <code>onAttach</code> contract.
*/
@Override
protected void onLoad() {
setEventListener(inputElem, this);
}
/**
* This method is called when a widget is detached from the browser's
* document. Overridden because of IE bug that throws away checked state and
* in order to clear the event listener off of the <code>inputElem</code>.
*/
@Override
protected void onUnload() {
// Clear out the inputElem's event listener (breaking the circular
// reference between it and the widget).
setEventListener(asOld(inputElem), null);
setValue(getValue());
}
/**
* Replace the current input element with a new one. Preserves
* all state except for the name property, for nasty reasons
* related to radio button grouping. (See implementation of
* {@link RadioButton#setName}.)
*
* @param elem the new input element
*/
protected void replaceInputElement(Element elem) {
InputElement newInputElem = InputElement.as(elem);
// Collect information we need to set
int tabIndex = getTabIndex();
String checked = getValue();
boolean enabled = isEnabled();
String formValue = getFormValue();
String uid = inputElem.getId();
String accessKey = inputElem.getAccessKey();
int sunkEvents = Event.getEventsSunk(inputElem);
// Clear out the old input element
setEventListener(asOld(inputElem), null);
getElement().replaceChild(newInputElem, inputElem);
// Sink events on the new element
Event.sinkEvents(elem, Event.getEventsSunk(inputElem));
Event.sinkEvents(inputElem, 0);
inputElem = newInputElem;
// Setup the new element
Event.sinkEvents(inputElem, sunkEvents);
inputElem.setId(uid);
if (!accessKey.equals("")) {
inputElem.setAccessKey(accessKey);
}
setTabIndex(tabIndex);
setValue(checked);
setEnabled(enabled);
setFormValue(formValue);
// Set the event listener
if (isAttached()) {
setEventListener(asOld(inputElem), this);
}
}
private Element asOld(com.google.gwt.dom.client.Element elem) {
Element oldSchool = elem.cast();
return oldSchool;
}
private void setEventListener(com.google.gwt.dom.client.Element e,
EventListener listener) {
DOM.setEventListener(asOld(e), listener);
}
@Override
public HandlerRegistration addChangeHandler(ChangeHandler handler) {
return addDomHandler(handler, ChangeEvent.getType());
}
}
以下答案留给那些喜欢使用“标准”GWT小部件和/或更喜欢以其他方式执行此操作的人:)
您可以使用<label>
轻松创建DOM.createLabel()
元素:
LabelElement label = DOM.createLabel().cast();
label.setHtmlFor("inputId");
但我坚持使用GWT提供的Widgets - 它们是由GWT构建和选择的,因此它们在所有支持的浏览器中的外观和行为都完全相同。他们选择的方法(例如,如果你放置Image
内联,它将被包装在一个表中,iirc - 因为通过display:inline
设置内联将无法在所有浏览器中使用:咳嗽:IE:咳嗽:)
tl; dr:除非你有非常具体的需求(比如创建自己的低级元素),坚持使用提供的Widgets
(或通过Composite
创建自己的) - 你会受益更多。
PS:如果你担心网络标准,可访问性等等 - 请不要,例如,大多数标准GWT小部件support ARIA - 你必须自己做的事情,如果你自己构建了组件。
编辑:回答AlexJReid的评论:
您可以使用FormPanel通过表单发送数据(值得注意的是,这种方式适用于所有浏览器,因为与其他浏览器不同,IE6会触发与其他浏览器不同的事件;此外,表单的{ {1}}将被设置为iframe - 多亏了这一点,页面将不必重新加载 - 这将超过AJAX的目的:)):
target
请注意final FormPanel form = new FormPanel();
form.setAction("page.php");
TextBox box = new TextBox();
box.setName("name");
box.setText("fasdf");
Button button = new Button("Send", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
form.submit();
}
});
form.add(box);
form.add(button);
行 - 这是您在提交此表单时设置将用于box.setName("name");
的值的名称。那么,Widgets会TextBox
支持哪些内容?实现FormPanel
接口的那些:
(当然,您可以添加任何Widget,但只会发送上述值)
最后一件事:除非你真的必须使用表格(比如发送文件或类似的东西),RequestBuilder可能值得尝试 - 它正在使用com.google.gwt.user.client.ui.HasName
惊天动地 - 母亲/ AJAX的父亲;)
答案 1 :(得分:10)
使用UIbinder,您只需使用 ui:field 属性在模板中创建标准html标签。
<label ui:field="myLabel">Some Text</label>
在视图中,您可以使用注释引用此元素:
@UiField LabelElement myLabel;
请注意,您用于GWT小部件的一些方法不可用。
e.g。而不是:
myLabel.setVisible(false);
你必须使用
myLabel.setAttribute("style", "display:none");
答案 2 :(得分:8)
作为Bayard为每个标签创建@UiField元素的方法的替代方法,您还可以对标签和文本框组合执行以下操作:
<label for="{myTextBox.getElement.getId}">Some field:</label>
<g:TextBox ui:field="myTextBox"/>
您不能在同一元素上设置ui:field和id属性,因此您必须在Java代码中为TextBox指定一个id:
...
@UiField(provided=true) TextBox myTextBox = new TextBox();
public MyFormView() {
myTextBox.getElement().setId(DOM.createUniqueId());
uiBinder.createAndBindUi(this);
}
...
这是指向正确方向的Ray Ryan's comment on UiBinder id generation。他确实提到了运行时ID生成,这将消除对java片段的需求,但据我所知,它被废弃了。
答案 3 :(得分:0)
我有同样的需求,最终创建了自己的Widget
public class Label extends Widget implements HasText {
public Label() {
setElement(DOM.createLabel());
}
@Override
public void add(Widget w) {
super.add(w, getElement());
}
@Override
public String getText() {
return getElement().getInnerText();
}
@Override
public void setText(String text) {
getElement().setInnerText((text == null) ? "" : text);
}
public void setFor(String forWho) {
getElement().setAttribute("for", forWho);
}
}
答案 4 :(得分:0)
我在UiBinder中编写了一个名为InputLabel的简单Widget(源代码如下)。 它使用HTML标签,但ui:字段用于引用输入小部件。我希望两全其美。
InputLabel小部件可以在UiBinder中使用,如下所示:
xmlns:tmp='urn:import:{REPLACE_WITH_JAVA_PACKAGE_PATH_TO_INPUTLABEL}'
<tmp:InputLabel for="{fieldRef}">Label text</tmp:InputLabel>
<g:FlowPanel ui:field="fieldRef">
<g:TextBox/>
</g:FlowPanel>
或者像这样:
<g:FlowPanel>
<g:CheckBox ui:field="fieldRef" />
</g:FlowPanel>
<tmp:InputLabel for="{fieldRef}">Label text</tmp:InputLabel>
Java源代码是:
import com.google.gwt.dom.client.*;
import com.google.gwt.i18n.client.HasDirection;
import com.google.gwt.i18n.shared.DirectionEstimator;
import com.google.gwt.i18n.shared.HasDirectionEstimator;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.DirectionalTextHelper;
import com.google.gwt.user.client.ui.HasDirectionalText;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
public class InputLabel extends Widget implements HasDirectionalText, HasDirectionEstimator {
final DirectionalTextHelper directionalTextHelper;
private boolean init = false;
public InputLabel() {
this(Document.get().createLabelElement());
}
public InputLabel(Element element) {
assert (LabelElement.TAG.equalsIgnoreCase(element.getTagName()));
this.setElement(element);
this.directionalTextHelper = new DirectionalTextHelper(this.getElement(), true);
}
public DirectionEstimator getDirectionEstimator() {
return this.directionalTextHelper.getDirectionEstimator();
}
public void setDirectionEstimator(DirectionEstimator directionEstimator) {
this.directionalTextHelper.setDirectionEstimator(directionEstimator);
}
public void setDirectionEstimator(boolean enabled) {
this.directionalTextHelper.setDirectionEstimator(enabled);
}
private InputElement getInputElement(Widget widget) {
if (widget.getElement().hasTagName(InputElement.TAG)) return InputElement.as(widget.getElement());
NodeList<Element> l = widget.getElement().getElementsByTagName(InputElement.TAG);
if (l.getLength() > 0) {
return InputElement.as(l.getItem(0));
}
return null;
}
public void setFor(IsWidget target) {
if (init) return;
init = true;
//
final InputElement input = getInputElement(target.asWidget());
if (input != null) {
if (!input.hasAttribute("id")) input.setId(DOM.createUniqueId());
getElement().setAttribute("for", input.getId());
}
}
public void setForm(String form) {
getElement().setAttribute("form", form);
}
public String getText() {
return this.directionalTextHelper.getTextOrHtml(false);
}
public void setText(String text) {
this.directionalTextHelper.setTextOrHtml(text, false);
}
public HasDirection.Direction getTextDirection() {
return this.directionalTextHelper.getTextDirection();
}
public void setText(String text, HasDirection.Direction dir) {
this.directionalTextHelper.setTextOrHtml(text, dir, false);
}
}