В этой статье я покажу, как работать со свойством clientId UIComponent , которое было улучшено в JavaServer Faces 2.0, как найти конкретный идентификатор со стороны клиента и как использовать эти знания с библиотекой jQuery. Мы рассмотрим составные компоненты , составление граней , шаблоны граней и UIComponents с NamingContainer (например, UIData).
Предварительно требования
В этой статье я использовал IDE NetBeans 6.9 , Mojarra 2.0.2 (FCS b10) в качестве реализации JSF 2.0 и GlassFish 3.0.1 .
Здравствуйте, ClientId
На этом этапе мы создадим наше первое простое веб-приложение с одной страницей.
1. В мастере NetBeans выберите «Java Web» -> «Веб-приложение» -> «ClientIdExampleApp» -> «Выбрать EE 6 Web и Glassfish 3» -> «Выбрать JavaServer Faces Framework (с представлением Facelets») и нажмите «Готово».
Получение ClientId из нового выражения EL в JSF 2.0 $ { component }
<h:form id="form1" prependId="true">
${component.clientId}
<h:commandButton id="btn1" value="${component.clientId}" />
${component.clientId}
<h:panelGroup id="panel1" layout="block">
${component.clientId}
</h:panelGroup>
</h:form>
Этот код должен производить что-то вроде этого:
<form enctype="application/x-www-form-urlencoded" action="/WebApplication1/faces/index.xhtml" method="post" name="form1" id="form1">
(1)form1
<input type="submit" (2)value="form1:btn1" name="form1:btn1" id="form1:btn1">
(3)form1
<div id="form1:panel1">
(4)form1:panel1
</div>
</form>
Хотя этот пример действительно легко кодировать, мы можем видеть, что:
$ {component.clientId} возвращает «
ближайший » родительский
UIComponent . Точки (2) и (4) разрешили clientId правильно, в то время как (1) и (3) разрешили clientId родителя:
UIForm . Если нам нужно создать функцию javascript, это решение действительно быстрое и достаточно хорошее. С другой стороны, когда нам нужна перекрестная ссылка на javascript id, лучше использовать
привязывающие атрибуты.
Получение ClientId от атрибутов привязки UIComponents
Второй способ сложнее, но эффективнее в разных случаях. Два шага необходимы, чтобы получить clientId путем привязки. Сначала нам нужно добавить атрибут связывания и связать этот атрибут со свойством Managed Bean, соответствующим конкретным подклассам UIComponent.
Простая форма:
<h:form id="form1" prependId="true" binding="(1)${index.form1}" style="background-color: red">
ClientId: (2)${index.form1.clientId}<br />
Simple attribute of form1: (3)${index.form1.attributes["style"]}<br />
<h:commandButton id="btn1" value="(4)#{index.form1.findComponent('btn1').clientId} :-)" />
<h:panelGroup id="panel1" layout="block">
(5)${component.clientId} <br />
</h:panelGroup><br />
panel1 clientId: (6)#{index.form1.findComponent("panel1").clientId} <br />
panel1 layout attribute (7)#{index.form1.findComponent("panel1").attributes["layout"]}
</h:form>
Java управляемый код компонента:
@ManagedBean
@RequestScoped
public class index {
private UIForm form1;
public UIForm getForm1() {
return form1;
}
public void setForm1(UIForm form1) {
this.form1 = form1;
}
public index() {
}
}
Отображается HTML:
<form style="background-color: red;" enctype="application/x-www-form-urlencoded" action="/WebApplication1/faces/index.xhtml;jsessionid=64e609789a8d90f6993151f964d4" method="post" name="form1" id="form1">
ClientId: form1<br>
Simple attribute of form1: background-color: red<br /><input type="submit" value="form1:btn1 :-)" name="form1:btn1" id="form1:btn1"><div id="form1:panel1">
form1:panel1 <br /></div><br />
panel1 clientId: form1: panel1 <br />
panel1 layout attribute: block
</form>
Краткое разъяснение
В пунктах: (1), (2), (3) и (5) мы использовали знак доллара $ для доступа к свойствам (form1 и component) управляемого компонента. В (4), (7), (6) мы использовали знак хеша # для ссылки на методы UIComponent, такие как findComponent, для поиска дочернего компонента и использования свойств panel1.
ClientId с помощью NamingContainer
Теперь я добавлю несколько примеров моего веб-приложения и объясню, как все это работает. Давайте начнем с h: dataTable с несколькими строками и двумя столбцами. Второй столбец будет содержать ah: commandButton, и мы хотим использовать эту кнопку, чтобы выполнить клиентское действие Javascript.
Вот простой набор данных:
<h:dataTable id="dt1" binding="${clientIdExample.dt1}" value="#{clientIdExample.localeList}" var="item"
dir="LTR" frame="hsides" rules="all" summary="This is a JSF code to create dataTable." >
<f:facet name="header">
<h:outputText value="This is 'dataTable' demo" />
</f:facet>
<h:column id="col1">
${component.clientId}
<f:facet name="header">
<h:outputText value="name"/>
</f:facet>
<h:outputText value="#{item.displayName}" style="margin:5px; padding:5px"></h:outputText>
</h:column>
<h:column id="col2">
<f:facet name="header">
<h:outputText value="click"/>
</f:facet>
<h:commandButton id="editRow" value="click" onclick="toggleRow('${component.clientId}');return false;"
style="margin:5px; padding:5px"/>
</h:column>
<f:facet name="footer">
<h:outputText value="The End" />
</f:facet>
</h:dataTable>
И, конечно же, наш ManagedBean:
@Named(value = "clientIdExample")
@RequestScoped
public class ClientIdExample {
private Locale[] localeList;
private HtmlDataTable dt1;
public Locale[] getLocaleList() {
Locale[] tmp = Locale.getAvailableLocales();
localeList = new Locale[5];
for (int i=0;i< localeList.length;i++){
localeList[i] = tmp[i];
}
return localeList;
}
public void setLocaleList(Locale[] localeList) {
this.localeList = localeList;
}
public HtmlDataTable getDt1() {
return dt1;
}
public void setDt1(HtmlDataTable dt1) {
this.dt1 = dt1;
}
public ClientIdExample() {
}
}
И сгенерированный HTML должен выглядеть так:
<table rules="all" frame="hsides" summary="This is a JSF code to create dataTable." dir="LTR" id="form1-dt1">
<thead>
<tr><th scope="colgroup" colspan="2">This is 'dataTable' demo</th></tr>
<tr>
<th scope="col">name</th>
<th scope="col">click</th>
</tr>
</thead>
<tfoot>
<tr><td colspan="2">The End</td></tr>
</tfoot>
<tbody>
<tr class="">
<td>
form1-dt1-0
<span style="margin: 5px; padding: 5px;">japoński (Japonia)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-0-editRow" id="form1-dt1-0-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-1
<span style="margin: 5px; padding: 5px;">hiszpański (Peru)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-1-editRow" id="form1-dt1-1-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-2
<span style="margin: 5px; padding: 5px;">angielski</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-2-editRow" id="form1-dt1-2-editRow"></td>
</tr>
<tr class="">
<td>
form1-dt1-3
<span style="margin: 5px; padding: 5px;">japoński (Japonia,JP)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-3-editRow" id="form1-dt1-3-editRow"></td>
</tr>
<tr>
<td>
form1-dt1-4
<span style="margin: 5px; padding: 5px;">hiszpański (Panama)</span></td>
<td><input type="submit" style="margin: 5px; padding: 5px;" value="click" name="form1-dt1-4-editRow" id="form1-dt1-4-editRow"></td>
</tr>
</tbody>
</table>
Теперь я представлю 3 способа выделения всей строки с помощью события click. Эти функции просты, поэтому им не нужно объяснение.
1)
function toggleRow(clientId)
{
$('#'+clientId).closest('tr').toggleClass("selectedRow");
}
2)
$(document).ready(function(){
$('input[id$=editRow]').click(function(){
$(this).closest('tr').toggleClass("selectedRow");
return false;
});
});
3)
$(document).ready(function(){
$('#${clientIdExample.dt1.clientId} tr td > input').click(function(){
$(this).closest('tr').toggleClass("selectedRow");
return false;
});
});
Работа с jQuery и JSF 2.0 (javax.faces.SEPARATOR_CHAR)
Обычно, когда вы используете инфраструктуру JSF и просматриваете вывод HTML, вы обнаруживаете, что clientId отделен знаком двоеточия «:». К сожалению, этот знак недопустим при использовании библиотеки jQuery, поскольку он зарезервирован для селекторов jQuery. JavaServer Faces 2.0 поставляется с параметром: javax.faces.SEPARATOR_CHAR. В этом случае вы должны изменить разделитель по умолчанию на другой, который принят jQuery. Например (web.xml):
<context-param>
<param-name>javax.faces.SEPARATOR_CHAR</param-name>
<param-value>-</param-value>
</context-param>
Звоните Ajax через шаблон Facelets и клиентов
В этом примере я покажу, как вызвать Ajax для обновления UIComponent в Template.xhtml из AjaxEngine.xhtml (Facelets Client). Мы будем использовать функцию javascript jsf.ajax.request вместо f: ajax, и мы будем использовать свойство clientId UIControl.
Если мы хотим использовать Javascript jsf.ajax.request в чистом виде, нам нужно загрузить соответствующий клиентский скрипт
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
Это сгенерирует что-то вроде этого:
<script src="/PrimeFacesLearning/javax.faces.resource/jsf.js.jsf?ln=javax.faces&stage=Development" type="text/javascript"></script>
template.xhtml:
<h:body>
<f:view contentType="text/html" locale="pl_PL">
<h:form id="form1" prependId="true" binding="#{template.form1}">
<ui:debug id="debug1" rendered="true" hotkey="l">
</ui:debug>
<div id="container">
<div id="header"></div>
<div id="center-column">
<div id="left-column">
<h:outputText id="ajaxText" binding="#{template.ajaxText}" value="${ajaxEngine.firstname}" />
</div>
<br />
<p:panel id="right-column" styleClass="right-column" toggleable="true" closable="true">
<ui:insert name="right-column" >
</ui:insert>
</p:panel>
</div>
</div>
</h:form>
</f:view>
</h:body>
DummyAjax.xhtml
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./resources/layout/Template.xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:sc="http://java.sun.com/jsf/composite/Controls">
<ui:define name="right-column">
<h1> f:ajax example using Facelets Templating</h1>
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<script src="/PrimeFacesLearning/javax.faces.resource/jsf.js.jsf?ln=javax.faces&stage=Development" type="text/javascript"></script>
<h:panelGrid id="panelGrid1">
<h:inputText value="#{ajaxEngine.firstname}" onkeyup="jsf.ajax.request(this, event,{render:'form1-text ${template.ajaxText.clientId} form1-count'}); return false">
</h:inputText>
<h:outputText id="text" value="#{ajaxEngine.firstname}" escape="false"/>
<br />
Firstname char count: <h:outputText id="count" value="#{ajaxEngine.count}" />
</h:panelGrid>
</ui:define>
</ui:composition>
/**
* This code will be automatically called when jsf.ajax.request will
* be populated from client side.
* Here we also set another property of DummyAjax - Integer count
* to manipulate other variables in managed bean.
* @param firstname
*/
public void setFirstname(String firstname) {
this.firstname = firstname;
setCount(getFirstname().length());
}
В приведенном выше коде у нас есть две страницы. Template.xhml и DummyAjax.xhtml в качестве клиента шаблона Facelets. В шаблоне у нас есть <h: outputText id = «ajaxText» binding = «# {template.ajaxText}» value = «$ {ajaxEngine.firstname}» />, а в DummyAjax.xhtml мы имеем
<h:inputText id="input1" value="#{ajaxEngine.firstname}" />
<h:outputText id="text" value="#{ajaxEngine.firstname}" escape="false"/>
Все эти три элемента управления ссылаются на одно свойство управляемого компонента: # {ajaxEngine.firstname}. Следующая интересная вещь — вызывать Ajax при каждом включении.
onkeyup="jsf.ajax.request(this, event,{render:'form1-text
${template.ajaxText.clientId} form1-count'}); return false"
Выражение метода для получения clientId каждого UIComponent:
form1-текст | # {Template.form1.findComponent ( «panelGrid1»). FindComponent ( «текст»). ClientId} |
form1-input1 | # {Template.form1.findComponent ( «panelGrid1»). FindComponent ( «вход1»). ClientID} |
Form1 подсчета | # {Template.form1.findComponent ( «panelGrid1»). FindComponent ( «Form1-счетчик»). ClientID} |
И, наконец, последняя вещь действительно полезна — это тело метода setFirstName (String firstname), где у нас есть шанс обновить столько свойств, сколько мы хотим.
Композиция элемента управления JavaServer Faces 2.0
Я бы не стал останавливаться на $ {cc.attr.id} только потому, что это работает так же, как и все содержимое статьи.
Краткий пример:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
xmlns:cc="http://java.sun.com/jsf/composite">
<!-- NO INTERFACE -->
<cc:interface>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
${cc.attrs.id},${cc.clientId} <br />
</cc:implementation>
</html>
<h:form id="form1" prependId="true">
<sc:Dummy id="dummy1" /><br />
<sc:Dummy id="dummy2" />
</hform>
<!--browser output-->
dummy1, form1-dummy1 <br />
dummy2,form1-dummy2
Краткое содержание статьи
Эта статья должна дать вам понимание того, как получить clientId в различных сценариях. Вы также должны знать, как использовать JSF 2.0 с jQuery, и вы узнали, как вызывать Ajax без тега f: ajax. Вы можете скачать исходный код из таблицы ниже.
Полезные ссылки
Язык выражения | Официальная ссылка на Java 6 EL. |
Пример составных компонентов. | Простой, но полезный пример использования CC. |
jsf.ajax. * javadoc | Полная ссылка на библиотеку jsf.js. |
JSF AJAX пример | Пример с f: actionListener и jsf.ajax.request (…) |
FireBug | Это один из лучших инструментов для просмотра html клиента, отладки Javascript и просмотра реальных запросов Ajax. |
PrimeFaces | Моя любимая библиотека тегов jsf. Использует jQuery в качестве движка Javascript. Много отличных элементов управления и, конечно, с открытым исходным кодом. |
Первая, вторая статья | В этой статье приводятся подробности о свойствах JSF clientId. |
JQuery | Эта библиотека упрощает жизнь разработчиков. |
Subversion хранилище кода. | Простой проект NetBeans, где я изучаю JSF 2.0 |