Получение идентификатора клиента другого компонента в JSF 2.0

Есть ли в JSF 2.0 встроенный метод для поиска идентификатора клиента другого компонента? На SO есть около тысячи вопросов, связанных с идентификаторами клиентов, и есть много хакерских методов для этого, но мне интересно, есть ли в JSF 2.0 более простой метод, о котором я просто не знаю.

#{component.clientId} оценивает собственный идентификатор клиента данного компонента, но я хочу сослаться на идентификатор другого компонента.

В этом сообщении блога упоминаются component.clientId и там также говорится, что #{someComponent.clientId} работает, но, насколько я могу судить, это не так. Я полагаю, он писал это до того, как были выпущены какие-либо эталонные реализации JSF 2.0, поэтому он просто перешел на JSR и, возможно, эта функциональность изменилась. Я не уверен.

Я знаю, что у PrimeFaces и RichFaces есть свои собственные функции для возврата идентификатора клиента, но мне просто интересно, есть ли для этого встроенный метод JSF 2.0. Вот некоторые примеры:

This works to return the outputText's ID.

`<h:outputText value="My client ID : #{component.clientId}" />`

Согласно сообщению в блоге выше, это должно работать, но это не так. Я просто ничего не получаю.

`<h:button id="sampleButton" value="Sample" />`

`<h:outputText value="sampleButton's client ID : #{sampleButton.clientId}" />`

Это работает в PrimeFaces:

`<h:outputText value="PrimeFaces : sampleButton's client ID : #{p:component('sampleButton')}" />` 

Работает в RichFaces:

`<h:outputText value="RichFaces : sampleButton's client ID : #{rich:clientId('sampleButton')}" />`

Кроме того, если это вообще возможно, я ищу решения, которые не сломаются, если я изменю значение javax.faces.SEPARATOR_CHAR или добавлю / удалю контейнеры за пределами указанных компонентов. Я потратил много времени на отслеживание проблем, вызванных жестко заданными путями идентификаторов.


person cutchin    schedule 25.08.2012    source источник


Ответы (3)


Вам необходимо присвоить компоненту имя переменной в области просмотра по атрибуту binding.

<h:button id="sampleButton" binding="#{sampleButton}" value="Sample" />
<h:outputText value="sampleButton's client ID : #{sampleButton.clientId}" />
person BalusC    schedule 26.08.2012
comment
Замечательно. Я предположил, что атрибут binding предназначен исключительно для предоставления компонентов для поддержки bean-компонентов - я не понимал, что вы также можете опубликовать компонент в области видимости. Большое спасибо. - person cutchin; 26.08.2012
comment
Я тоже не знал, что ты можешь это сделать! Я не видел никаких ссылок в документации на использование привязки / EL. Это новое в JSF 2.x? (т.е. он также доступен в версии 1.2?) - person Steve Atkinson; 27.08.2012
comment
Это всегда было в JSF / EL. Это не относится к JSF2. См. Также этот связанный вопрос / ответ: http://stackoverflow.com/questions/8168302/jsf-component-binding-without-bean-property - person BalusC; 27.08.2012
comment
нет ли проблем с коллизией или плохой / неправильной привязкой? я бы хотел иметь clientId, но если я рискую получить неправильные значения компонентов ... это будет убийца - person Toskan; 28.08.2012
comment
@Toskan: Я не уверен, что понимаю ваше беспокойство. - person BalusC; 28.08.2012
comment
@BalusC, это в основном причина, потому что я не понимаю, как привязка может на что-то влиять. Меня только что заинтересовала эта ссылка незаконныйargumentexception.blogspot .ch / 2009/10 / - person Toskan; 28.08.2012
comment
@Toskan: А вот сюда. Если у вас есть @ManagedBean(name="foo") и вы где-то используете binding="#{foo}", значит, вы столкнулись. Вы должны быть абсолютно уверены, что имя переменной binding уникально в области EL текущего представления. См. Также последний связанный связанный ответ, чтобы узнать простой способ избежать этих возможных столкновений с помощью HashMap. - person BalusC; 28.08.2012
comment
Я думаю, что важно, чтобы при присоединении привязки вы могли легко уничтожить приложение, т. Е. Подключившись к той же записи хэш-карты. Например: у вас есть две формы, в обеих формах у вас есть 1 ввод с id = abc (это законно), вы обычно присоединяетесь к записи хэш-карты, созданной с помощью идентификатора, например. # {components.myInputId}, который в два раза больше abc, что фактически приведет к тому, что элемент ввода не будет отображаться вообще. Думаю, самая безопасная ставка - использовать случайно сгенерированный идентификатор? это все еще кажется немного меня - person Toskan; 28.08.2012
comment
Он выполняет свою работу, но также может создать проблему, если вы примените (по ошибке или вложением) одно и то же имя привязки в два тега на своей странице. Это приведет к тому, что оба тега будут использовать один и тот же объект, который может быть сложно идентифицировать. Эта ссылка содержит дополнительные сведения - person Ioannis Deligiannis; 07.07.2013
comment
@john: Незнание - это действительно боль. Эта нелепая ссылка еще раз подтверждает это. Он даже рекомендует никогда не использовать привязку, хотя она определенно имеет смысл, когда ее понимают. См. Также stackoverflow.com/questions/12506679/ - person BalusC; 07.07.2013
comment
Я согласен, но я подумал, что, поскольку я (среди других) почувствовал боль (по моему невежеству), хорошо поделиться;). Кроме того, привязка, безусловно, может выиграть от лучшей документации (например, вашей ссылки) - person Ioannis Deligiannis; 07.07.2013

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

client.html

<h:outputText value="#{UIHelper.clientId('look-up-address-panel-id')}" />

UIHelper.java

@ManagedBean(name = "UIHelper", eager = true)
@ApplicationScoped
public class UIHelper
{

public String clientId(final String id)
{
  FacesContext context = FacesContext.getCurrentInstance();
  UIViewRoot root = context.getViewRoot();
  final UIComponent[] found = new UIComponent[1];
  root.visitTree(new FullVisitContext(context), new VisitCallback()
  {
    @Override
    public VisitResult visit(VisitContext context, UIComponent component)
    {
      if (component.getId().equals(id))
      {
        found[0] = component;
        return VisitResult.COMPLETE;
      }
      return VisitResult.ACCEPT;
    }
  });
  return found[0] == null ? "" : "#" + found[0].getClientId().replace(":", "\\\\:");
}

}
person mert inan    schedule 14.11.2013

Поскольку это был один из первых результатов моего поиска в Google, я задался вопросом, почему я получил

javax.el.PropertyNotFoundException (свойство 'itemId' не найдено [...])

пробуя принятое решение, я хотел бы поделиться своим решением для JSF 1.2:

Метод UIComponent getClientId требует параметра FacesContext (см. документация UIComponent). Итак, добавьте привязку к компоненту поддержки, а также еще один метод, который возвращает clientId:

xhtml:

<h:button id="sampleButton" binding="#{backingBean.sampleButton}" value="Sample" />
<h:outputText value="sampleButton's client ID : #{backingBean.sampleButtonClientId}" />

Фасоль:

private UIComponent sampleButton;

public UIComponent getSampleButton() {
    return sampleButton;
}

public void setSampleButton(final UIComponent sampleButton) {
    this.sampleButton = sampleButton;
}

public String getSampleButtonClientId() {
    final FacesContext context = FacesContext.getCurrentInstance();
    return sampleButton.getClientId(context);
}

Обратите внимание, что компонент, к которому вы привязываете свой компонент, должен иметь область действия запроса, иначе вы можете получить java.lang.IllegalStateException (duplicate Id for a component) (сравните с этой темой ).

person david    schedule 22.01.2014