Skip to content

5. مقدمه‌ای بر کتابخانهٔ کامپوننت PrimeFaces

5.1. نقش PrimeFaces در یک برنامه JSF

بیایید به معماری یک برنامه JSF که در ابتدای این سند مورد بحث قرار گرفت، بازگردیم:

صفحات JSF با استفاده از سه کتابخانه تگ ساخته شده‌اند:

1
2
3
4
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  • خط ۲: تگ‌های <h:x> از فضای نام [http://java.sun.com/jsf/html]، که با تگ‌های HTML مطابقت دارند،
  • خط ۳: تگ‌های <f:y> از فضای نام [http://java.sun.com/jsf/core]، که با تگ‌های JSF مطابقت دارند،
  • خط ۴: تگ‌های <ui:z> از فضای نام [http://java.sun.com/jsf/facelets] که با تگ‌های facelet مطابقت دارند.

برای ساخت صفحات JSF، ما یک کتابخانه تگ چهارم را که شامل کامپوننت‌های PrimeFaces است، اضافه خواهیم کرد.

1
2
3
<html xmlns="http://www.w3.org/1999/xhtml"
      ...
xmlns:p="http://primefaces.org/ui">
  • خط ۳: تگ‌های <p:z> در فضای نام [http://primefaces.org/ui] با کامپوننت‌های PrimeFaces مطابقت دارند.

این تنها تغییری است که اعمال خواهد شد. بنابراین در ویوها ظاهر می‌شود. رویدادپردازها و مدل‌ها همان‌طور که در JSF بودند باقی می‌مانند. این نکته مهمی است که باید درک شود.

استفاده از کامپوننت‌های PrimeFaces به شما امکان می‌دهد رابط‌های وبی ایجاد کنید که به لطف کامپوننت‌های متعدد این کتابخانه، کاربرپسندتر و به لطف فناوری AJAX که به طور بومی از آن استفاده می‌کند، روان‌تر هستند. به این‌ها رابط‌های غنی یا RIA (برنامه‌های اینترنتی غنی) گفته می‌شود.

معماری JSF قبلی به معماری PF (PrimeFaces) زیر تبدیل می‌شود:

5.2. مزایای PrimeFaces

وب‌سایت PrimeFaces [http://www.primefaces.org/showcase/ui/home.jsf] فهرستی از کامپوننت‌هایی را که می‌توان در یک صفحه PF استفاده کرد، ارائه می‌دهد:

در مثال‌های پیش رو، از دو ویژگی اول PrimeFaces استفاده خواهیم کرد:

  • برخی از حدود صد کامپوننت ارائه‌شده،
  • رفتار بومی آنها AJAX.

از جمله کامپوننت‌های موجود:

ما در مثال‌هایمان تنها از حدود پانزده مورد از آن‌ها استفاده خواهیم کرد، اما این تعداد برای درک اصول ساخت یک صفحه PrimeFaces کافی خواهد بود.

5.3. آموزش PrimeFaces

PrimeFaces نمونه‌هایی از نحوه استفاده از هر یک از اجزای خود را ارائه می‌دهد. کافی است روی لینک مربوطه کلیک کنید. بیایید به یک مثال نگاه کنیم:

  • در [1]، مثال مربوط به کامپوننت [Spinner
  • در [2]، کادر محاوره‌ای که پس از کلیک روی دکمه [Submit] نمایش داده می‌شود.

در اینجا سه ویژگی جدید وجود دارد:

  • کامپوننت [Spinner]، که به‌طور پیش‌فرض در JSF وجود ندارد،
  • همین امر در مورد کادر گفتگو نیز صدق می‌کند،
  • و در نهایت، POST که توسط [Submit] فراخوانی می‌شود از AJAX استفاده می‌کند. اگر هنگام POST با دقت به مرورگر نگاه کنید، ساعت شنی را نخواهید دید. صفحه دوباره بارگذاری نمی‌شود. بلکه به سادگی تغییر می‌کند: یک مؤلفه جدید – در این مورد، پنجرهٔ گفتگو – روی صفحه ظاهر می‌شود.

بیایید ببینیم چگونه همه این‌ها محقق می‌شود. کد XHTML در مثال به شرح زیر است:


<h:form>
       <p:panel header="Spinners">
           <h:panelGrid id="grid" columns="2" cellpadding="5">
                <h:outputLabel for="spinnerBasic" value="Basic Spinner: " />
                <p:spinner id="spinnerBasic" value="#{spinnerController.number1}"/>
                <h:outputLabel for="spinnerStep" value="Step Factor: " />
                <p:spinner id="spinnerStep" value="#{spinnerController.number2}" stepFactor="0.25"/>
                <h:outputLabel for="minmax" value="Min/Max: " />
                <p:spinner id="minmax" value="#{spinnerController.number3}" min="0" max="100"/>
                <h:outputLabel for="prefix" value="Prefix: " />
                <p:spinner id="prefix" value="0" prefix="$" min="0" value="#{spinnerController.number4}"/>
           <h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
           <p:outputPanel>
                   <p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
                      <p:ajax update="ajaxspinnervalue" process="@this" />
               </p:spinner>
               <h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
            </p:outputPanel>
           </h:panelGrid>
       </p:panel>
    <p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
    
    <p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
        ...
     </p:dialog>
</h:form>

ابتدا توجه کنید که تگ‌های استاندارد JSF وجود دارند: <h:form> در خط ۱، <h:panelGrid> در خط ۳، <h:outputLabel> در خط ۴. برخی از برچسب‌های JSF توسط PF به ارث برده شده و بهبود یافته‌اند: <p:commandButton> خط ۲۱. سپس، تگ‌های قالب‌بندی PF وجود دارند: <p:panel> خط ۲، <p:outputPanel> خط ۱۳، <p:dialog> خط ۲۳. در نهایت، تگ‌های ورودی وجود دارند: <p:spinner> خط ۵.

بیایید این کد را در ارتباط با نما تحلیل کنیم:

  • در [1]، کامپوننتی که از تگ <p:panel> در خط ۲ به دست آمده است،
  • در [2]، فیلد ورودی ایجاد شده با ترکیب یک تگ <p:outputLabel> و یک تگ <p:spinner>، در خطوط 6 و 7،
  • به [3]، دکمه برای POST که با استفاده از تگ <p:commandButton> در خط 21 ایجاد شده است،
  • در [4]، کادر محاوره‌ای در خطوط 23–25،
  • [5]، یک کانتینر نامرئی برای دو کامپوننت است. این کانتینر توسط تگ <p:outputPanel> در خط ۱۳ ایجاد می‌شود.

بیایید کد زیر را که یک اقدام AJAX را پیاده‌سازی می‌کند، تحلیل کنیم:


           <h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
           <p:outputPanel>
                   <p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
                      <p:ajax update="ajaxspinnervalue" process="@this" />
               </p:spinner>
               <h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
</p:outputPanel>

این کد نمای زیر را تولید می‌کند:

  • خط ۱: متن [1] را نمایش می‌دهد. این همچنین به عنوان برچسب برای کامپوننت id=ajaxspinner (برای ویژگی) عمل می‌کند. این کامپوننت همان کامپوننت موجود در خط ۳ (ویژگی id) است،
  • خطوط ۳–۵: مؤلفه [2] را نمایش می‌دهند. این مؤلفه یک مؤلفه ورودی/نمایشی مرتبط با قالب #{spinnerController.number5} (ویژگی مقدار) است،
  • خط ۶: مؤلفه [3] را نمایش می‌دهد. این مؤلفه یک مؤلفه نمایشی است که به قالب #{spinnerController.number5} (ویژگی value) متصل است،
  • خط ۴: تگ <p:ajax> یک رفتار AJAX را به spinner اضافه می‌کند. هرگاه مقدار دومی تغییر کند، یک POST با آن مقدار (با ویژگی process که روی "@this" تنظیم شده) به قالب # ارسال می‌شود.{spinnerController.number5}. پس از انجام این کار، صفحه به‌روزرسانی می‌شود (atribut update). مقدار این atribut شناسه (ID) یک کامپوننت روی صفحه است، در این مورد کامپوننتی که در خط ۶ قرار دارد. سپس کامپوننت هدف atribut update با مدل به‌روزرسانی می‌شود. این بار دیگر #{spinnerController.number5} است، یعنی مقدار spinner. بنابراین، فیلد [3] ورودی‌های فیلد [2] را دنبال می‌کند.

این یک مثال از رفتار AJAX است، مخففی که به معنای جاوااسکریپت غیرهمزمان و XML می‌باشد. به طور کلی، رفتار AJAX به شرح زیر عمل می‌کند:

  • مرورگر یک صفحه HTML را نمایش می‌دهد که حاوی کد جاوااسکریپت (J در AJAX) است. عناصر صفحه یک شیء جاوااسکریپت را تشکیل می‌دهند که به عنوان DOM (مدل شیء مستندات) شناخته می‌شود،
  • سرور میزبان برنامه وبی است که این صفحه را تولید کرده است،
  • در [1]، رویدادی در صفحه رخ می‌دهد. به عنوان مثال، افزایش مقدار spinner. این رویداد توسط جاوااسکریپت مدیریت می‌شود،
  • در [2]، جاوااسکریپت یک POST را روی برنامه وب اجرا می‌کند. این کار را به‌صورت غیرهم‌زمان انجام می‌دهد (حرف «A» در AJAX). کاربر می‌تواند به کار با صفحه ادامه دهد. صفحه مسدود نمی‌شود، اما در صورت لزوم می‌توان آن را مسدود کرد. POST قالب صفحه را با استفاده از مقادیر ارسال‌شده، در این مورد قالب #{spinnerController.number5}، به‌روزرسانی می‌کند،
  • به [3]؛ برنامه وب پاسخی را به جاوااسکریپت بازمی‌گرداند، که یا XML (X در AJAX) یا JSON است (نشانه‌گذاری شیء JavaScript
  • در [4]، جاوااسکریپت از این پاسخ برای به‌روزرسانی ناحیه خاصی از DOM استفاده می‌کند، که در این مورد ناحیه id=ajaxspinnervalue است.

هنگام استفاده از JSF و PrimeFaces، جاوااسکریپت توسط PrimeFaces تولید می‌شود. این کتابخانه بر کتابخانه جاوااسکریپت JQuery متکی است. به همین ترتیب، کامپوننت‌های PrimeFaces به کامپوننت‌های موجود در کتابخانه‌های JQuery و UI (رابط کاربری) متکی هستند. بنابراین، JQuery اساس PrimeFaces را تشکیل می‌دهد.

بیایید به مثال خود بازگردیم و اکنون به POST برای دکمه [Submit] نگاه کنیم:

کد مرتبط با POST به شرح زیر است:


<p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
    
    <p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
        <h:panelGrid id="display" columns="2" cellpadding="5">
            <h:outputText value="Value 1: " />
            <h:outputText value="#{spinnerController.number1}" /> 
            
            <h:outputText value="Value 2: " />
            <h:outputText value="#{spinnerController.number2}" /> 
            
            <h:outputText value="Value 3: " />
            <h:outputText value="#{spinnerController.number3}" /> 
            
            <h:outputText value="Value 4: " />
            <h:outputText value="#{spinnerController.number4}" /> 
            
            <h:outputText value="Value 5: " />
            <h:outputText value="#{spinnerController.number5}" /> 
        </h:panelGrid>
     </p:dialog>
                
</h:form>
  • خط ۱: POST توسط دکمه در خط ۱ فراخوانی می‌شود. در PrimeFaces، تگ‌هایی که یک POST را فراخوانی می‌کنند، به طور پیش‌فرض این کار را از طریق یک فراخوانی AJAX انجام می‌دهند. به همین دلیل است که این تگ‌ها دارای ویژگی `update` هستند تا فیلدی را که پس از دریافت پاسخ سرور باید به‌روزرسانی شود، مشخص کنند. در اینجا، فیلدی که به‌روزرسانی می‌شود، panelGrid در خط ۴ است. بنابراین، با بازگشت POST، این فیلد با مقادیر ارسال‌شده به مدل به‌روزرسانی خواهد شد. با این حال، آن‌ها در داخل یک کادر گفتگو قرار دارند که به طور پیش‌فرض پنهان است. این ویژگی `oncomplete` در خط ۱ است که آن را نمایش می‌دهد. این رویداد پس از اتمام پردازش `POST` رخ می‌دهد. مقدار این ویژگی کد جاوااسکریپت است. در اینجا، ما کادر محاوره‌ای با id=dialog را نمایش می‌دهیم، یعنی همان کادر محاوره‌ای در خط ۳ (ویژگی widgetVar
  • خط ۳: می‌توانیم ویژگی‌های مختلف کادر گفتگو را ببینیم. برای اینکه بفهمید هر کدام چه کاری انجام می‌دهند، باید آزمایش کنید.

ما به قالب اشاره کردیم اما هنوز آن را نشان نداده‌ایم. این هم از آن:

public class SpinnerController {

    private int number1;
    private double number2;
    private int number3;
    private int number4;
    private int number5;

     // گیرنده و تنظیم‌کننده
...
}

به‌طور کلی، می‌توانید به شرح زیر عمل کنید:

  • کامپوننت PrimeFaces مورد نظر خود را شناسایی کنید،
  • مثال آن را مطالعه کنید. مثال‌های PrimeFaces به‌خوبی طراحی شده‌اند و آسان برای درک هستند.

5.4. اولین پروژه PrimeFaces: mv-pf-01

بیایید یک پروژه وب Maven را با استفاده از NetBeans راه‌اندازی کنیم:

  • [1, 2, 3]: ما در حال ایجاد یک پروژه Maven از نوع [Web Application] هستیم،
  • [4]: سرور تام‌کت خواهد بود،
  • در [5]، پروژهٔ تولیدشده،
  • در [6]، فایل [index.jsp] و پکیج جاوا را حذف می‌کنیم،
  • در [7, 8]: در ویژگی‌های پروژه، پشتیبانی از Java Server Faces را اضافه می‌کنیم،
  • به [9]؛ در زبانه [Components]، کتابخانه کامپوننت PrimeFaces را انتخاب کنید. NetBeans از کتابخانه‌های کامپوننت دیگر نیز پشتیبانی می‌کند: ICEFaces و RichFaces.
  • در [10]، پروژهٔ تولیدشده. در [11]، وابستگی به PrimeFaces را توجه کنید.

به‌طور ساده، یک پروژه PrimeFaces یک پروژه استاندارد JSF است که وابستگی به PrimeFaces به آن اضافه شده است. بیش از این نیست.

با درک این موضوع، فایل [pom.xml] را برای کار با آخرین نسخه‌های کتابخانه‌ها اصلاح می‌کنیم:


    <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-impl</artifactId>
      <version>2.1.8</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.primefaces</groupId>
      <artifactId>primefaces</artifactId>
      <version>3.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-web-api</artifactId>
      <version>6.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>jsf20</id>
      <name>Repository for library Library[jsf20]</name>
      <url>http://download.java.net/maven/2/</url>
    </repository>
    <repository>
      <id>primefaces</id>
      <name>Repository for library Library[primefaces]</name>
      <url>http://repository.primefaces.org/</url>
    </repository>
</repositories>

خطوط ۲۶–۳۰: به مخزن Maven برای PrimeFaces توجه کنید. پس از اعمال این تغییرات، پروژه را بیلد می‌کنیم تا دانلود وابستگی‌ها آغاز شود. سپس پروژه [12] را به دست می‌آوریم.

اکنون، بیایید سعی کنیم مثالی را که بررسی کردیم بازتولید کنیم. صفحه [index.html] به شکل زیر درمی‌آید:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head>
    <title>Spinner</title>
  </h:head>
  <h:body>
    <!-- فرم -->
    <h:form>
      <p:panel header="Spinners">
        <h:panelGrid id="grid" columns="2" cellpadding="5">
          <h:outputLabel for="spinnerBasic" value="Basic Spinner: " />
          <p:spinner id="spinnerBasic" value="#{spinnerController.number1}"/>
          <h:outputLabel for="spinnerStep" value="Step Factor: " />
          <p:spinner id="spinnerStep" value="#{spinnerController.number2}" stepFactor="0.25"/>
          <h:outputLabel for="minmax" value="Min/Max: " />
          <p:spinner id="minmax" value="#{spinnerController.number3}" min="0" max="100"/>
          <h:outputLabel for="prefix" value="Prefix: " />
          <p:spinner id="prefix" prefix="$" min="0" value="#{spinnerController.number4}"/>
          <h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
          <p:outputPanel>
            <p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
              <p:ajax update="ajaxspinnervalue" process="@this" />
            </p:spinner>
            <h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
          </p:outputPanel>
        </h:panelGrid>
      </p:panel>
      <p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
      <!-- جعبه‌ی گفتگو -->
      <p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
        <h:panelGrid id="display" columns="2" cellpadding="5">
          <h:outputText value="Value 1: " />
          <h:outputText value="#{spinnerController.number1}" /> 
          <h:outputText value="Value 2: " />
          <h:outputText value="#{spinnerController.number2}" /> 
          <h:outputText value="Value 3: " />
          <h:outputText value="#{spinnerController.number3}" /> 
          <h:outputText value="Value 4: " />
          <h:outputText value="#{spinnerController.number4}" /> 
          <h:outputText value="Value 5: " />
          <h:outputText value="#{spinnerController.number5}" /> 
        </h:panelGrid>
      </p:dialog>
    </h:form>
  </h:body>
</html>

خط ۵ را فراموش نکنید که فضای نام (namespace) کتابخانه تگ PrimeFaces را اعلام می‌کند. ما بیانی (bean) که به‌عنوان مدل صفحه عمل می‌کند را به پروژه اضافه می‌کنیم:

  

بیان به شرح زیر است:


package beans;

import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean
@RequestScoped
public class SpinnerController {

  // قالب
  private int number1;
  private double number2;
  private int number3;
  private int number4;
  private int number5;

  // گیرنده‌ها و تنظیم‌کننده‌ها
  ...
}

این کلاس یک بین (خط ۶) با دامنه درخواست (خط ۷) است. از آنجایی که هیچ نامی مشخص نشده است، بین نام کلاس را با اولین حرف کوچک می‌گیرد: spinnerController.

وقتی پروژه اجرا می‌شود، خروجی زیر تولید می‌شود:

 

بدین ترتیب ما به تازگی نحوه تست یک مثال گرفته شده از وب‌سایت PrimeFaces را نشان دادیم. تمام مثال‌ها را می‌توان به این روش تست کرد.

در ادامه، ما صرفاً بر روی برخی از کامپوننت‌های PrimeFaces تمرکز خواهیم کرد. ابتدا، مثال‌هایی را که با استفاده از JSF مطالعه کرده‌ایم، مجدداً بررسی کرده و برخی از تگ‌های JSF را با تگ‌های PrimeFaces جایگزین خواهیم کرد. ظاهر صفحات کمی تغییر خواهد کرد؛ آن‌ها مانند AJAX رفتار خواهند کرد، اما نیازی به تغییر بیین‌های مربوطه نخواهد بود. در هر یک از مثال‌های بعدی، ما صرفاً کد XHTML صفحات و اسکرین‌شات‌های مربوطه را ارائه خواهیم داد. از خوانندگان دعوت می‌شود تا مثال‌ها را آزمایش کنند تا تفاوت‌های بین صفحات JSF و صفحات PF را شناسایی کنند.

5.5. مثال mv-pf-02: مدیر رویداد – بین‌المللی‌سازی – ناوبری بین صفحات

این پروژه، نسخه تطبیق‌یافته پروژه‌های JSF و [mv-jsf2-02] (بند ۲.۴، صفحه ۴۱) است:

پروژه NetBeans به شرح زیر است:

صفحه [index.html] به شرح زیر است:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <f:view locale="#{changeLocale.locale}">
    <h:head>
      <title><h:outputText value="#{msg['welcome.titre']}" /></title>
    </h:head>
    <body>
      <h:form id="formulaire">
        <h:panelGrid columns="2">
          <p:commandLink value="#{msg['welcome.langue1']}" action="#{changeLocale.setFrenchLocale}" ajax="false"/>
          <p:commandLink value="#{msg['welcome.langue2']}" action="#{changeLocale.setEnglishLocale}" ajax="false"/>
        </h:panelGrid>
        <h1><h:outputText value="#{msg['welcome.titre']}" /></h1>
        <p:commandLink value="#{msg['welcome.page1']}" action="page1" ajax="false"/>
      </h:form>
    </body>
  </f:view>
</html>

در خطوط ۱۵، ۱۶ و ۱۹، تگ‌های <h:commandLink> با تگ‌های <p:commandLink> جایگزین شده‌اند. این تگ به‌طور پیش‌فرض مانند AJAX رفتار می‌کند، اما این رفتار را می‌توان با تنظیم ویژگی ajax="false" غیرفعال کرد. بنابراین در اینجا، تگ‌های <p:commandLink> مانند تگ‌های <h:commandLink> رفتار می‌کنند: صفحه هنگام کلیک روی این لینک‌ها دوباره بارگیری می‌شود.

5.6. مثال mv-pf-03: چیدمان صفحه با استفاده از Facelets

این پروژه ایجاد صفحات XHTML را با استفاده از قالب‌های Facelets از مثال [mv-jsf2-09] (بخش 2.11) نشان می‌دهد:

 

پروژه NetBeans به شرح زیر است:

  • در [1]، فایل‌های پیکربندی پروژه در JSF،
  • در [2]، صفحات در XHTML،
  • به [3]، بین پشتیبانی برای تغییر زبان،
  • در [4]، فایل‌های پیام،
  • به [5]، وابستگی‌ها.

صفحات پروژه بر اساس صفحه [layout.xhtml] مدل شده‌اند:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <f:view locale="#{changeLocale.locale}">
    <h:head>
      <title>JSF</title>
      <h:outputStylesheet library="css" name="styles.css"/>
    </h:head>
    <h:body style="background-image: url('${request.contextPath}/resources/images/standard.jpg');">
      <h:form id="formulaire">
        <table style="width: 600px">
          <tr>
            <td colspan="2" bgcolor="#ccccff">
              <ui:include src="entete.xhtml"/>
            </td>
          </tr>
          <tr>
            <td style="width: 100px; height: 200px" bgcolor="#ffcccc">
              <ui:include src="menu.xhtml"/>
            </td>
            <td>
              <p:outputPanel id="contenu">
                <ui:insert name="contenu" >
                  <h2>Contenu</h2>
                </ui:insert>
              </p:outputPanel>
            </td>
          </tr>
          <tr bgcolor="#ffcc66">
            <td colspan="2">
              <ui:include src="basdepage.xhtml"/>
            </td>
          </tr>         
        </table>
      </h:form>
    </h:body>
  </f:view>
</html>
  • خط ۹: یک تگ <f:view> کل صفحه را در بر می‌گیرد تا از بین‌المللی‌سازی که فراهم می‌کند، بهره‌مند شود،
  • خط ۱۵: یک فرم با شناسه 'form'. این فرم بدنه صفحه را تشکیل می‌دهد. در این بدنه تنها یک بخش پویا وجود دارد که شامل خطوط ۲۸–۳۰ است. اینجاست که بخش متغیر صفحه درج خواهد شد:
  • منطقهٔ کادر‌دار بالا با فراخوانی‌های AJAX به‌روزرسانی خواهد شد. برای شناسایی آن، ما آن را در یک کانتینر PrimeFaces قرار داده‌ایم که توسط تگ <p:outputPanel> (خط ۲۷) ایجاد شده است. و این کانتینر «content» نامگذاری شده است (ویژگی id). از آنجایی که این کانتینر در داخل یک فرم قرار دارد که خود یک کانتینر با نام «form» است، نام کامل این ناحیه پویا به صورت زیر است:form:content. اولین «:» نشان می‌دهد که ما از ریشه سند شروع می‌کنیم، سپس به کانتینر با نام «form» و بعد به کانتینر با نام «content» می‌رویم. یکی از دشواری‌های AJAX، نام‌گذاری صحیح فیلدهایی است که باید توسط فراخوانی AJAX به‌روزرسانی شوند. ساده‌ترین راه این است که به کد منبع صفحه HTML دریافتی نگاه کنید:

1
2
3
            <td><span id="formulaire:contenu">
                  <h2>Contenu</h2></span>
</td>

در بالا، می‌بینیم که تگ <h:outputPanel> یک تگ <span> از نوع HTML ایجاد کرده است. در این مثال، نام نسبی 'form:content' (بدون ':' ابتدایی) و نام کامل ':form:content' (با ':' ابتدایی) به یک شیء واحد اشاره دارند.

شایان ذکر است که فراخوانی‌های AJAX (<p:commandButton>, <p:commandLink>) که ناحیه پویا را به‌روزرسانی می‌کنند، دارای ویژگی update=":form:content" خواهند بود.

صفحه [index.xhtml] تنها صفحه‌ای است که توسط پروژه نمایش داده می‌شود:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <ui:fragment rendered="#{requestScope.page1 || requestScope.page2==null}">
        <ui:include src="page1.xhtml"/>
      </ui:fragment>
      <ui:fragment rendered="#{requestScope.page2}">
        <ui:include src="page2.xhtml"/>
      </ui:fragment>
    </ui:define>
  </ui:composition>
</html>
  • خط ۸: قالب برای [index.xhtml] همان صفحه‌ای است که به تازگی در [layout.xhtml] توصیف شد؛
  • خط ۹: این فیلد شناسه محتوا است که توسط [index.html] به‌روزرسانی می‌شود. در داخل این فیلد، دو قطعه وجود دارد:
    • قطعه [page1.xhtml] در خط ۱۱؛
    • قطعه [page2.xhtml] در خط 14.

این دو قطعه با یکدیگر ناسازگار هستند.

  • خط ۱۰: قطعه [page1.xhtml] در صورتی نمایش داده می‌شود که ویژگی 'page1' روی 'true' تنظیم شده باشد یا ویژگی 'page2' وجود نداشته باشد. این حالت برای اولین درخواست صادق است، جایی که هیچ‌کدام از این ویژگی‌ها در درخواست وجود نخواهد داشت. در این حالت، قطعه [page1.xhtml] نمایش داده می‌شود؛
  • خط ۱۱؛ قطعه [page2.xhtml] نمایش داده می‌شود اگر درخواست دارای ویژگی 'page2' با مقدار 'true' باشد

قطعه [page1.xhtml] به شرح زیر است:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <body>
    <h:panelGrid columns="2">
      <p:commandLink value="#{msg['page1.langue1']}" actionListener="#{changeLocale.setFrenchLocale}" ajax="true" update=":formulaire:contenu"/>
      <p:commandLink value="#{msg['page1.langue2']}" actionListener="#{changeLocale.setEnglishLocale}" ajax="true" update=":formulaire:contenu"/>
    </h:panelGrid>
    <h1><h:outputText value="#{msg['page1.titre']}" /></h1>
     <p:commandLink value="#{msg['page1.lien']}" update=":formulaire:contenu">
      <f:setPropertyActionListener value="#{true}" target="#{requestScope.page2}" />  
    </p:commandLink>
  </body>
</html>

و محتوای زیر را نمایش می‌دهد:

  • خطوط ۱۱ و ۱۲: دو لینک برای تغییر زبان. این دو لینک فراخوانی‌های AJAX (ajax=true) را راه‌اندازی می‌کنند. این تنظیم پیش‌فرض است. بنابراین می‌توانید ویژگی ajax=true را حذف کنید. ما بعداً این کار را دوباره انجام نخواهیم داد. توجه داشته باشید که این دو پیوند ناحیه :form:content (ویژگی update) را که در بالا برجسته شده است، به‌روزرسانی می‌کنند،
  • خط ۱۵: یک لینک ناوبری AJAX که بار دیگر ناحیه :form:content را به‌روزرسانی می‌کند،
  • خط 16: تگ <h:setPropertyActionListener> برای تنظیم ویژگی 'page2' در درخواست به مقدار 'true' استفاده می‌شود. این باعث می‌شود که قطعه [page2.xhtml] (خط ۶ زیر) در صفحه [index.xhtml] نمایش داده شود:

  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <ui:fragment rendered="#{requestScope.page1 || requestScope.page2==null}">
        <ui:include src="page1.xhtml"/>
      </ui:fragment>
      <ui:fragment rendered="#{requestScope.page2}">
        <ui:include src="page2.xhtml"/>
      </ui:fragment>
    </ui:define>
</ui:composition>

قطعه [page2.xhtml] مشابه است:

کد برای [page2.xhtml] به شرح زیر است:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <body>
    <h1><h:outputText value="#{msg['page2.entete']}"/></h1>
    <p:commandLink value="#{msg['page2.lien']}" update=":formulaire:contenu">
      <f:setPropertyActionListener value="#{true}" target="#{requestScope.page1}" />  
    </p:commandLink>
  </body>
</html>

از این مثال، نکات زیر را برای ادامهٔ سند مد نظر قرار خواهیم داد:

  • ما از قالب [layout.xhtml] به عنوان قالب صفحه استفاده خواهیم کرد،
  • منطقه پویا با شناسه ID:form:content مشخص می‌شود و از طریق فراخوانی AJAX به‌روزرسانی خواهد شد.

5.7. مثال mv-pf-04: فرم ورود داده

این پروژه پورتی از پروژه‌های JSF2 و [mv-jsf2-03] است (به بخش 2.5 مراجعه کنید):

پروژه NetBeans به شرح زیر است:

در [1] که در بالا نشان داده شده است، صفحات XHTML پروژه قرار دارند. چیدمان توسط قالب [layout.xhtml] که قبلاً مورد بحث قرار گرفت، ارائه می‌شود. صفحه [index.xhtml] تنها صفحه پروژه است. این صفحه در ناحیه :form:content نمایش داده می‌شود. کد آن به شرح زیر است:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <ui:include src="page1.xhtml"/>
    </ui:define>
  </ui:composition>
</html>

این به سادگی قطعه [page1.xhtml] را نمایش می‌دهد. این معادل فرم بررسی‌شده در مثال [mv-jsf2-03] است. به یاد داشته باشید که هدف آن فرم نمایش تگ‌های ورودی JSF بود. این تگ‌ها در اینجا با تگ‌های PrimeFaces جایگزین شده‌اند.

PanelGrid

برای استایل‌دهی به عناصر در [page1.xhtml]، از تگ <p:panelGrid> استفاده می‌کنیم. برای مثال، برای دو لینک زبان:


<!-- زبان‌ها -->
    <p:panelGrid columns="2">
      <p:commandLink value="#{msg['form.langue1']}" actionListener="#{changeLocale.setFrenchLocale}" update=":formulaire:contenu"/>
      <p:commandLink value="#{msg['form.langue2']}" actionListener="#{changeLocale.setEnglishLocale}" update=":formulaire:contenu"/>
    </p:panelGrid>

این خروجی زیر را تولید می‌کند:

 

شکل دیگری از تگ <p:panelGrid> به شرح زیر است:


<p:panelGrid>

      <f:facet name="header">  
        <p:row>  
          <p:column colspan="3"><h:outputText value="#{msg['form.titre']}"/></p:column>  
        </p:row>  
        <p:row>  
          <p:column><h:outputText value="#{msg['form.headerCol1']}"/></p:column>  
          <p:column><h:outputText value="#{msg['form.headerCol2']}"/></p:column>  
          <p:column><h:outputText value="#{msg['form.headerCol3']}"/></p:column>  
        </p:row>  
      </f:facet>        

      <p:row>
        <p:column>
          <h:outputText value="inputText"/>
        </p:column>
        <p:column>
          <h:outputLabel for="inputText" value="#{msg['form.loginPrompt']}" />  
          <p:inputText id="inputText" value="#{form.inputText}"/>
        </p:column>
        <p:column>
          <h:outputText id="inputTextValue" value="#{form.inputText}"/>
        </p:column>
      </p:row>
...
     <f:facet name="footer">
        <p:row>
          <p:column colspan="3">
            <div align="center">
              <p:commandButton value="#{msg['form.submitText']}" update=":formulaire:contenu"/>
            </div>
          </p:column>
        </p:row>
      </f:facet>    
</p:panelGrid>

رده‌ها و ستون‌های جدول با تگ‌های <p:row> و <p:column> مشخص می‌شوند.

خطوط ۳–۱۲ سربرگ جدول را تعریف می‌کنند:

 

خطوط 14–25 یک ردیف از جدول را تعریف می‌کنند:

 

خطوط ۲۷–۳۵ پاورقی جدول را تعریف می‌کنند:

 

inputText


      <p:row>
        <p:column>
          <h:outputText value="inputText"/>
        </p:column>
        <p:column>
          <h:outputLabel for="inputText" value="#{msg['form.loginPrompt']}" />  
          <p:inputText id="inputText" value="#{form.inputText}"/>
        </p:column>
        <p:column>
          <h:outputText id="inputTextValue" value="#{form.inputText}"/>
        </p:column>
</p:row>
 

رمز عبور


<p:row>
        <p:column>
          <h:outputText value="inputSecret"/>
        </p:column>
        <p:column>
          <h:outputLabel for="inputSecret" value="#{msg['form.passwdPrompt']}"/>
          <p:password id="inputSecret" value="#{form.inputSecret}" feedback="true"   
               promptLabel="#{msg['form.promptLabel']}" weakLabel="#{msg['form.weakLabel']}"  
               goodLabel="#{msg['form.goodLabel']}" strongLabel="#{msg['form.strongLabel']}" />  
        </p:column>
        <p:column>
          <h:outputText id="inputSecretValue" value="#{form.inputSecret}"/>
        </p:column>
      </p:row>

خط ۷: ویژگی feedback=true بازخوردی درباره کیفیت رمز عبور ارائه می‌دهد. [1]

inputTextArea


<p:row>
        <p:column>
          <h:outputText value="inputTextArea"/>
        </p:column>
        <p:column>
          <h:outputLabel for="inputTextArea" value="#{msg['form.descPrompt']}"/>
          <p:editor id="inputTextArea" value="#{form.inputTextArea}" rows="4"/>
        </p:column> 
        <p:column>
          <h:outputText id="inputTextAreaValue" value="#{form.inputTextArea}"/>
        </p:column>
      </p:row>

خط ۷: تگ <p:editor> یک ویرایشگر متن غنی نمایش می‌دهد که به شما امکان می‌دهد متن را قالب‌بندی کنید (فونت، اندازه، رنگ، ترازبندی و غیره). آنچه به سرور ارسال می‌شود، کد HTML برای متن واردشده [2] است.

selectOneListBox


<p:row>
        <p:column>
          <h:outputText value="selectOneListBox"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectOneListBox1" value="#{msg['form.selectOneListBox1Prompt']}"/>
          <p:selectOneListbox id="selectOneListBox1" value="#{form.selectOneListBox1}">
            <f:selectItem itemValue="1" itemLabel="un"/>
            <f:selectItem itemValue="2" itemLabel="deux"/>
            <f:selectItem itemValue="3" itemLabel="trois"/>
          </p:selectOneListbox>
        </p:column>
        <p:column>
          <h:outputText id="selectOneListBox1Value" value="#{form.selectOneListBox1}"/>
        </p:column>
      </p:row>
 

selectOneMenu


<p:row>
        <p:column>
          <h:outputText value="selectOneMenu"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectOneMenu" value="#{msg['form.selectOneMenuPrompt']}"/>
          <p:selectOneMenu id="selectOneMenu" value="#{form.selectOneMenu}">
            <f:selectItem itemValue="1" itemLabel="un"/>
            <f:selectItem itemValue="2" itemLabel="deux"/>
            <f:selectItem itemValue="3" itemLabel="trois"/>
            <f:selectItem itemValue="4" itemLabel="quatre"/>
            <f:selectItem itemValue="5" itemLabel="cinq"/>
          </p:selectOneMenu>
        </p:column>
        <p:column>
          <h:outputText id="selectOneMenuValue" value="#{form.selectOneMenu}"/>
        </p:column>
      </p:row>
 

selectManyMenu


<p:row>
        <p:column>
          <h:outputText value="selectManyMenu"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectManyMenu" value="#{msg['form.selectManyMenuPrompt']}"/>
          <p:selectManyMenu id="selectManyMenu" value="#{form.selectManyMenu}" >
            <f:selectItem itemValue="1" itemLabel="un"/>
            <f:selectItem itemValue="2" itemLabel="deux"/>
            <f:selectItem itemValue="3" itemLabel="trois"/>
            <f:selectItem itemValue="4" itemLabel="quatre"/>
            <f:selectItem itemValue="5" itemLabel="cinq"/>
          </p:selectManyMenu>
          <p:commandLink value="#{msg['form.buttonRazText']}" actionListener="#{form.clearSelectManyMenu()}" update=":formulaire:selectManyMenu" style="margin-left: 10px"/>
        </p:column>
        <p:column>
          <h:outputText id="selectManyMenuValue" value="#{form.selectManyMenuValue}"/>
        </p:column>
      </p:row>
 

در خط ۱۴، توجه کنید که لینک [Raz] فیلد :form:selectManyMenu که با کامپوننت در خط ۶ مطابقت دارد – را با مقدار AJAX به‌روز می‌کند. با این حال، مهم است بدانیم که در طول فرآیند POST AJAX، تمام مقادیر فرم ارسال می‌شوند. بنابراین، کل قالب به‌روزرسانی می‌شود. با این قالب، اما تنها فیلد :form:selectManyMenu به‌روزرسانی می‌شود.

selectBooleanCheckbox


<p:row>
        <p:column>
          <h:outputText value="selectBooleanCheckbox"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectBooleanCheckbox" value="#{msg['form.selectBooleanCheckboxPrompt']}"/>
          <p:selectBooleanCheckbox id="selectBooleanCheckbox" value="#{form.selectBooleanCheckbox}"/>
        </p:column>
        <p:column>
          <h:outputText id="selectBooleanCheckboxValue" value="#{form.selectBooleanCheckbox}"/>
        </p:column>
      </p:row>
 

selectManyCheckbox


<p:row>
        <p:column>
          <h:outputText value="selectManyCheckbox"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectManyCheckbox" value="#{msg['form.selectManyCheckboxPrompt']}"/>
          <p:selectManyCheckbox id="selectManyCheckbox" value="#{form.selectManyCheckbox}">
            <f:selectItem itemValue="1" itemLabel="rouge"/>
            <f:selectItem itemValue="2" itemLabel="bleu"/>
            <f:selectItem itemValue="3" itemLabel="blanc"/>
            <f:selectItem itemValue="4" itemLabel="noir"/>
          </p:selectManyCheckbox>
        </p:column>
        <p:column>
          <h:outputText id="selectManyCheckboxValue" value="#{form.selectManyCheckboxValue}"/>
        </p:column>
      </p:row>
 

selectOneRadio


<p:row>
        <p:column>
          <h:outputText value="selectOneRadio"/>
        </p:column>
        <p:column>
          <h:outputLabel for="selectOneRadio" value="#{msg['form.selectOneRadioPrompt']}"/>
          <p:selectOneRadio id="selectOneRadio" value="#{form.selectOneRadio}" >
            <f:selectItem itemValue="1" itemLabel="voiture"/>
            <f:selectItem itemValue="2" itemLabel="vélo"/>
            <f:selectItem itemValue="3" itemLabel="scooter"/>
            <f:selectItem itemValue="4" itemLabel="marche"/>
          </p:selectOneRadio>
        </p:column>
        <p:column>
          <h:outputText id="selectOneRadioValue" value="#{form.selectOneRadio}"/>
        </p:column>
      </p:row>
 

5.8. مثال: mv-pf-05: فهرست‌های پویا

این پروژه یک پورت از پروژه JSF2 [mv-jsf2-04] است (به بخش 2.6 مراجعه کنید):

Image

این پروژه در مقایسه با پروژه قبلی، هیچ تگ PrimeFaces جدیدی معرفی نمی‌کند. بنابراین، ما در مورد آن توضیحی ارائه نخواهیم داد. این پروژه بخشی از فهرست مثال‌هایی است که در وب‌سایت مستندات در دسترس خواننده قرار گرفته است.

5.9. مثال: mv-pf-06: ناوبری – جلسه – مدیریت استثنا

این پروژه یک نسخهٔ منتقل‌شده (port) از پروژهٔ JSF2 [mv-jsf2-05] است (به بخش 2.7 مراجعه کنید):

بار دیگر، این مثال هیچ تگ جدید PrimeFaces را معرفی نمی‌کند. ما فقط در مورد جدول لینک‌های نمایش‌داده‌شده در کادر بالا توضیح خواهیم داد:


<p:panelGrid columns="6">
  <p:commandLink value="1" action="form1?faces-redirect=true" ajax="false"/>
  <p:commandLink value="2" action="#{form.doAction2}" ajax="false"/>
  <p:commandLink value="3" action="form3?faces-redirect=true" ajax="false"/>
  <p:commandLink value="4" action="#{form.doAction4}" ajax="false"/>
  <p:commandLink value="#{msg['form.pagealeatoireLink']}" action="#{form.doAlea}" ajax="false"/>
  <p:commandLink value="#{msg['form.exceptionLink']}" action="#{form.throwException}" ajax="false"/>
</p:panelGrid>
  • تمام لینک‌ها دارای ویژگی `ajax=false` هستند. بنابراین صفحه به طور معمول بارگیری می‌شود؛
  • به خطوط ۲ و ۴ توجه کنید که نشان می‌دهند چگونه یک هدایت (redirection) را انجام دهیم.

5.10. مثال: mv-pf-07: اعتبارسنجی و تبدیل ورودی کاربر

این پروژه، نسخهٔ تطبیق‌یافتهٔ پروژه‌های JSF2 و [mv-jsf2-06] است (به بخش ۲.۸ مراجعه کنید):

Image

این برنامه دو تگ جدید معرفی می‌کند، تگ <p:messages>:


<p:messages globalOnly="true"/>

Image

و تگ <p:message>:


<p:inputText id="saisie1" value="#{form.saisie1}" styleClass="saisie"/>
<p:message for="saisie1" styleClass="error"/>

در مقایسه با تگ <h:message> در JSF، تگ <p:message> در PF تغییرات زیر را معرفی می‌کند:

  • ظاهر پیام خطا متفاوت است ([1])،
  • میدانی که حاوی ورودی نادرست است در [2] با یک حاشیه قرمز احاطه شده است.

5.11. مثال: mv-pf-08: رویدادهای مربوط به تغییرات در وضعیت مؤلفه

این پروژه یک پورت از پروژه‌های JSF2 و [mv-jsf2-07] است (به بخش 2.9 مراجعه کنید):

Image

پروژه JSF مفهوم listeners را معرفی کرد. مدیریت listener با PrimeFaces به شیوه‌ای متفاوت پیاده‌سازی شد.

با JSF:

1
2
3
4
5
6
7
         <!-- خط ۱ -->
        <h:outputText value="#{msg['combo1.prompt']}"/>
        <h:selectOneMenu id="combo1" value="#{form.combo1}" immediate="true" onchange="submit();" valueChangeListener="#{form.combo1ChangeListener}" styleClass="combo">
          <f:selectItems value="#{form.combo1Items}"/>
        </h:selectOneMenu>
        <h:panelGroup></h:panelGroup>
<h:outputText value="#{form.combo1}"/>

با PrimeFaces:

<h:outputText value="#{msg['combo1.prompt']}"/>
        <p:selectOneMenu id="combo1" value="#{form.combo1}" styleClass="combo">
          <f:selectItems value="#{form.combo1Items}"/>
          <p:ajax update=":formulaire:combo2"/>  
        </p:selectOneMenu>
        <h:panelGroup></h:panelGroup>
        <h:outputText value="#{form.combo1}"/>

        <h:outputText value="#{msg['combo2.prompt']}"/>
        <p:selectOneMenu id="combo2" value="#{form.combo2}" styleClass="combo">
          <f:selectItems value="#{form.combo2Items}"/>
        </p:selectOneMenu>
  • خط ۲: تگ <h:selectOneMenu> بدون ویژگی valueChangeListener،
  • خط ۴: تگ <p:ajax> یک رفتار AJAX را به تگ والد خود <h:selectOneMenu> اضافه می‌کند. به طور پیش‌فرض، این تگ به رویداد «تغییر مقدار» لیست combo1 واکنش نشان می‌دهد. در پاسخ به این رویداد، مقادیر مربوط به فرم مربوطه از طریق یک فراخوانی AJAX به سرور ارسال می‌شوند. بنابراین مدل به‌روزرسانی می‌شود. سپس از این مدل جدید برای به‌روزرسانی لیست کشویی با شناسه combo2 (خط ۱۰) استفاده می‌شود. توجه کنید که در خط ۴، فراخوانی AJAX هیچ متدی از مدل را اجرا نمی‌کند. این کار در اینجا غیرضروری است. ما صرفاً می‌خواهیم مدل را با استفاده از POST با مقادیر وارد شده به‌روزرسانی کنیم.

5.12. مثال: mv-pf-09: ورود داده با کمک

این پروژه دارای تگ‌های ورودی مخصوص PrimeFaces است که ورود انواع خاصی از داده‌ها را تسهیل می‌کند:

5.12.1. پروژه NetBeans

پروژه NetBeans به شرح زیر است:

ارزش این پروژه در موارد زیر نهفته است:

  • صفحهٔ واحد [index.html] نمایش‌داده‌شده توسط پروژه،
  • قالب [Form.java] برای آن صفحه.

5.12.2. قالب

این فرم شامل چهار فیلد ورودی مرتبط با قالب زیر است:


package forms;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean
@SessionScoped
public class Form implements Serializable {

  private Date calendrier;
  private Integer slider = 100;
  private Integer spinner = 1;
  private String autocompleteValue;

  public Form() {
  }

  public List<String> autocomplete(String query) {
    ...
  }
   // گیرنده‌ها و تنظیم‌کننده‌ها
...
}

این چهار ورودی با فیلدهای خطوط 14–17 مطابقت دارند.

5.12.3. فرم

فرم به شرح زیر است:


<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <h2><h:outputText value="#{msg['app.titre']}"/></h2>
      <p:growl id="messages" autoUpdate="true"/>
      <p:panelGrid columns="3" columnClasses="col1,col2,col3,col4">
        <h:outputText value="#{msg['saisie.type']}" styleClass="entete"/>
        <h:outputText value="#{msg['saisie.champ']}" styleClass="entete"/>
        <h:outputText value="#{msg['bean.valeur']}" styleClass="entete"/>

        <!-- تقویم -->
              ...

        <!-- اسلایدر -->
              ...

        <!-- اسپینر -->
              ...

        <!-- تکمیل خودکار -->
              ...

      </p:panelGrid>
    </ui:define>
  </ui:composition>
</html>

بیایید به چهار فیلد ورودی نگاه کنیم.

5.12.4. تقویم

برچسب <p:calendar> به شما امکان می‌دهد از میان تاریخ‌های یک تقویم، تاریخی را انتخاب کنید. این برچسب از ویژگی‌های مختلفی پشتیبانی می‌کند.


<h:outputText value="#{msg['calendar.prompt']}"/>
        <p:calendar id="calendrier" value="#{form.calendrier}" pattern="dd/MM/yyyy" timeZone="Europe/Paris"/>
        <h:outputText id="calendrierValue" value="#{form.calendrier}">
          <f:convertDateTime pattern="dd/MM/yyyy" type="date" timeZone="Europe/Paris"/>
        </h:outputText>

در خط ۲، مشخص می‌کنیم که تاریخ باید به فرمت «dd/mm/yyyy» نمایش داده شود و منطقه زمانی پاریس است. وقتی نشانگر را در فیلد ورودی قرار می‌دهید، یک تقویم نمایش داده می‌شود:

 

5.12.5. اسلایدر

برچسب <p:slider> به شما امکان می‌دهد با کشیدن یک اسلایدر در امتداد یک نوار، یک عدد صحیح وارد کنید:

 

کد تگ به شرح زیر است:


        <h:outputText value="#{msg['slider.prompt']}"/>
        <h:panelGrid columns="1" style="margin-bottom:10px">  
          <p:inputText id="slider" value="#{form.slider}" required="true" requiredMessage="#{msg['slider.required']}" validatorMessage="#{msg['slider.invalide']}">  
            <f:validateLongRange minimum="100" maximum="200"/>
          </p:inputText>
          <p:slider for="slider" minValue="100" maxValue="200"/>  
        </h:panelGrid>  
<h:outputText id="sliderValue" value="#{form.slider}"/>
  • خط ۳: این یک تگ استاندارد <p:inputText> است که برای وارد کردن یک عدد صحیح استفاده می‌شود. این مقدار را می‌توان با استفاده از اسلایدر نیز وارد کرد،
  • خط ۴: تگ <p:slider> به تگ ورودی <p:inputText> (برای ویژگی) متصل است. یک حداقل و حداکثر مقدار برای آن تعیین شده است.

5.12.6. اسپینر

ما قبلاً فرصت ارائه این کامپوننت را داشته‌ایم:


        <h:outputText value="#{msg['spinner.prompt']}"/>
        <p:spinner id="spinner" min="1" max="12" value="#{form.spinner}" required="true" requiredMessage="#{msg['spinner.required']}" validatorMessage="#{msg['spinner.invalide']}">
          <f:validateLongRange minimum="1" maximum="12"/>
        </p:spinner>
<h:outputText id="spinnerValue" value="#{form.spinner}"/>

خط ۳: اسپینر اجازه می‌دهد یک عدد صحیح بین ۱ و ۱۲ وارد شود. می‌توانید عدد را مستقیماً در کادر ورودی اسپینر وارد کنید یا از فلش‌ها برای افزایش یا کاهش عدد واردشده استفاده کنید.

 

5.12.7. تکمیل خودکار

تکمیل خودکار شامل تایپ چند حرف اول عبارت جستجو است. سپس پیشنهادها در یک فهرست کشویی ظاهر می‌شوند. می‌توانید یکی از این پیشنهادها را انتخاب کنید. این مؤلفه به جای لیست‌های کشویی زمانی استفاده می‌شود که لیست‌های کشویی حاوی محتوای زیادی باشند. فرض کنید می‌خواهید یک لیست کشویی از شهرهای فرانسه ارائه دهید. چندین هزار شهر وجود دارد. اگر به کاربر اجازه دهید سه حرف اول نام شهر را تایپ کند، سپس می‌توانید لیستی کوتاه‌تر از شهرهایی را که با آن حروف شروع می‌شوند به او ارائه دهید.

 

کد این کامپوننت به شرح زیر است:


        <h:outputText value="#{msg['autocomplete.prompt']}"/>
        <p:autoComplete value="#{form.autocompleteValue}" completeMethod="#{form.autocomplete}" required="true" requiredMessage="#{msg['autocomplete.required']}"/>
        <h:outputText id="autocompleteValue" value="#{form.autocompleteValue}"/>
        <h:panelGroup/>
        <h:panelGroup>
        <center><p:commandLink value="#{msg['valider']}" update="formulaire:contenu"/></center>
        </h:panelGroup>
<h:panelGroup/>

تگ <p:autoComplete> در خط ۲ همان چیزی است که قابلیت تکمیل خودکار را فعال می‌کند. پارامتر مورد توجه در اینجا ویژگی completeMethod است که مقدار آن نام متدی در مدل است که مسئول تولید پیشنهادها بر اساس حروف تایپ‌شده توسط کاربر است. این متد به شرح زیر است:


  public List<String> autocomplete(String query) {
    List<String> results = new ArrayList<String>();

    for (int i = 0; i < 10; i++) {
      results.add(query + i);
    }

    return results;
}

  • خط ۱: این متد به عنوان پارامتر، رشته حروفی را که کاربر در فیلد ورودی تایپ کرده است دریافت می‌کند. این متد یک لیست از پیشنهادها را بازمی‌گرداند،
  • خطوط ۴–۶: یک لیست ۱۰ تایی از پیشنهادها ساخته می‌شود که شامل حروف دریافت‌شده به‌عنوان پارامتر است و به هر کدام یک رقم از ۰ تا ۹ اضافه می‌کند.

5.12.8. تگ <p:growl>

تگ <p:growl> یک جایگزین احتمالی برای تگ <p:messages> است که پیام‌های خطای فرم را نمایش می‌دهد.


      <p:growl id="messages" autoUpdate="true"/>

در مثال بالا، از ویژگی id استفاده نشده است. ویژگی autoUpdate=true نشان می‌دهد که فهرست پیام‌های خطا باید هر بار که فرم ارسال می‌شود، تازه‌سازی شود.

فرض کنید فرم زیر ارسال می‌شود: [1]:

  • پس از ارسال ([2])، تگ <p:growl> پیام‌های خطای مربوط به ورودی‌های نادرست را نمایش می‌دهد.

5.13. مثال: mv-pf-10: dataTable - 1

این پروژه تگ <p:dataTable> را معرفی می‌کند که برای نمایش لیست‌های داده استفاده می‌شود

Image

5.13.1. پروژه NetBeans

پروژه NetBeans به شرح زیر است:

ارزش پروژه در این است:

  • صفحهٔ واحد [index.html] نمایش‌داده‌شده توسط پروژه،
  • قالب [Form.java] برای آن صفحه، و بین [Personne].

5.13.2. فایل پیام

فایل [messages_fr.properties] به شرح زیر است:


app.titre=intro-08
app.titre2=DataTable - 1
submit=Valider
personnes.headers.id=Id
personnes.headers.nom=Nom
personnes.headers.prenom=Pr\u00e9nom
layout.hautdepage=Primefaces en fran\u00e7ais
layout.menu=Menu fran\u00e7ais
layout.basdepage=ISTIA, universit\u00e9 d'Angers
form.langue1=Fran\u00e7ais
form.langue2=Anglais
form.noData=La liste des personnes est vide
form.listePersonnes=Liste de personnes
form.action=Action

5.13.3. مدل

بیان [Personne] نمایانگر یک شخص است:


package forms;

import java.io.Serializable;

public class Personne implements Serializable{
  // داده‌ها
  private int id;
  private String nom;
  private String prénom;
  
  // تولیدکنندگان
  public Personne(){
    
  }
  
  public Personne(int id, String nom, String prénom){
    this.id=id;
    this.nom=nom;
    this.prénom=prénom;
  }
  
  // toString
  public String toString(){
    return String.format("Personne[%d,%s,%s]", id,nom,prénom);
  }
  
  // گیرنده و تنظیم‌کننده
...
}

قالب صفحه [index.xhtml] کلاس زیر است: [Form]:


package forms;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class Form implements Serializable{

  // مدل
  private List<Personne> personnes;
  private int personneId;

  // سازنده
  public Form() {
    // ابتدایی‌سازی فهرست افراد
    personnes = new ArrayList<Personne>();
    personnes.add(new Personne(1, "dupont", "jacques"));
    personnes.add(new Personne(2, "durand", "élise"));
    personnes.add(new Personne(3, "martin", "jacqueline"));
  }

  public void retirerPersonne() {
...
  }
  
  // گیرنده‌ها و تنظیم‌کننده‌ها
...  
}
  • خطوط ۹–۱۰: بیِن در محدودهٔ جلسه (session-scoped) قرار دارد،
  • خطوط ۱۸–۲۴: سازنده یک لیست از سه نفر ایجاد می‌کند که در نتیجه در طول درخواست‌ها پایدار باقی می‌ماند،
  • خط ۱۵: شماره فردی که باید از لیست حذف شود،
  • خطوط 26–28: متد حذف.

5.13.4. فرم

فرم به شرح زیر است: [index.xhtml]:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <h2><h:outputText value="#{msg['app.titre2']}"/></h2>
      <p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}">
        <f:facet name="header">  
           #{msg['form.listePersonnes']}  
        </f:facet>  
        <p:column>
          <f:facet name="header">
             #{msg['personnes.headers.id']}
          </f:facet>
           #{personne.id}
        </p:column>
        <p:column>
          <f:facet name="header">
             #{msg['personnes.headers.nom']}
          </f:facet>
           #{personne.nom}
        </p:column>
        <p:column>
          <f:facet name="header">
             #{msg['personnes.headers.prenom']}
          </f:facet>
           #{personne.prénom}
        </p:column>
        <p:column>
          <f:facet name="header">
             #{msg['form.action']}
          </f:facet>
          <p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu">
            <f:setPropertyActionListener target="#{form.personneId}" value="#{personne.id}"/>
          </p:commandLink>
        </p:column>
      </p:dataTable>
    </ui:define>
  </ui:composition>
</html>

این کار نمای زیر را تولید می‌کند (جعبهٔ زیر):

  • خط ۱۲: جدولی را که در کادر بالا نشان داده شده تولید می‌کند. ویژگی 'value' مجموعه‌ای را که در جدول نمایش داده می‌شود مشخص می‌کند، در این مورد فهرست افراد در مدل. ویژگی 'emptyMessage' اختیاری است. این ویژگی پیامی را که هنگام خالی بودن فهرست نمایش داده می‌شود مشخص می‌کند. به‌طور پیش‌فرض، این پیام 'هیچ رکوردی یافت نشد' است. در اینجا، این خواهد بود:
 
  • خطوط ۱۳–۱۵: ایجاد سربرگ [1]،
  • خطوط ۱۶–۲۱: ایجاد ستون [2]،
  • خطوط ۲۲–۲۷: ایجاد ستون [3]،
  • خطوط ۲۸–۳۳: ایجاد ستون [4]،
  • خطوط ۳۴–۴۱: ستون [5] را تولید کنید.

لینک [Retirer] امکان حذف یک شخص از لیست را فراهم می‌کند. خط [38]: این روش [Form].retirerPersonne است که این کار را انجام می‌دهد. این نیازمند شماره فردی است که باید حذف شود. این شماره در خط ۳۹ ارائه شده است. در خط ۳۸ از ویژگی «action» استفاده شده است. در موارد دیگر از ویژگی «actionListener» استفاده شده است. من مطمئن نیستم که تفاوت عملکردی این دو ویژگی را به‌طور کامل درک کرده باشم. با این حال، در عمل متوجه می‌شویم که ویژگی‌های تعیین‌شده توسط تگ‌های <setPropertyActionListener> قبل از اجرای متدی که توسط ویژگی «action» مشخص شده است، تنظیم می‌شوند، در حالی که این امر برای ویژگی actionListener صدق نمی‌کند. به‌طور ساده، به محض اینکه پارامترهایی برای ارسال به اکشن فراخوانی‌شده داشته باشید، باید از ویژگی action استفاده کنید.

روش حذف یک شخص به شرح زیر است:


...
@ManagedBean
@SessionScoped
public class Form implements Serializable{

  //قالب
  private List<Personne> personnes;
  private int personneId;

  public void retirerPersonne() {
    //در حال جستجو برای شخص انتخاب‌شده
    int i = 0;
    for (Personne personne : personnes) {
      // فرد فعلی = فرد انتخاب‌شده؟
      if (personne.getId() == personneId) {
        // حذف شخص فعلی از لیست
        personnes.remove(i);
        //انجام شد
        break;
      } else {
        // فرد بعدی
        i++;
      }
    }
  }
...  
}

5.14. مثال: mv-pf-11: dataTable - 2

این پروژه شامل جدولی است که فهرستی از داده‌ها را نمایش می‌دهد و می‌توان یک سطر را از آن انتخاب کرد:

انتخاب یک سطر از جدول، اطلاعات مربوط به سطر انتخاب‌شده را در زمان POST به مدل ارسال می‌کند. در نتیجه، دیگر نیازی به لینک [Retirer] برای هر شخص وجود ندارد. یک لینک واحد برای کل جدول کافی است.

پروژه NetBeans به جز چند جزئیات، دقیقاً مشابه پروژه قبلی است: فرم و قالب آن. فرم [index.xhtml] به شرح زیر است:


<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <h2><h:outputText value="#{msg['app.titre2']}"/></h2>
      <p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
                   rowKey="#{personne.id}"  selection="#{form.personneChoisie}" selectionMode="single">
        ...
      </p:dataTable>
      <p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu"/>
    </ui:define>
  </ui:composition>
</html>
  • خط ۱۳: ویژگی selectionMode به شما امکان می‌دهد یک حالت انتخاب (single یا multiple) را انتخاب کنید. در اینجا، ما انتخاب کرده‌ایم که فقط یک ردیف را انتخاب کنیم،
  • خط ۱۳: ویژگی rowkey یک ویژگی از عناصر نمایش داده شده را مشخص می‌کند که امکان انتخاب منحصربه‌فرد آن‌ها را فراهم می‌آورد. در اینجا، ما شناسه (ID) شخص انتخاب‌شده را انتخاب کرده‌ایم،
  • خط ۱۳: ویژگی `selection` به ویژگی‌ای در مدل اشاره دارد که مرجعی به شخص انتخاب‌شده را دریافت خواهد کرد. به لطف ویژگی `rowkey` که قبلاً آمده است، مرجعی به شخص انتخاب‌شده را می‌توان در سمت سرور محاسبه کرد. ما جزئیات روش مورد استفاده را نداریم. می‌توانیم تصور کنیم که مجموعه به صورت متوالی برای یافتن عنصر متناظر با rowkey انتخاب‌شده جستجو می‌شود. این بدان معناست که اگر روشی که rowkey را با انتخاب مرتبط می‌کند پیچیده‌تر باشد، از این روش نمی‌توان استفاده کرد،

با توضیحات فوق، متد [Form].retirerPersonne به شرح زیر به‌روزرسانی می‌شود:


...

@ManagedBean
@SessionScoped
public class Form implements Serializable {

  // قالب
  private List<Personne> personnes;
  private Personne personneChoisie;

  // تولیدکننده
  public Form() {
  ...
  }

  public void retirerPersonne() {
    // حذف شخص انتخاب‌شده
    personnes.remove(personneChoisie);
  }

  // گیرنده و تنظیم‌کننده
...
}
  • خط ۹: برای هر POST، مرجع در خط ۹ با مرجع شخص انتخاب‌شده در لیست خط ۸، مقداردهی اولیه می‌شود،
  • در خط ۱۸: این کار حذف شخص را ساده‌تر می‌کند. جستجویی که در مثال قبلی انجام دادیم با استفاده از تگ <dataTable> انجام شد.

5.15. مثال: mv-pf-12: dataTable - 3

این پروژه مشابه پروژه قبلی است. به طور خاص، نما یکسان است:

Image

پروژه NetBeans دقیقاً مشابه پروژه قبلی است، به جز چند جزئیات جزئی که به آن‌ها خواهیم پرداخت. فرم [index.xhtml] به شرح زیر تغییر می‌کند:


...
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <h2><h:outputText value="#{msg['app.titre2']}"/></h2>
      <p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
                   selectionMode="single" selection="#{form.personneChoisie}">
  ...
      </p:dataTable>
      <p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu"/>
    </ui:define>
  </ui:composition>
</html>
  • در خط ۶، ویژگی `rowkey` حذف شده است، در حالی که ویژگی `selection` باقی مانده است. ارتباط بین ویژگی‌های `rowkey` و `selection` اکنون از طریق یک کلاس برقرار می‌شود. ویژگی value در خط ۵ اکنون یک نمونه از رابط PrimeFaces SelectableDataModel<T> را در خود جای داده است. متد [Form].getPersonnes در مدل به شرح زیر به‌روزرسانی شده است:

  public DataTableModel getPersonnes() {
    return new DataTableModel(personnes);
}

بنابراین یک بیون جدید به پروژه اضافه می‌شود:

این بین به شرح زیر است:


package forms;

import java.util.List;
import javax.faces.model.ListDataModel;
import org.primefaces.model.SelectableDataModel;

public class DataTableModel extends ListDataModel<Personne> implements SelectableDataModel<Personne> {

  // سازنده‌ها
  public DataTableModel() {
  }

  public DataTableModel(List<Personne> personnes) {
    super(personnes);
  }

  @Override
  public Object getRowKey(Personne personne) {
    return personne.getId();
  }

  @Override
  public Personne getRowData(String rowKey) {
    // فهرست افراد
    List<Personne> personnes = (List<Personne>) getWrappedData();
    // کلید یک عدد صحیح است 
    int key = Integer.parseInt(rowKey);
    // جستجو برای شخص انتخاب‌شده
    for (Personne personne : personnes) {
      if (personne.getId() == key) {
        return personne;
      }
    }
    // هیچ چیزی یافت نشد
    return null;
  }
}
  • خط ۷: این کلاس یک نمونه از رابط SelectableDataModel است. حداقل دو کلاس این رابط را پیاده‌سازی می‌کنند: ListDataModel که سازنده‌اش یک لیست را به عنوان پارامتر می‌پذیرد، و ArrayDataModel که سازنده‌اش یک آرایه را به عنوان پارامتر می‌پذیرد. در اینجا، بین ما کلاس ListDataModel را ارث می‌برد،
  • خطوط ۱۳–۱۵: سازنده، لیست افرادی را که ما مدیریت می‌کنیم به‌عنوان پارامتر می‌پذیرد. این پارامتر به کلاس والد پاس می‌شود،
  • خط ۱۸: متد getRowKey جایگزین ویژگی rowkey شده است که حذف شده است. این متد باید شیئی را بازگرداند که یک شخص را به طور منحصربه‌فرد شناسایی می‌کند، در این مورد شناسه شخص.
  • خط ۲۳: متد getRowData باید شیء انتخاب‌شده را بر اساس rowkey آن بازگرداند. بنابراین، در این مورد، یک شخص را بر اساس شناسه (ID) او بازمی‌گرداند. مرجع به‌دست‌آمده بدین ترتیب به شیء هدفِ ویژگی «selection» در تگ dataTable اختصاص داده می‌شود، که در این مورد ویژگی «selection="#{form.personneChoisie}"» است. پارامتر متد، کلید ردیف (rowkey) شیء انتخاب‌شده توسط کاربر، به شکل یک رشته کاراکتری، است،
  • سطور ۲۴–۳۵: مرجع فردی را که شناسهٔ او دریافت شده است بازمی‌گرداند. این مرجع به مدل [Form].personneChoisie اختصاص داده می‌شود. بنابراین متد [retirerPersonne] بدون تغییر باقی می‌ماند:

  public void retirerPersonne() {
    // حذف شخص منتخب
    personnes.remove(personneChoisie);
  }

این تکنیک زمانی به کار می‌رود که ارتباط بین ویژگی‌های rowkey و selection یک ارتباط ساده از نوع ویژگی (rowkey) به شیء (selection) نباشد.

5.16. مثال: mv-pf-13: dataTable - 4

این پروژه مشابه پروژه قبلی است، با این تفاوت که روش انتخاب فردی که باید حذف شود تغییر می‌کند:

Image

در بالا می‌بینیم که شیء از طریق منوی زمینه (کلیک راست) انتخاب می‌شود. تأیید حذف درخواست می‌شود:

 

فرم [index.xhtml] به شرح زیر تغییر می‌کند:


...
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">

      <!-- عنوان -->
      <h2><h:outputText value="#{msg['app.titre2']}"/></h2>

      <!-- منوی زمینه -->
      <p:contextMenu for="personnes">  
        <p:menuitem value="#{msg['form.supprimer']}" onclick="confirmation.show()"/>
      </p:contextMenu>  

      <!-- جعبه‌ی گفتگو -->
      <p:confirmDialog widgetVar="confirmation" message="#{msg['form.suppression.confirmation']}"  
                       header="#{msg['form.suppression.message']}" severity="alert" >                   
        <p:commandButton value="#{msg['form.supprimer.oui']}" update=":formulaire:contenu"                          action="#{form.retirerPersonne}" oncomplete="confirmation.hide()"/>
        <p:commandButton value="#{msg['form.supprimer.non']}" onclick="confirmation.hide()" type="button" />                
      </p:confirmDialog>  

      <!-- dataTable-->
      <p:dataTable id="personnes" value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
                   selection="#{form.personneChoisie}" selectionMode="single">
        ...
      </p:dataTable>
    </ui:define>
  </ui:composition>
</html>
  • خطوط ۹–۱۱: یک منوی زمینه برای (برای ویژگی) dataTable در خط ۲۱ (ویژگی id) تعریف می‌کند. بنابراین این منوی زمینه زمانی ظاهر می‌شود که روی جدول افراد کلیک راست می‌کنید،
  • خط ۱۰: منوی ما تنها یک گزینه دارد (برچسب menuItem). هنگامی که این گزینه کلیک می‌شود، کد جاوااسکریپت در ویژگی onclick اجرا می‌شود. کد جاوااسکریپت [confirmation.show()] کادر محاوره‌ای را در خط 14 (ویژگی widgetVar) نمایش می‌دهد. این کد به شرح زیر است:
  • خط ۱۴: ویژگی «message» مقدار [3] را نمایش می‌دهد، ویژگی «header» مقدار [1] را نمایش می‌دهد، ویژگی «severity» آیکون [2] را نمایش می‌دهد،
  • خط ۱۶: [4] را نمایش می‌دهد. با کلیک، شخص حذف می‌شود (ویژگی action)، سپس کادر محاوره‌ای بسته می‌شود (ویژگی oncomplete). ویژگی oncomplete کدی در جاوااسکریپت است که پس از انجام عمل سمت سرور، اجرا می‌شود،
  • خط ۱۷: نمایش [5]. با کلیک، کادر گفتگو بسته می‌شود و شخص حذف نمی‌شود.

5.17. مثال: mv-pf-14: dataTable - 5

این پروژه نشان می‌دهد که پس از اجرای فراخوانی AJAX می‌توان پاسخی از سرور دریافت کرد. برای این کار، از ویژگی oncomplete فراخوانی AJAX استفاده می‌کنیم:

 

فرم [index.xhtml] به شرح زیر به‌روزرسانی می‌شود:


...
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
...
<!-- جعبه‌ی گفتگو ۱ -->
      <p:confirmDialog widgetVar="confirmation" ... >                   
        <p:commandButton value="#{msg['form.supprimer.oui']}" update=":formulaire:contenu" action="#{form.retirerPersonne}" oncomplete="handleRequest(xhr, status, args);confirmation.hide()"/>
        <p:commandButton ... />                
      </p:confirmDialog>  

      <!--جاوا اسکریپت -->
      <script type="text/javascript">  
        function handleRequest(xhr, status, args) {  
          // خطا؟
          if(args.msgErreur) {  
            alert(args.msgErreur);  
          }  
        }  
      </script> 
...
      </p:dataTable>
    </ui:define>
  </ui:composition>
</html>
  • خط ۷: ویژگی oncomplete تابع جاوااسکریپت را در خطوط ۱۳–۱۸ فراخوانی می‌کند،
  • خط ۱۳: امضای متد باید به شکل زیر باشد. `args` یک دیکشنری است که مدل سمت سرور می‌تواند آن را پر کند،
  • خط ۱۵: اسکریپت بررسی می‌کند که آیا دیکشنری `args` دارای ویژگی‌ای با نام 'msgErreur' است. در صورت وجود، آن نمایش داده می‌شود (خط ۱۶).

در مدل، متد [retirerPersonne] به صورت زیر تعریف شده است:


public void retirerPersonne() {
    // حذف تصادفی
    int i = (int) (Math.random() * 2);
    if (i == 0) {
      // فرد انتخاب‌شده حذف می‌شود
      personnes.remove(personneChoisie);
    } else {
      //یک خطا بازگردانده می‌شود
      String msgErreur = Messages.getMessage(null, "form.msgErreur", null).getSummary();
      RequestContext.getCurrentInstance().addCallbackParam("msgErreur", msgErreur);
    }
  }
  • خط ۳: یک عدد تصادفی ۰ یا ۱ تولید می‌شود،
  • خطوط ۴–۶: اگر مقدار آن ۰ باشد، شخص انتخاب‌شده توسط کاربر از فهرست افراد حذف می‌شود،
  • خط ۹: در غیر این صورت، یک پیام خطای بین‌المللی‌سازی‌شده تولید می‌شود:

form.msgErreur=La personne n'a pu \u00eatre supprim\u00e9e. Veuillez r\u00e9essayer ult\u00e9rieurement.
form.msgErreur_detail=La personne n'a pu \u00eatre supprim\u00e9e. Veuillez r\u00e9essayer ult\u00e9rieurement.
  • خط ۱۰: یک دستور پیچیده که برای افزودن ویژگی‌ای به نام «msgErreur» با مقدار «msgErreur» که در خط ۹ ساخته شده است، به فرهنگ لغت «args» که قبلاً ذکر شد، طراحی شده است. سپس این ویژگی توسط متد جاوااسکریپت [index.xhtml] بازیابی می‌شود:

      <!--جاوا اسکریپت -->
      <script type="text/javascript">  
        function handleRequest(xhr, status, args) {  
          // خطا؟
          if(args.msgErreur) {  
            alert(args.msgErreur);  
          }  
        }  
</script> 

5.18. مثال: mv-pf-15: نوار ابزار

در این پروژه، ما در حال ساخت یک نوار ابزار هستیم:

ابزارکِش، کامپوننتی است که در بالا برجسته شده است. این ابزارک با استفاده از کد زیرِ XHTML تولید می‌شود، که خود پیروی از [index.xhtml] می‌کند:



<?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.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
  <ui:composition template="layout.xhtml">
    <ui:define name="contenu">
      <!-- عنوان -->
      <h2><h:outputText value="#{msg['app.titre2']}"/></h2>

      <!--نوار ابزار-->
      <p:toolbar>
        <p:toolbarGroup align="left">  
          ...  
        </p:toolbarGroup>
        <p:toolbarGroup align="right">  
          ...  
        </p:toolbarGroup>  
      </p:toolbar>
    </ui:define>
  </ui:composition>
</html>
  • خطوط ۱۵–۲۲: نوار ابزار،
  • خطوط ۱۶–۱۸: گروه مؤلفه‌ها را در سمت چپ نوار ابزار تعریف می‌کنند،
  • خطوط ۱۹–۲۱: همین امر در مورد اجزای سمت راست نیز صدق می‌کند.

اجزاء در سمت چپ نوار ابزار به شرح زیر هستند:


        <p:toolbarGroup align="left">  
          <h:outputText value="#{msg['form.etudiant']}"/>
          <p:spacer width="50px"/>
          <p:selectOneMenu value="#{form.personneId}" effect="fade">  
            <f:selectItems value="#{form.personnes}" var="personne" itemLabel="#{personne.prénom} #{personne.nom}" itemValue="#{personne.id}"/>  
          </p:selectOneMenu>              
          <p:separator/>
          <p:commandButton id="delete-personne" icon="ui-icon-trash" action="#{form.supprimerPersonne}" update=":formulaire:contenu"/>  
          <p:tooltip for="delete-personne" value="#{msg['form.delete.personne']}"/>  
</p:toolbarGroup>

آنها نمای زیر را نمایش می‌دهند:

  • خط ۲: نمایش می‌دهد [1],
  • خط ۳: یک فاصله ۳۰ پیکسلی [2] را نمایش می‌دهد،
  • خطوط ۴–۶: یک لیست کشویی با فهرستی از افراد را نمایش می‌دهند [3],
  • خط ۷: یک جداکننده [4] را نمایش می‌دهد،
  • خط ۸: یک دکمه [5] نمایش می‌دهد که فرد انتخاب‌شده را از فهرست کشویی حذف می‌کند. این دکمه دارای یک آیکون است. این آیکون‌ها مربوط به JQuery و UI هستند. فهرستی از این موارد را می‌توان در URL، [http://jqueryui.com/themeroller/] و [6] یافت:
  • برای یافتن نام یک آیکون، کافی است ماوس را روی آن ببرید. این نام سپس در ویژگی `icon` از کامپوننت <commandButton> استفاده می‌شود، برای مثال `icon="ui-icon-trash"`. توجه داشته باشید که در مثال بالا، نام داده‌شده .ui-icon-trash است و نقطهٔ ابتدایی از این نام در ویژگی icon, حذف می‌شود.
  • خط ۹: یک ابزارک (tooltip) برای دکمه ایجاد می‌کند (برای ویژگی `icon`). هنگامی که مکان‌نما روی دکمه قرار می‌گیرد، پیام ابزارک نمایش داده می‌شود: [7].

قالب مرتبط با این اجزا به شرح زیر است:


package forms;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class Form implements Serializable {

  // قالب
  private List<Personne> personnes;
  private int personneId;

  // سازنده
  public Form() {
    // ابتکارسازی فهرست افراد
    personnes = new ArrayList<Personne>();
    personnes.add(new Personne(1, "dupont", "jacques"));
    personnes.add(new Personne(2, "durand", "élise"));
    personnes.add(new Personne(3, "martin", "jacqueline"));
  }

  public void supprimerPersonne() {
    // جستجوی شخص انتخاب‌شده
    int i = 0;
    for (Personne personne : personnes) {
      // فرد فعلی = فرد انتخاب‌شده؟
      if (personne.getId() == personneId) {
        // حذف شخص فعلی از فهرست
        personnes.remove(i);
        // فرآیند کامل شد
        break;
      } else {
        // فرد بعدی
        i++;
      }
    }
  }

  // گیرنده‌ها و تنظیم‌کننده‌ها
  ...
}

اجزاء در سمت راست نوار ابزار به شرح زیر هستند:


<p:toolbar>
        <p:toolbarGroup align="left">  
          ... 
        </p:toolbarGroup>
        <p:toolbarGroup align="right">  
          <p:menuButton value="#{msg['form.options']}">  
            <p:menuitem id="menuitem-francais" value="#{msg['form.francais']}" actionListener="#{changeLocale.setFrenchLocale}" update=":formulaire"/>  
            <p:menuitem id="menuitem-anglais" value="#{msg['form.anglais']}" actionListener="#{changeLocale.setEnglishLocale}" update=":formulaire"/>  
          </p:menuButton>  
        </p:toolbarGroup>  
      </p:toolbar>

آنها نمای نشان داده شده در زیر را نمایش می‌دهند:

 
  • خطوط ۶–۹: یک دکمه منو. این دکمه شامل گزینه‌های منو است،
  • خط ۷: گزینه تغییر فرم به زبان فرانسوی،
  • خط ۸: گزینهٔ تغییر آن به انگلیسی.

5.19. Conclusion

اکنون به اندازه کافی می‌دانیم که مثال برنامه‌نویسی خود را به PrimeFaces منتقل کنیم. ما تنها به حدود پانزده کامپوننت نگاهی انداخته‌ایم، در حالی که این کتابخانه بیش از ۱۰۰ کامپوننت دارد. از خوانندگان دعوت می‌شود تا هر کامپوننتی را که نیاز دارند مستقیماً در وب‌سایت PrimeFaces جستجو کنند.

5.20. آزمایش با اکلیپس

پروژه‌های Maven در وب‌سایت نمونه‌های [1] در دسترس هستند:

پس از وارد کردن به Eclipse، می‌توان آن‌ها را اجرا کرد [2]. در [3]، Tomcat را انتخاب کنید. سپس آن‌ها در مرورگر داخلی Eclipse [3] نمایش داده می‌شوند.