In-line editing in XPages
Rune Hegge 19 February 2010 23:14:39
The Data Table and View controls are great for displaying views and document lists in XPages. However, even i 8.5.1 there's still some functionality you may miss in these controls. One of them is in-line editing. I don't know if there are any plans on including such functionality in the future, but right now I had to search for customized ways to implement in-line editing support. Searching several sources on the web I found some related articles, like this one on the XPages Blog, but not exactly what I was looking for. Finally I decided to build this functionality from scratch. In this article I describe the basic principles of my code, and I have also attached a sample database (link at the bottom of the article) that you may download and see all the elements in play. Now, let's have a look at what I did.Basic design elements
In the sample database there is a form, "Person", that we are using to store the documents. The form contains three fields, "Name" (text), "Age" (number) and "Gender" (text):
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The documents are listed in the "People" view:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
In the XPage "PeopleList" I added a Data Table control, "PeopleTable", with four columns, one for each field and then one column for buttons handling each row. The Data Table has a Data Binding to the People view and each row is addressed with the Collection name "person".
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
For each field in the "Person" form there is a Computed Field control with a Simple data binding to the corresponding field via the "person" data source. These controls will display the current field values from the documents in the "People" view.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Adding editable fields
Ok, so far I've only demonstrated standard Data Table functionality. Enabling the editability for the fields obviously will require some edit fields. For two of the fields in the Person form I've added an Edit Box control, for the last field, "Gender", I've added a Combo Box control. Each of these three controls are placed in the same column as the corresponding Computed Field control. I difference to the computed fields, both of the Edit Box controls and the Combo Box are binded to three View Scope variables; "currName", "currAge" and "currGender". A View Scope variable is available throughout all elements on the current page. These three variables will temporarily store the edited values added by the user.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
By default, the Data Table will display the document values in "read mode":
Put row in edit mode
We will now add functionality that will let the user select a document/line to edit. The nature of the Data Table is that it repeats it's content in the middle row for each document in the data source, in this case the "People" view. This means that both the Computed Fields and the Edit Boxes/Combo Box will be repeated for each document. However, we don't want both the "input" and the "read" controls to be displayed at the same time. Thus, we will now add a Visible formula for each of the controls. The principle of these formulas will be that a View Scope variable, one for each document/line, contains the "display state" of that document. This will be a boolean variable containing the values "true" (document is being edited) or "false" (document is in read mode). As we see from the image below, the collection name "person" representing the "current row" is used to retrieve the UNID of the document in question. The UNID is combined with "editLine" to create unique display state variables, one for each document. For the controls that should be displayed in read mode, the Visible formula will be "!viewScope.get("editLine" + person.getUniversalID())", the edit mode controls will have "viewScope.get("editLine" + person.getUniversalID())" (the inverse of the first formula).
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Now, let's have a look on how we will set these variables to put a row in edit mode and back in read mode. As mentioned before, in the rightmost column there are buttons that will work on the documents rows. Remeber that each of these buttons also will be repeated, so that every document in the document list has it's own representation. First, let's have a look at the "Edit" button. This button will obviously put the document in question in "edit mode". In the onclick-event we put javascipt code that will manipulate the corresponding view scope variable mentioned above and also retrieve document values from the backend document. In the first two lines of code in the image below we retrieve the UNID of the current document and use this to get a handle to the document (doc). In line 4,5 and 6 we pull out the current field values from the backend document and put them in the view scope variables that we earlier bound to the two Edit Box and the Combo Box controls. Now, these "editable fields" will display the values of the current document. In line 7 we see that the "editLine[UNID]" variable is set to true. We also see (to the right in the image) that the onclick event will perform a partial update of the "PeopleTable" control, which is the Data Table we are working with here. This will make the onclick event of the button update the Visible formulas for the controls within the Data Table. And with the new value of the view scope variable this will hide the "read controls" and show the "edit controls".
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The result of clicking the "Edit" button you see here:
Ok, so what you may be wondering about at this point is the purpose of line 3 and 8 in the code example above. As the three "edit controls" will serve every row in the Data Table, we need to make sure that values from row 1 is mixed with the values from row 2, and so on. The easiest way to do this is to make sure that only one row at a time is editable. So, in line 8 we set a view scope variable, "currentEditLine", to hold the name of the unique variable we discussed earlier. In line 3 of the javascript code we use this value (if previously set by another Edit button) to reset the "Visible variable" for that row (reset = set to false). If this is confusing, just accept that these two lines of code will make sure that only one row at a time is editable.
Update document with new values
So, now the row is in edit mode. We assume that the user will change one or more of the values. The goal for us now must be to be able to write these values back to the backend document. This will be done by another button in column 4; "Save". As in the code for the "Edit" button, line 1 and 2 retrieves the backend document into the "doc" variable using the UNID from the current row. Line 3-5 retrieves the view scope variables corresponding to the three fields and replaces the current field values with the (potential) new values from these variables. Remember that these are the view scope variables bound to the editable controls. Line 6 saves the backend document.
In line 7 we set the "Visible" view scope variable to "false" to put the current row back in read mode.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
And that's about it, folks. The only thing I haven'd covered so far is the "Cancel" link, also within column 4. This link has an onclick event identical to line 7 of the "Save" button. This means that it puts the current row back into read mode, without performing any document update. Another detail worth mentioning is that the Edit, Save and Cancel buttons have Visible formulas identical to the corresponding read and edit controls in the other columns.
Possible improvements
This is a very basic example on how to add in-line editability to a standard Data Table control. It covers the most important factors for this functionality. However, there are some obvious suggestions for improvements. For example, if a user now click the "Edit" button for a row while another row already is in edit mode, any changes made by the user in the first row will be lost. The javascript formula may be modified to either ask the user whether to save the changes or just save any changes directly.
Another improvement may be to make an onclick event for the whole row that will replace the Edit button. However, to do this today, I beleve that a Repeat control must be used instead of the Data Control, and this will probably involve a lot more coding. But please prove me wrong :-) In that case, John Mackey's article on "Dynamic View Custom Control" may be a good place to start.
- Comments [1]
