1 / 33

JSF dataTables Advanced use of Properties and Development Techniques

? Substituting Controls in a dataTable. ? You may wish to substitute comboBoxes and radioButtons (selection controls) in a dataTable for input or output controls. Here's an example of such a page

betty_james
Télécharger la présentation

JSF dataTables Advanced use of Properties and Development Techniques

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


    1. JSF dataTables Advanced use of Properties and Development Techniques Part III of a 3-part section on the use of the rich and complex U.I. structures that are dataTables. This section includes control substitution, graphics in dataTables, JavaScript column sort, cell color, inline frames and input row selection.

    2. ? Substituting Controls in a dataTable ? You may wish to substitute comboBoxes and radioButtons (selection controls) in a dataTable for input or output controls. Heres an example of such a page To do this, you will need to: Delete the existing inputText controls from the dataTable Substitute (drag and drop) new JSF components Bind the components to EGL data In your JSFHandler, you will need to access any database information needed to populate the new controls We will do an example with both static and dynamic-content control substitution.

    3. Substituting Controls in a dataTable Steps 1 of 3 the JSFHandler We will use a page named: allsiteusers.jsp. You may have created this (it was optional) for a previous exercise. If so, please replace the JSFHandler code with the code in the Notes section of this slide. Note the following: Database and U.I. record array In order to take advantage of U.I. controls that require datatypes NOT on the database An array of states from the database Everything else should be familiar package jsfhandlers; import com.ibm.egl.jsf.*; import egl.ui.selectionlist; import eglderbyr7.data.Siteuser; import eglderbyr7.data.Statetable; import eglderbyr7.primitivetypes.data.SiteuserFirstname; import eglderbyr7.primitivetypes.data.SiteuserId; import eglderbyr7.primitivetypes.data.SiteuserLastname; import eglderbyr7.primitivetypes.data.SiteuserState; handler allsiteusers type JSFHandler {onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allsiteusers.jsp"} viewRoot UIViewRoot; siteuserDB Siteuser[0]; //Database records array siteusersUI SiteuserSub[0]; //U.I. records array UIRec siteuserSub; //Single record, for appending into array //States array from database. Note no selectedValueItem - this will be done in Page Designer statesCB Statetable[0] {@SelectionList {labelItem = StateName, valueItem = StateAbbrev}}; // Function Declarations function onConstruction() get siteuserDB; //Load SiteUser dynamic array from the database get statesCB; //Load the States dynamic array from the database loadUIRecords(); //Invoke local function end function onPrerender() end function loadUIRecords() //Routine to load U.I. records from DB for (i int from 1 to size(siteUserDB) by 1) move siteuserDB[i] to UIRec byName; move siteuserDB[i].Sutype as string to UIRec.SuTypeString; move siteuserDB[i].JoinClub to uirec.JoinClubB; move siteuserDB[i].receiveupdates to uirec.ReceiveUpdatesB; siteusersUI.appendElement(UIRec); end end end record SiteuserSub type basicrecord //new U.I. record SiteuserId SiteuserId?; Firstname SiteuserFirstname?; Lastname SiteuserLastname?; State SiteuserState?; SuTypeString string; ReceiveUpdatesB boolean; JoinClubB boolean; end package jsfhandlers; import com.ibm.egl.jsf.*; import egl.ui.selectionlist; import eglderbyr7.data.Siteuser; import eglderbyr7.data.Statetable; import eglderbyr7.primitivetypes.data.SiteuserFirstname; import eglderbyr7.primitivetypes.data.SiteuserId; import eglderbyr7.primitivetypes.data.SiteuserLastname; import eglderbyr7.primitivetypes.data.SiteuserState; handler allsiteusers type JSFHandler {onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allsiteusers.jsp"} viewRoot UIViewRoot; siteuserDB Siteuser[0]; //Database records array siteusersUI SiteuserSub[0]; //U.I. records array UIRec siteuserSub; //Single record, for appending into array //States array from database. Note no selectedValueItem - this will be done in Page Designer statesCB Statetable[0] {@SelectionList {labelItem = StateName, valueItem = StateAbbrev}}; // Function Declarations function onConstruction() get siteuserDB; //Load SiteUser dynamic array from the database get statesCB; //Load the States dynamic array from the database loadUIRecords(); //Invoke local function end function onPrerender() end function loadUIRecords() //Routine to load U.I. records from DB for (i int from 1 to size(siteUserDB) by 1) move siteuserDB[i] to UIRec byName; move siteuserDB[i].Sutype as string to UIRec.SuTypeString; move siteuserDB[i].JoinClub to uirec.JoinClubB; move siteuserDB[i].receiveupdates to uirec.ReceiveUpdatesB; siteusersUI.appendElement(UIRec); end end end record SiteuserSub type basicrecord //new U.I. record SiteuserId SiteuserId?; Firstname SiteuserFirstname?; Lastname SiteuserLastname?; State SiteuserState?; SuTypeString string; ReceiveUpdatesB boolean; JoinClubB boolean; end

    4. ? Substituting Controls in a dataTable Steps 2 of 3 Page Design Create a new allsiteusers.jsp page (or if you have an allsiteusers, delete your existing dataTable) Drag and drop: siteUsersUI SiteUserSub[] onto the page Show (display on the page) only the columns in the screen capture Delete the existing State field, and substitute a Combo Box Delete the existing su_type field, and substitute a Radio Button Group. For this control, add three selection entries. From Properties ? Drag and drop a Panel Group-box into the Receive Updates column (At the prompt select JSP style Panel Group box. This will allow you to add HTML and JSF components). Into this group box drag an HTML table (2 rows/1 column, 0 border) then into the table add the text and drag the checkboxes into the rows (as shown above)

    5. ? Substituting Controls in a dataTable Steps 3 of 3 Bind EGL Data (From Page Designer) - Using Properties, bind the following controls Value: to the following EGL variables ComboBox: Drag and drop: StatesCB StateTable[] on top of the control Specify the Value: #{varsiteUsersUI.State} RadioButton Group Specify the Value: #{varsiteUsersUI.SuTypeString} OPTIONAL (for the dataTable) Display alternate row colors: rowHighlight/rowClass3 Add a 1-pixel width border to the dataTable Run the page on the server

    6. JSF dataTable Row Actions Add a Selection Column ?The other Row Action, is to add a selection column to the table. This technique allows users to select multiple rows in a dataTable. These selected rows then are identified and made available for processing in your JSFHandler through a dynamic array bound to the dataTables checkbox (see screen capture). The user Submits the form one time and all selected rows can be processed together Lets see how to implement this common requirement with EGL and JSF.

    7. ? Add an action thats performed when a row is clicked 1 of 5 Create a new, .JSP web page, named: allordersupdate.jsp Copy/Paste the code in the Notes section of this slide and read the comments. Note the following: The sel int[0] array is a dynamic array that will (at run-time) contain the index values of the ordersArray for every row the user checks (checkbox control) The loop shows how to reference the selected ordersArray row by using the sel arrays occurrences - note the nested array brackets shorthand package jsfhandlers; import com.ibm.egl.jsf.*; import eglderbyr7.data.Orders; handler allordersupdate type JSFHandler {onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allordersupdate.jsp", viewRootVar = viewRoot} viewRoot UIViewRoot; ordersArray Orders[0]; //array of Orders (from the database) sel int[0]; //Array of selected rows (from the dataTable!) //Note this array will contain ordersArray row indexes //... one array element for each row selected. selectedOrders string; //display variable // Function Declarations function onConstruction() get ordersArray; //Go get the data end function onPrerender() end function showSelOrders() selectedOrders = "";//Clear the selectedOrders variable //Loop through the selected dataTable rows for (i int from 1 to size(sel) by 1) //assign the OrdersArray[selection_array[index]].orderId selectedOrders += "" + ordersArray[sel[i]].OrderId; if(i != size(sel)) selectedOrders += ","; end end end endpackage jsfhandlers; import com.ibm.egl.jsf.*; import eglderbyr7.data.Orders; handler allordersupdate type JSFHandler {onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allordersupdate.jsp", viewRootVar = viewRoot} viewRoot UIViewRoot; ordersArray Orders[0]; //array of Orders (from the database) sel int[0]; //Array of selected rows (from the dataTable!) //Note this array will contain ordersArray row indexes //... one array element for each row selected. selectedOrders string; //display variable // Function Declarations function onConstruction() get ordersArray; //Go get the data end function onPrerender() end function showSelOrders() selectedOrders = "";//Clear the selectedOrders variable //Loop through the selected dataTable rows for (i int from 1 to size(sel) by 1) //assign the OrdersArray[selection_array[index]].orderId selectedOrders += "" + ordersArray[sel[i]].OrderId; if(i != size(sel)) selectedOrders += ","; end end end end

    8. ? Create the default dataTable 2 of 5 After youve pressed Ctrl/S (to save your JSFHandler) return to Page Designer Drag and drop ordersArray on the page and create the dataTable shown below: Display all of the fields All of the fields should be input controls Except OrderID which should be an output control

    9. ? Add a selection column to the table 3 of 5 From Page Designer, select the entire dataTable, and from Row actions: Click: Add selection column to the table A new column will be added to your dataTable with a small checkbox inside it, representing the selection row action, and your Properties should show:? From: Value: click the Browse icon Select the sel int[] array OPTIONAL Click: Add selection toolbar Click: Add selection combo box

    10. ? Add an action thats performed when a row is clicked 4 of 5 ? From Page Data Drag and drop the showSelOrders function on the page it will create a Submit Button Drag and drop the selectedOrders string onto the page. Create an output text field From the dataTable properties, display 10 rows at a time, and enable paging Run the page and select rows (try out the cool-io buttons). Press showSelOrders Note: Obviously what youd really do with selected rows is process them (and only them) editing, writing out to the database, using them to look up other values, etc.Note: Obviously what youd really do with selected rows is process them (and only them) editing, writing out to the database, using them to look up other values, etc.

    11. JSF dataTable Row Actions OPTIONAL Radio-Button (single-row) Selection 5 of 5 By simply changing the hx:inputRowSelect Property to: ? Select only one row, you can change the multiple-row selection check-boxes to an exclusive (select only one row in a dataTable) radio-button. This slide contains EGL JSFHandler code to implement this with a new page. Follow the steps in the previous slides to do the JSF work. package jsfhandlers; import com.ibm.egl.jsf.UIViewRoot; import eglderbyr7.data.Customer; handler allcustomers3 type JSFHandler {onConstructionFunction = onConstruction, cancelOnPageTransition = yes, view = "allcustomers3.jsp", onPreRenderFunction = onpreRender, viewRootVar = viewRoot} viewRoot UIViewRoot; sel int[0]; msg string; customers customer[0]; //U.I. (dataTable) copy of customer rows sz, i int; //internal counters, etc. // Procedural (Business) Logic Section. Add EGL functions function onConstruction() get customers; end //end-onConstruction function onpreRender() end //end-onPreRender function updateCustomer() msg = "You clicked this customer's row: " + customers[sel[1]].LastName; end //end-function end //end JSFHandler package jsfhandlers; import com.ibm.egl.jsf.UIViewRoot; import eglderbyr7.data.Customer; handler allcustomers3 type JSFHandler {onConstructionFunction = onConstruction, cancelOnPageTransition = yes, view = "allcustomers3.jsp", onPreRenderFunction = onpreRender, viewRootVar = viewRoot} viewRoot UIViewRoot; sel int[0]; msg string; customers customer[0]; //U.I. (dataTable) copy of customer rows sz, i int; //internal counters, etc. // Procedural (Business) Logic Section. Add EGL functions function onConstruction() get customers; end //end-onConstruction function onpreRender() end //end-onPreRender function updateCustomer() msg = "You clicked this customer's row: " + customers[sel[1]].LastName; end //end-function end //end JSFHandler

    12. JSF dataTable Row Actions Editing a dataTable Row ?The final Row Action, Editing a dataTable row will allow you to easily add U.I. logic for: Displaying rows as read-only fields Allowing users to update one or more rows in the JSFHandler that provides the array data to the dataTable in the .JSP Save your changes to the database Note: For this technique, the array that is being displayed on the page must be held in session. Lets see how to implement this common requirement with EGL and JSF.

    13. ? Customize the EGL JSFHandler 1 of 6 Create a new, .JSP web page, named: allcustomersEditPanel.jsp Edit the JSFHandler and Copy/Paste the code in the Notes section of this slide and read the comments. Note the following: The updateCustomers() function tests individual fields for changes between the stored database copy of each row vs what the user might have modified in the browser (rendered in the U.I. copy of the row) The updateDBRow() function updates an individual row at a time package jsfhandlers; import com.ibm.egl.jsf.UIViewRoot; import eglderbyr7.data.Customer; handler allcustomersEditPanel type JSFHandler{onConstructionFunction = onConstruction, view = "allcustomersEditPanel.jsp", viewRootVar = viewRoot} viewRoot UIViewRoot; customersDB customer[0]; //database copy of customer rows customersUI customer[0]; //U.I. (dataTable) copy of customer rows customerRec customer; //individual record for potential update sz, i int; //internal counters, etc. // Procedural (Business) Logic Section. Add EGL functions function onConstruction() get customersDB; sz = size(customersDB); customersUI.appendAll(customersDB); end //end-onConstruction function updateCustomers() for(i from 1 to sz by 1) if(customersUI[i].FirstName != customersDB[i].FirstName || customersUI[i].LastName != customersDB[i].LastName || customersUI[i].PassWord != customersDB[i].PassWord || customersUI[i].Phone != customersDB[i].Phone || customersUI[i].EmailAddress != customersDB[i].EmailAddress || customersUI[i].Apartment != customersDB[i].Apartment || customersUI[i].City != customersDB[i].City || customersUI[i].Postalcode != customersDB[i].Postalcode || customersUI[i].State != customersDB[i].State || customersUI[i].Directions != customersDB[i].Directions) updateDBRow(); else //do nothing to this row end //end-if end //end-for end //end-function function updateDBRow() customerRec = customersui[i]; replace customerRec with #sql{ update EGL.CUSTOMER set EGL.CUSTOMER.FIRST_NAME = :customerRec.FirstName, EGL.CUSTOMER.LAST_NAME = :customerRec.LastName, EGL.CUSTOMER.PASSWORD = :customerRec.PassWord, EGL.CUSTOMER.PHONE = :customerRec.Phone, EGL.CUSTOMER.EMAIL_ADDRESS = :customerRec.EmailAddress, EGL.CUSTOMER.STREET = :customerRec.Street, EGL.CUSTOMER.APARTMENT = :customerRec.Apartment, EGL.CUSTOMER.CITY = :customerRec.City, EGL.CUSTOMER."STATE" = :customerRec.State, EGL.CUSTOMER.POSTALCODE = :customerRec.Postalcode, EGL.CUSTOMER.DIRECTIONS = :customerRec.Directions where EGL.Customer.customer_ID = :customerRec.CustomerID }; end //end function end //end JSFHandlerpackage jsfhandlers; import com.ibm.egl.jsf.UIViewRoot; import eglderbyr7.data.Customer; handler allcustomersEditPanel type JSFHandler{onConstructionFunction = onConstruction, view = "allcustomersEditPanel.jsp", viewRootVar = viewRoot} viewRoot UIViewRoot; customersDB customer[0]; //database copy of customer rows customersUI customer[0]; //U.I. (dataTable) copy of customer rows customerRec customer; //individual record for potential update sz, i int; //internal counters, etc. // Procedural (Business) Logic Section. Add EGL functions function onConstruction() get customersDB; sz = size(customersDB); customersUI.appendAll(customersDB); end //end-onConstruction function updateCustomers() for(i from 1 to sz by 1) if(customersUI[i].FirstName != customersDB[i].FirstName || customersUI[i].LastName != customersDB[i].LastName || customersUI[i].PassWord != customersDB[i].PassWord || customersUI[i].Phone != customersDB[i].Phone || customersUI[i].EmailAddress != customersDB[i].EmailAddress || customersUI[i].Apartment != customersDB[i].Apartment || customersUI[i].City != customersDB[i].City || customersUI[i].Postalcode != customersDB[i].Postalcode || customersUI[i].State != customersDB[i].State || customersUI[i].Directions != customersDB[i].Directions) updateDBRow(); else //do nothing to this row end //end-if end //end-for end //end-function function updateDBRow() customerRec = customersui[i]; replace customerRec with #sql{ update EGL.CUSTOMER set EGL.CUSTOMER.FIRST_NAME = :customerRec.FirstName, EGL.CUSTOMER.LAST_NAME = :customerRec.LastName, EGL.CUSTOMER.PASSWORD = :customerRec.PassWord, EGL.CUSTOMER.PHONE = :customerRec.Phone, EGL.CUSTOMER.EMAIL_ADDRESS = :customerRec.EmailAddress, EGL.CUSTOMER.STREET = :customerRec.Street, EGL.CUSTOMER.APARTMENT = :customerRec.Apartment, EGL.CUSTOMER.CITY = :customerRec.City, EGL.CUSTOMER."STATE" = :customerRec.State, EGL.CUSTOMER.POSTALCODE = :customerRec.Postalcode, EGL.CUSTOMER.DIRECTIONS = :customerRec.Directions where EGL.Customer.customer_ID = :customerRec.CustomerID }; end //end function end //end JSFHandler

    14. ? Add the Array to the Page and Customize its Properties 2 of 6 (from Page Data) Drag and drop the customersUI array, and create the dataTable shown here ? ? Use output (read/only) controls for the fields in the dataTable Feel free to enhance the control, adding: A border Alternate Row colors Paging Eight rows/per page

    15. ? Add an Edit Action that brings up a form for in-place editing 3 of 6 From Row Actions, click: Add an edit column that brings up a form for in-place editing of row content This will add a large column to the left of your existing columns, with a panel group box in which to add form fields

    16. ? Add the Update Function as a Submit Button 4 of 6 Drag and drop the updateCustomers() function onto the page, to become a submit button

    17. ? Test Your Work 5 of 6 Run the page. Test out the edit feature. Click updateCustomers to save your changes to the database.

    18. ? OPTIONAL Update a Row at a Time Through the Edit Form 6 of 6 ? You might want to update the row on the database (or at least launch a DB update request) once for each row clicked as opposed to doing them all at once at the end of the input / edit cycle. To do this: Create a new function in the JSFHandler that responds to a JSF component tree clicked row event (more on this in an upcoming section). There is a sample function in the slide Notes that will do this (and is commented for better understanding) Select the hx:commandExRowEdit component of the dataTable which is the row edit form. You may need to place your cursor in the FirstName field, and scroll to access this property. From Properties All Attributes: Select action And pick the new function Test your work function updateOneRow() // New function tableEx1 UIData; //variable of type JSF dataTable tableEx1 = viewRoot.findComponent("form1:tableEx1"); // initialize this variable with the address of the component i = tableEx1.getRowIndex() +1; //return the row clicked by the user and assign its value to the EGL table index (i) updateDBRow(); // invoke your table update function end function updateOneRow() // New function tableEx1 UIData; //variable of type JSF dataTable tableEx1 = viewRoot.findComponent("form1:tableEx1"); // initialize this variable with the address of the component i = tableEx1.getRowIndex() +1; //return the row clicked by the user and assign its value to the EGL table index (i) updateDBRow(); // invoke your table update function end

    19. JSF dataTable Row Actions Programmatically Changing a Cell Color in a dataTable ? Another common requirement is to programmatically (that is, within your EGL JSFHandler) color a given cell of a dataTable, for the purpose of drawing the users attention to it. Lets see how to implement this with EGL and JSF.

    20. ? Programmatically Changing a Cell Color in a dataTable 1 of 6 Create a new, .JSP web page, named: allcustomers5.jsp Edit the JSFHandler and Copy/Paste the code in the Notes section of this slide Save your changes, and read the comments. Notes: Essentially, in this technique you will create two panel-groups inside the column (cell) with a different colored HTML table in each. You will duplicate the JSF output field in each panel, and then hide/show the appropriate panel as per your logic requirements. So, after reading the database, you will iterate over the rows returned to the dynamic array and value the vis1/vis2 boolean fields (which are used to render the JSF panel groups) appropriately You will have to customize the SQLRecord (or BasicRecord) and add Persistent=no fields. package jsfhandlers; handler allcustomers5 type JSFHandler{onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allcustomers5.jsp"} customers customerTemp2[0]; //array of customer rows function onConstruction() get customers; //iterate over customers array. Hide/Show different panel-group box for(i int from 1 to size(customers) by 1) if(i % 2 == 0) customers[i].vis1 = true; customers[i].vis2 = false; else customers[i].vis1 = false; customers[i].vis2 = true; end end end function onPrerender() end end record customerTemp2 type SQLRecord{tableNames =[["EGL.Customer"]], keyItems =[CUSTOMER_ID]} CUSTOMER_ID int{column = "CUSTOMER_ID"}; FIRST_NAME string{column = "FIRST_NAME", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 30}; LAST_NAME string{column = "LAST_NAME", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 30}; PHONE string{column = "PHONE", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 14}; vis1 boolean{Persistent = no}; //render visible/hide for panel group1 vis2 boolean{Persistent = no}; //render visible/hide for panel group2 end package jsfhandlers; handler allcustomers5 type JSFHandler{onConstructionFunction = onConstruction, onPrerenderFunction = onPrerender, view = "allcustomers5.jsp"} customers customerTemp2[0]; //array of customer rows function onConstruction() get customers; //iterate over customers array. Hide/Show different panel-group box for(i int from 1 to size(customers) by 1) if(i % 2 == 0) customers[i].vis1 = true; customers[i].vis2 = false; else customers[i].vis1 = false; customers[i].vis2 = true; end end end function onPrerender() end end record customerTemp2 type SQLRecord{tableNames =[["EGL.Customer"]], keyItems =[CUSTOMER_ID]} CUSTOMER_ID int{column = "CUSTOMER_ID"}; FIRST_NAME string{column = "FIRST_NAME", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 30}; LAST_NAME string{column = "LAST_NAME", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 30}; PHONE string{column = "PHONE", isSqlNullable = yes, sqlVariableLen = yes, maxLen = 14}; vis1 boolean{Persistent = no}; //render visible/hide for panel group1 vis2 boolean{Persistent = no}; //render visible/hide for panel group2 end

    21. ? Programmatically Changing a Cell Color in a dataTable 2 of 6 From Page Designer/Page Data drag the customers array on to the page. Output (read/only) fields although that is just for this workshop, you could just as well have selected input fields But, dont select the vis1 or vis2 boolean fields Select and delete the {Phone} field (not the column, just the field)

    22. ? Programmatically Changing a Cell Color in a dataTable 3 of 6 From the Palette Drag a Panel Group Box (type: JSP) into the PHONE column Select (set focus to) the Panel Group Box, and from HTML Tags, double-click: Table 1 row/1 column 100% Table width 0 pixel Border width

    23. ? Programmatically Changing a Cell Color in a dataTable 4 of 6 From Enhanced Faces Components, drag an Output field into the table (inside the Panel Group) From Page Data, select PHONE and drag & drop on top of the new Output field Repeat the above series of steps to create another Panel Group (type: JSP) with another HTML table and new Output field bound (also) to PHONE

    24. ? Programmatically Changing a Cell Color in a dataTable 5 of 6 Select the HTML table, and from Properties, specify: Height: 100% Color (some custom color) Select the other HTML table, and repeat, giving it a different color

    25. ? Programmatically Changing a Cell Color in a dataTable 6 of 6 (For each of the JSP Panel Groups) Select the component From Properties/All Attributes Specify the rendered Attribute Value as: Compute From Page Data From the customers array, select either vis1 or vis2 Run the page on the server

    26. OPTIONAL WORKSHOP - JSF dataTable Showing Dynamic Images ? Youve seen pages like this before!!! Lets see how to implement this common requirement with EGL and JSF.

    27. JSF dataTable Dynamic Images 1 of 4 ?Create a new page, named: itemlist.jsp Right-click over the .JSP page, and from the EGL editor, add the following (USING CONTENT ASSIST): itemArray Item[0]; Status statusRec; ItemLib.GetItemListAll(itemArray, status); Press Ctrl/S (save and generate Java)

    28. JSF dataTable Dynamic Images 2 of 4 ?From Page Designer - From Page Data select itemArray, drag and drop it onto the page. Select: ? Displaying an existing record (Read/only) for the fields ?Select and delete the output field for image. ?From Enhanced Faces Components, select an Image control Drag and drop it into the empty Image column ?From Page Data, expand itemArray. Drag and drop Image onto the Image control.

    29. JSF dataTable Dynamic Images 3 of 4 Right-click over the Page, and select Run on Server

    30. JSF dataTable Dynamic Images 4 of 4 OPTIONAL Drag and Drop a link on the image in the dataTable. Set the properties (URL) as shown below: And add a parameter to pass the itemArray.itemid value to the itemdetail.jsp page (which you will have to create)

    31. ? OPTIONAL WORKSHOP - JSF dataTable Column Sort Using JavaScript 1 of 3 While somewhat limited, in the interaction with other JSF features and techniques, this JavaScript sort provided by Monuranjan Borgohain can be useful, and is extremely simple to implement. Steps (from Project Explorer): Right-click over the \theme\ folder under \WebContent\ and create a new file, named: sorttable.js (note, the extension is .js not .jsp) Copy the large JavaScript in the slide Notes below into the new file. Save and close the file Create a new .JSP page, named: javaScriptDataTableSort.jsp Edit the EGL Add the code shown here to: Declare an array of customer records Return the array data from the database Save (Ctrl/S) and return to Page Designer var stIsIE = /*@cc_on!@*/false; sorttable = { init: function() { // quit if this function has already been called if (arguments.callee.done) return; // flag this function so we don't do the same thing twice arguments.callee.done = true; // kill the timer if (_timer) clearInterval(_timer); if (!document.createElement || !document.getElementsByTagName) return; sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(/\bsortable\b/) != -1) { sorttable.makeSortable(table); } }); }, makeSortable: function(table) { if (table.getElementsByTagName('thead').length == 0) { // table doesn't have a tHead. Since it should have, create one and // put the first table row in it. the = document.createElement('thead'); the.appendChild(table.rows[0]); table.insertBefore(the,table.firstChild); } // Safari doesn't support table.tHead, sigh if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; if (table.tHead.rows.length != 1) return; // can't cope with two header rows // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as // "total" rows, for example). This is B&R, since what you're supposed // to do is put them in a tfoot. So, if there are sortbottom rows, // for backwards compatibility, move them to tfoot (creating it if needed). sortbottomrows = []; for (var i=0; i<table.rows.length; i++) { if (table.rows[i].className.search(/\bsortbottom\b/) != -1) { sortbottomrows[sortbottomrows.length] = table.rows[i]; } } if (sortbottomrows) { if (table.tFoot == null) { // table doesn't have a tfoot. Create one. tfo = document.createElement('tfoot'); table.appendChild(tfo); } for (var i=0; i<sortbottomrows.length; i++) { tfo.appendChild(sortbottomrows[i]); } delete sortbottomrows; } // work through each column and calculate its type headrow = table.tHead.rows[0].cells; for (var i=0; i<headrow.length; i++) { // manually override the type with a sorttable_type attribute if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/); if (mtch) { override = mtch[1]; } if (mtch && typeof sorttable["sort_"+override] == 'function') { headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; } else { headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); } // make it clickable to sort headrow[i].sorttable_columnindex = i; headrow[i].sorttable_tbody = table.tBodies[0]; dean_addEvent(headrow[i],"click", function(e) { if (this.className.search(/\bsorttable_sorted\b/) != -1) { // if we're already sorted by this column, just // reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted', 'sorttable_sorted_reverse'); this.removeChild(document.getElementById('sorttable_sortfwdind')); sortrevind = document.createElement('span'); sortrevind.id = "sorttable_sortrevind"; sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; this.appendChild(sortrevind); return; } if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { // if we're already sorted by this column in reverse, just // re-reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted_reverse', 'sorttable_sorted'); this.removeChild(document.getElementById('sorttable_sortrevind')); sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); return; } // remove sorttable_sorted classes theadrow = this.parentNode; forEach(theadrow.childNodes, function(cell) { if (cell.nodeType == 1) { // an element cell.className = cell.className.replace('sorttable_sorted_reverse',''); cell.className = cell.className.replace('sorttable_sorted',''); } }); sortfwdind = document.getElementById('sorttable_sortfwdind'); if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } sortrevind = document.getElementById('sorttable_sortrevind'); if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } this.className += ' sorttable_sorted'; sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); // build an array to sort. This is a Schwartzian transform thing, // i.e., we "decorate" each row with the actual sort key, // sort based on the sort keys, and then put the rows back in order // which is a lot faster because you only do getInnerText once per row row_array = []; col = this.sorttable_columnindex; rows = this.sorttable_tbody.rows; for (var j=0; j<rows.length; j++) { row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]]; } /* If you want a stable sort, uncomment the following line */ //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); /* and comment out this one */ row_array.sort(this.sorttable_sortfunction); tb = this.sorttable_tbody; for (var j=0; j<row_array.length; j++) { tb.appendChild(row_array[j][1]); } delete row_array; }); } } }, guessType: function(table, column) { // guess the type of a column based on its first non-blank row sortfn = sorttable.sort_alpha; for (var i=0; i<table.tBodies[0].rows.length; i++) { text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); if (text != '') { if (text.match(/^-?[$]?[\d,.]+%?$/)) { return sorttable.sort_numeric; } // check for a date: dd/mm/yyyy or dd/mm/yy // can have / or . or - as separator // can be mm/dd as well possdate = text.match(sorttable.DATE_RE) if (possdate) { // looks like a date first = parseInt(possdate[1]); second = parseInt(possdate[2]); if (first > 12) { // definitely dd/mm return sorttable.sort_ddmm; } else if (second > 12) { return sorttable.sort_mmdd; } else { // looks like a date, but we can't tell which, so assume // that it's dd/mm (English imperialism!) and keep looking sortfn = sorttable.sort_ddmm; } } } } return sortfn; }, getInnerText: function(node) { // gets the text we want to use for sorting for a cell. // strips leading and trailing whitespace. // this is *not* a generic getInnerText function; it's special to sorttable. // for example, you can override the cell text with a customkey attribute. // it also gets .value for <input> fields. hasInputs = (typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length; if (node.getAttribute("sorttable_customkey") != null) { return node.getAttribute("sorttable_customkey"); } else if (typeof node.textContent != 'undefined' && !hasInputs) { return node.textContent.replace(/^\s+|\s+$/g, ''); } else if (typeof node.innerText != 'undefined' && !hasInputs) { return node.innerText.replace(/^\s+|\s+$/g, ''); } else if (typeof node.text != 'undefined' && !hasInputs) { return node.text.replace(/^\s+|\s+$/g, ''); } else { switch (node.nodeType) { case 3: if (node.nodeName.toLowerCase() == 'input') { return node.value.replace(/^\s+|\s+$/g, ''); } case 4: return node.nodeValue.replace(/^\s+|\s+$/g, ''); break; case 1: case 11: var innerText = ''; for (var i = 0; i < node.childNodes.length; i++) { innerText += sorttable.getInnerText(node.childNodes[i]); } return innerText.replace(/^\s+|\s+$/g, ''); break; default: return ''; } } }, reverse: function(tbody) { // reverse the rows in a tbody newrows = []; for (var i=0; i<tbody.rows.length; i++) { newrows[newrows.length] = tbody.rows[i]; } for (var i=newrows.length-1; i>=0; i--) { tbody.appendChild(newrows[i]); } delete newrows; }, /* sort functions each sort function takes two parameters, a and b you are comparing a[0] and b[0] */ sort_numeric: function(a,b) { aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); if (isNaN(aa)) aa = 0; bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); if (isNaN(bb)) bb = 0; return aa-bb; }, sort_alpha: function(a,b) { if (a[0]==b[0]) return 0; if (a[0]<b[0]) return -1; return 1; }, sort_ddmm: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, sort_mmdd: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, shaker_sort: function(list, comp_func) { // A stable sort function to allow multi-level sorting of data // see: http://en.wikipedia.org/wiki/Cocktail_sort // thanks to Joseph Nahmias var b = 0; var t = list.length - 1; var swap = true; while(swap) { swap = false; for(var i = b; i < t; ++i) { if ( comp_func(list[i], list[i+1]) > 0 ) { var q = list[i]; list[i] = list[i+1]; list[i+1] = q; swap = true; } } // for t--; if (!swap) break; for(var i = t; i > b; --i) { if ( comp_func(list[i], list[i-1]) < 0 ) { var q = list[i]; list[i] = list[i-1]; list[i-1] = q; swap = true; } } // for b++; } // while(swap) } } /* ****************************************************************** Supporting functions: bundled here to avoid depending on a library ****************************************************************** */ // Dean Edwards/Matthias Miller/John Resig /* for Mozilla/Opera9 */ if (document.addEventListener) { document.addEventListener("DOMContentLoaded", sorttable.init, false); } /* for Internet Explorer */ /*@cc_on @*/ /*@if (@_win32) document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { sorttable.init(); // call the onload handler } }; /*@end @*/ /* for Safari */ if (/WebKit/i.test(navigator.userAgent)) { // sniff var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { sorttable.init(); // call the onload handler } }, 10); } /* for other browsers */ window.onload = sorttable.init; // written by Dean Edwards, 2005 // with input from Tino Zijdel, Matthias Miller, Diego Perini // http://dean.edwards.name/weblog/2005/10/add-event/ function dean_addEvent(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else { // assign each event handler a unique ID if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++; // create a hash table of event types for the element if (!element.events) element.events = {}; // create a hash table of event handlers for each element/event pair var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // store the existing event handler (if there is one) if (element["on" + type]) { handlers[0] = element["on" + type]; } } // store the event handler in the hash table handlers[handler.$$guid] = handler; // assign a global event handler to do all the work element["on" + type] = handleEvent; } }; // a counter used to create unique IDs dean_addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } }; function handleEvent(event) { var returnValue = true; // grab the event object (IE uses a global event object) event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); // get a reference to the hash table of event handlers var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { // add W3C standard event methods event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; } // Dean's forEach: http://dean.edwards.name/base/forEach.js /* forEach, version 1.0 Copyright 2006, Dean Edwards License: http://www.opensource.org/licenses/mit-license.php */ // array-like enumeration if (!Array.forEach) { // mozilla already supports this Array.forEach = function(array, block, context) { for (var i = 0; i < array.length; i++) { block.call(context, array[i], i, array); } }; } // generic enumeration Function.prototype.forEach = function(object, block, context) { for (var key in object) { if (typeof this.prototype[key] == "undefined") { block.call(context, object[key], key, object); } } }; // character enumeration String.forEach = function(string, block, context) { Array.forEach(string.split(""), function(chr, index) { block.call(context, chr, index, string); }); }; // globally resolve forEach enumeration var forEach = function(object, block, context) { if (object) { var resolve = Object; // default if (object instanceof Function) { // functions have a "length" property resolve = Function; } else if (object.forEach instanceof Function) { // the object implements a custom forEach method so use that object.forEach(block, context); return; } else if (typeof object == "string") { // the object is a string resolve = String; } else if (typeof object.length == "number") { // the object is array-like resolve = Array; } resolve.forEach(object, block, context); } }; var stIsIE = /*@cc_on!@*/false; sorttable = { init: function() { // quit if this function has already been called if (arguments.callee.done) return; // flag this function so we don't do the same thing twice arguments.callee.done = true; // kill the timer if (_timer) clearInterval(_timer); if (!document.createElement || !document.getElementsByTagName) return; sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(/\bsortable\b/) != -1) { sorttable.makeSortable(table); } }); }, makeSortable: function(table) { if (table.getElementsByTagName('thead').length == 0) { // table doesn't have a tHead. Since it should have, create one and // put the first table row in it. the = document.createElement('thead'); the.appendChild(table.rows[0]); table.insertBefore(the,table.firstChild); } // Safari doesn't support table.tHead, sigh if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; if (table.tHead.rows.length != 1) return; // can't cope with two header rows // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as // "total" rows, for example). This is B&R, since what you're supposed // to do is put them in a tfoot. So, if there are sortbottom rows, // for backwards compatibility, move them to tfoot (creating it if needed). sortbottomrows = []; for (var i=0; i<table.rows.length; i++) { if (table.rows[i].className.search(/\bsortbottom\b/) != -1) { sortbottomrows[sortbottomrows.length] = table.rows[i]; } } if (sortbottomrows) { if (table.tFoot == null) { // table doesn't have a tfoot. Create one. tfo = document.createElement('tfoot'); table.appendChild(tfo); } for (var i=0; i<sortbottomrows.length; i++) { tfo.appendChild(sortbottomrows[i]); } delete sortbottomrows; } // work through each column and calculate its type headrow = table.tHead.rows[0].cells; for (var i=0; i<headrow.length; i++) { // manually override the type with a sorttable_type attribute if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/); if (mtch) { override = mtch[1]; } if (mtch && typeof sorttable["sort_"+override] == 'function') { headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; } else { headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); } // make it clickable to sort headrow[i].sorttable_columnindex = i; headrow[i].sorttable_tbody = table.tBodies[0]; dean_addEvent(headrow[i],"click", function(e) { if (this.className.search(/\bsorttable_sorted\b/) != -1) { // if we're already sorted by this column, just // reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted', 'sorttable_sorted_reverse'); this.removeChild(document.getElementById('sorttable_sortfwdind')); sortrevind = document.createElement('span'); sortrevind.id = "sorttable_sortrevind"; sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; this.appendChild(sortrevind); return; } if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { // if we're already sorted by this column in reverse, just // re-reverse the table, which is quicker sorttable.reverse(this.sorttable_tbody); this.className = this.className.replace('sorttable_sorted_reverse', 'sorttable_sorted'); this.removeChild(document.getElementById('sorttable_sortrevind')); sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); return; } // remove sorttable_sorted classes theadrow = this.parentNode; forEach(theadrow.childNodes, function(cell) { if (cell.nodeType == 1) { // an element cell.className = cell.className.replace('sorttable_sorted_reverse',''); cell.className = cell.className.replace('sorttable_sorted',''); } }); sortfwdind = document.getElementById('sorttable_sortfwdind'); if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } sortrevind = document.getElementById('sorttable_sortrevind'); if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } this.className += ' sorttable_sorted'; sortfwdind = document.createElement('span'); sortfwdind.id = "sorttable_sortfwdind"; sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; this.appendChild(sortfwdind); // build an array to sort. This is a Schwartzian transform thing, // i.e., we "decorate" each row with the actual sort key, // sort based on the sort keys, and then put the rows back in order // which is a lot faster because you only do getInnerText once per row row_array = []; col = this.sorttable_columnindex; rows = this.sorttable_tbody.rows; for (var j=0; j<rows.length; j++) { row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]]; } /* If you want a stable sort, uncomment the following line */ //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); /* and comment out this one */ row_array.sort(this.sorttable_sortfunction); tb = this.sorttable_tbody; for (var j=0; j<row_array.length; j++) { tb.appendChild(row_array[j][1]); } delete row_array; }); } } }, guessType: function(table, column) { // guess the type of a column based on its first non-blank row sortfn = sorttable.sort_alpha; for (var i=0; i<table.tBodies[0].rows.length; i++) { text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); if (text != '') { if (text.match(/^-?[$]?[\d,.]+%?$/)) { return sorttable.sort_numeric; } // check for a date: dd/mm/yyyy or dd/mm/yy // can have / or . or - as separator // can be mm/dd as well possdate = text.match(sorttable.DATE_RE) if (possdate) { // looks like a date first = parseInt(possdate[1]); second = parseInt(possdate[2]); if (first > 12) { // definitely dd/mm return sorttable.sort_ddmm; } else if (second > 12) { return sorttable.sort_mmdd; } else { // looks like a date, but we can't tell which, so assume // that it's dd/mm (English imperialism!) and keep looking sortfn = sorttable.sort_ddmm; } } } } return sortfn; }, getInnerText: function(node) { // gets the text we want to use for sorting for a cell. // strips leading and trailing whitespace. // this is *not* a generic getInnerText function; it's special to sorttable. // for example, you can override the cell text with a customkey attribute. // it also gets .value for <input> fields. hasInputs = (typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length; if (node.getAttribute("sorttable_customkey") != null) { return node.getAttribute("sorttable_customkey"); } else if (typeof node.textContent != 'undefined' && !hasInputs) { return node.textContent.replace(/^\s+|\s+$/g, ''); } else if (typeof node.innerText != 'undefined' && !hasInputs) { return node.innerText.replace(/^\s+|\s+$/g, ''); } else if (typeof node.text != 'undefined' && !hasInputs) { return node.text.replace(/^\s+|\s+$/g, ''); } else { switch (node.nodeType) { case 3: if (node.nodeName.toLowerCase() == 'input') { return node.value.replace(/^\s+|\s+$/g, ''); } case 4: return node.nodeValue.replace(/^\s+|\s+$/g, ''); break; case 1: case 11: var innerText = ''; for (var i = 0; i < node.childNodes.length; i++) { innerText += sorttable.getInnerText(node.childNodes[i]); } return innerText.replace(/^\s+|\s+$/g, ''); break; default: return ''; } } }, reverse: function(tbody) { // reverse the rows in a tbody newrows = []; for (var i=0; i<tbody.rows.length; i++) { newrows[newrows.length] = tbody.rows[i]; } for (var i=newrows.length-1; i>=0; i--) { tbody.appendChild(newrows[i]); } delete newrows; }, /* sort functions each sort function takes two parameters, a and b you are comparing a[0] and b[0] */ sort_numeric: function(a,b) { aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); if (isNaN(aa)) aa = 0; bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); if (isNaN(bb)) bb = 0; return aa-bb; }, sort_alpha: function(a,b) { if (a[0]==b[0]) return 0; if (a[0]<b[0]) return -1; return 1; }, sort_ddmm: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; m = mtch[2]; d = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, sort_mmdd: function(a,b) { mtch = a[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt1 = y+m+d; mtch = b[0].match(sorttable.DATE_RE); y = mtch[3]; d = mtch[2]; m = mtch[1]; if (m.length == 1) m = '0'+m; if (d.length == 1) d = '0'+d; dt2 = y+m+d; if (dt1==dt2) return 0; if (dt1<dt2) return -1; return 1; }, shaker_sort: function(list, comp_func) { // A stable sort function to allow multi-level sorting of data // see: http://en.wikipedia.org/wiki/Cocktail_sort // thanks to Joseph Nahmias var b = 0; var t = list.length - 1; var swap = true; while(swap) { swap = false; for(var i = b; i < t; ++i) { if ( comp_func(list[i], list[i+1]) > 0 ) { var q = list[i]; list[i] = list[i+1]; list[i+1] = q; swap = true; } } // for t--; if (!swap) break; for(var i = t; i > b; --i) { if ( comp_func(list[i], list[i-1]) < 0 ) { var q = list[i]; list[i] = list[i-1]; list[i-1] = q; swap = true; } } // for b++; } // while(swap) } } /* ****************************************************************** Supporting functions: bundled here to avoid depending on a library ****************************************************************** */ // Dean Edwards/Matthias Miller/John Resig /* for Mozilla/Opera9 */ if (document.addEventListener) { document.addEventListener("DOMContentLoaded", sorttable.init, false); } /* for Internet Explorer */ /*@cc_on @*/ /*@if (@_win32) document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); var script = document.getElementById("__ie_onload"); script.onreadystatechange = function() { if (this.readyState == "complete") { sorttable.init(); // call the onload handler } }; /*@end @*/ /* for Safari */ if (/WebKit/i.test(navigator.userAgent)) { // sniff var _timer = setInterval(function() { if (/loaded|complete/.test(document.readyState)) { sorttable.init(); // call the onload handler } }, 10); } /* for other browsers */ window.onload = sorttable.init; // written by Dean Edwards, 2005 // with input from Tino Zijdel, Matthias Miller, Diego Perini // http://dean.edwards.name/weblog/2005/10/add-event/ function dean_addEvent(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false); } else { // assign each event handler a unique ID if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++; // create a hash table of event types for the element if (!element.events) element.events = {}; // create a hash table of event handlers for each element/event pair var handlers = element.events[type]; if (!handlers) { handlers = element.events[type] = {}; // store the existing event handler (if there is one) if (element["on" + type]) { handlers[0] = element["on" + type]; } } // store the event handler in the hash table handlers[handler.$$guid] = handler; // assign a global event handler to do all the work element["on" + type] = handleEvent; } }; // a counter used to create unique IDs dean_addEvent.guid = 1; function removeEvent(element, type, handler) { if (element.removeEventListener) { element.removeEventListener(type, handler, false); } else { // delete the event handler from the hash table if (element.events && element.events[type]) { delete element.events[type][handler.$$guid]; } } }; function handleEvent(event) { var returnValue = true; // grab the event object (IE uses a global event object) event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); // get a reference to the hash table of event handlers var handlers = this.events[event.type]; // execute each event handler for (var i in handlers) { this.$$handleEvent = handlers[i]; if (this.$$handleEvent(event) === false) { returnValue = false; } } return returnValue; }; function fixEvent(event) { // add W3C standard event methods event.preventDefault = fixEvent.preventDefault; event.stopPropagation = fixEvent.stopPropagation; return event; }; fixEvent.preventDefault = function() { this.returnValue = false; }; fixEvent.stopPropagation = function() { this.cancelBubble = true; } // Dean's forEach: http://dean.edwards.name/base/forEach.js /* forEach, version 1.0 Copyright 2006, Dean Edwards License: http://www.opensource.org/licenses/mit-license.php */ // array-like enumeration if (!Array.forEach) { // mozilla already supports this Array.forEach = function(array, block, context) { for (var i = 0; i < array.length; i++) { block.call(context, array[i], i, array); } }; } // generic enumeration Function.prototype.forEach = function(object, block, context) { for (var key in object) { if (typeof this.prototype[key] == "undefined") { block.call(context, object[key], key, object); } } }; // character enumeration String.forEach = function(string, block, context) { Array.forEach(string.split(""), function(chr, index) { block.call(context, chr, index, string); }); }; // globally resolve forEach enumeration var forEach = function(object, block, context) { if (object) { var resolve = Object; // default if (object instanceof Function) { // functions have a "length" property resolve = Function; } else if (object.forEach instanceof Function) { // the object implements a custom forEach method so use that object.forEach(block, context); return; } else if (typeof object == "string") { // the object is a string resolve = String; } else if (typeof object.length == "number") { // the object is array-like resolve = Array; } resolve.forEach(object, block, context); } };

    32. ? OPTIONAL WORKSHOP - JSF dataTable Column Sort Using JavaScript 2 of 3 (From Page Designer/Page Data): Drag and drop the customers array. Select some (not all) columns to become your dataTable (see next slide for an example) With the entire dataTable selected, change its Style class to: sortable From Page Designer (source) mode Add the following line near the top of the file as shown

    33. ? OPTIONAL WORKSHOP - JSF dataTable Column Sort Using JavaScript 3 of 3 Run the Page and click on any column heading text Optionally go back to Page Designer and try different U.I. features. Some will work, and others will not with this JavaScript approach

    34. Now that you have completed this unit, you should have: Stated the basic dataTable Concepts and Standard Options Working with the options in the web tooling Manipulated JSF dataTable as per U.I. requirements by enabling: dataTable Columns Centering/Aligning Programmatic heading text Sorting Adding/Substituting controls in rows Selection controls Submit buttons Dynamic behavior Rendering columns, fields and the dataTable visible or invisible Programmatically changing row U.I. properties Changing row color on mouse-over Summary dataTables Nested dataTables Unit Summary

More Related