Подтвердить что ты не робот

GWT есть виджет <label>?

Мне нужно добавить форму к небольшой части функциональности AJAX, реализованной в GWT. В HTML-выражениях я хотел бы

<label for="personName">Name:</label><input type="text" size="50" id="personName"/>

Кажется, виджет Label в GWT просто отображается как DIV.

В идеале я бы хотел щелкнуть по тексту метки, чтобы сфокусировать соответствующий вход. Это встроенная функция браузера, с которой я не хочу общаться с ClickHandlers на ярлыках ярлыков!

Кто-нибудь сталкивался с этой проблемой? Существует ли как встроенный виджет, но называется чем-то еще?

EDIT: Придумали следующее. Может быть, есть лучший способ?

HTML label = new HTML();
label.setHTML("<label for='"+input.getElement().getId()+"'>"+labelText+"</label>");
4b9b3361

Ответ 1

По популярному запросу я представляю вам InputLabel, a <label> + <input type="text"> Widget:)

Это основано на CheckBox классе (который обертывает элемент <input type="checkbox">) - он не имеет был протестирован полностью - я оставляю это читателю;)

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 label
   */
  public InputLabel(String label) {
    this();
    setText(label);
  }

  /**
   * Creates an input box with the specified text label.
   * 
   * @param label the input box 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 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 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 (a superclass of
    // InputLabel) setElement method calls setTabIndex before inputElem is
    // initialized. See InputLabel 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 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 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, - они были созданы и выбраны GWT, чтобы они выглядели одинаково во всех поддерживаемых браузерах и вел себя одинаково. Подход, который они выбрали (например, если вы поместите встроенную строку Image, она будет обернута внутри таблицы, iirc - потому что установка его встроенного с помощью display:inline не будет работать во всех браузерах: cough: IE: cough:).

tl; dr: если у вас нет особых потребностей (например, создания собственных элементов низкого уровня), придерживайтесь предоставленного Widgets (или создайте собственный через Composite) - вы выиграете больше.

PS: И если вас беспокоят веб-стандарты, доступность и т.д. - нет, например, большинства стандартных виджетах GWT поддержка ARIA - то, что вам нужно было бы сделать самостоятельно, если бы вы создали свои собственные компоненты.

Изменить: ответ на комментарий AlexJReid:

Вы можете отправлять данные через форму, используя FormPanel (стоит отметить, что таким образом он будет работать на всех браузерах, поскольку, в отличие от в других браузерах IE6 запускает другое событие, а затем другие браузеры, кроме того, форма target будет установлена ​​в iframe - благодаря этому страница не будет перезагружаться - это превзойдет цель AJAX:))

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"); - это вы указали имя, которое будет использоваться для значения этого TextBox при отправке этой формы. Итак, что поддерживает Widgets FormPanel? Те, которые реализуют интерфейс com.google.gwt.user.client.ui.HasName:

  • TextBox
  • PasswordTextBox
  • RadioButton
  • SimpleRadioButton
  • CheckBox
  • SimpleCheckBox
  • TextArea
  • ListBox
  • FileUpload
  • Hidden

(вы можете добавить, конечно, любой виджет, но будут отправлены только те значения, которые указаны выше)

Последнее: если вам действительно не нужно использовать форму (например, при отправке файлов или что-то подобное), RequestBuilder может быть стоит попробовать - он использует XmlHttpRequest, показывая капот - мать/отец AJAX;)

Ответ 2

С UIbinder вы можете просто создавать стандартные html-метки в своем шаблоне с атрибутом поля ui:.

<label ui:field="myLabel">Some Text</label>

В вашем представлении вы можете ссылаться на этот элемент, используя аннотацию:

@UiField LabelElement myLabel;

Обратите внимание, что некоторые из методов, которые вы использовали для использования с виджетами GWT, недоступны.

например. вместо:

myLabel.setVisible(false);

вам нужно будет использовать

myLabel.setAttribute("style", "display:none");

Ответ 3

В качестве альтернативы методу Байарда для создания элемента @UiField для каждой метки вы также можете сделать следующее для комбинации меток и текстовых полей:

<label for="{myTextBox.getElement.getId}">Some field:</label>
<g:TextBox ui:field="myTextBox"/>

Вам не разрешено задавать свойства ui: и id в одном и том же элементе, поэтому вам нужно предоставить TextBox идентификатор в java-коде:

...

@UiField(provided=true) TextBox myTextBox = new TextBox();

public MyFormView() {
    myTextBox.getElement().setId(DOM.createUniqueId());
    uiBinder.createAndBindUi(this);
}

...

Здесь Рей Райан комментирует создание идентификатора UiBinder, который указал мне в правильном направлении. Он упоминает о генерации времени выполнения, который устраняет необходимость в фрагменте java, но насколько я могу судить об отказе.

Ответ 4

У меня была такая же потребность, и я создал собственный виджет

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);
}

}

Ответ 5

Я написал простой виджет для использования в UiBinder под названием InputLabel (исходный код ниже). Он использует 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);
    }
}