In this post, I’ll discuss several options and demonstrate one method of adding a new document via a Dojo Data Grid in XPages.
Dojo Data Grid Series
Dojo Grids in XPages — All Blog Posts
Adding a New Item
Looking at the dojo documentation, you can see that there is a newItem method of the data store that is used to add a new entry in the grid.
Caveats
You can get this to work with a grid in XPages, but there are several caveats to note:
- If a new row is added programmatically, it will not display in the grid immediately. It appears that it will require a partial refresh of the REST service and the grid in order to see it. (The XPages REST service must not be using the Notification type of store, which would add it to the grid immediately.)
- It only works with a viewJsonService REST service (more on that in a moment)
- It requires saving the REST service in order to post the new document (more on that in a moment as well)
The Problem with viewItemFileService
I was very surprised to find that adding a new document does not work with a viewItemFileService REST service, because editing documents and deleting them work just fine.
When I tried to use the newItem() method of the REST service, I saw this error in the Firebug console:
Unimplemented API: dojo.data.api.Write.newItem
I ran some code to verify that the newItem method exists for this type of REST service. I then looked at the source of the method and saw this:
newItem: function (/* Object? */ keywordArgs, /*Object?*/ parentInfo){
throw new Error('Unimplemented API: dojo.data.api.Write.newItem');
}
Guess that explains the error — the method wasn’t implemented for the viewItemFileService!
Using viewJsonService
The good news is that it does work with a viewJsonService REST service.
Interestingly, I assumed I would need a Web Site document that allowed PUT operations to work with this type of service (because it was required for editing rows and the DELETE operation must be enabled to allow deletions), but it seems to work without it! (NOTE: This is with very limited testing and a lot of moving parts, but I tried it several times and it seems to be fine without it.)
I would expect that a Web Site document would be required if using an AJAX call to post to the REST service, but I haven’t tried it yet.
Setting new document fields
You can only set the value of fields that are columns in the REST service whose names match field names on the underlying documents.
It will just ignore fields with different names. Case sensitivity does not seem to matter.
Setting the Form Name
There’s a formName property of the REST service that you can set to define the form name that will be assigned when a new document is added via the REST service. This is a handy property; otherwise, you’d have to add a column to the underlying view to display the form name and add the form name to the request that gets posted back to the REST service.
![Grid26_0]()
Adding the New Row
There are several ways to approach this. Ultimately, you have to provide the user a way to enter the data in order to create a new document.
My initial thought was to add an empty row to the end of the grid and let the user populate it and save it. But after thinking about it a bit, I came to the conclusion it’s not my preference. My concern is that if you add a blank row to the end of the grid, but then edit some other document and save it, you’ll commit the edit as well as a blank document. (I realize it’s possible to post updates to a single document via the REST service, but that’s beyond the scope of this discussion.)
Currently, I like the idea of using a separate copy of the same grid to fill in the data for a new row.
![Grid26_1]()
I believe it has several advantages:
- The ability to add a new row is always visible. If there’s a lot of data in the grid, the user would have to scroll to the end in order to see the new row.
- There’s no chance of inadvertently saving a blank document if the user edits a row and saves the data store.
- You can easily run client-side validation of the data before adding the document.
- You can allow the user to enter data in every grid column without allowing it on all existing documents.
At a high level, these are the steps for this configuration:
- Create a copy of your main grid’s REST service.
- Give it a ‘keys’ attribute of an unmatchable string, such as ‘!@#$%^&*()’ and set keysExactMatch to true
- This will ensure that the second grid has the same structure and fields available, but doesn’t have any data to display.
- Create a copy of the main grid and bind it to the new REST service
- Set all of the columns in the second grid to be editable.
- Add a new, blank row to the second grid.
- Add a button that will take the new data and create a new document by posting it to the main REST service.
Adding a blank row
This code will add a blank row to the second grid (assuming the grid ID is djxDataGrid2).
djxDataGrid2.store.newItem();
I’m sure there’s a better way than clicking a button to add the row, but it does the job for this proof-of-concept. (It didn’t work in the onClientLoad event of the page, probably because the grid wasn’t finished loading at that time.)
Posting the New Document
With a few lines of code, you can retrieve the row in the second grid and post it to the REST service of the main grid.
// Read the first item from the 'new' grid
var newItem = djxDataGrid2.getItem(0);
djxDataGrid1.store.newItem(newItem);
// Post the new document to the main grid's REST service
var args = {onError: function() {alert('error!');}};
djxDataGrid1.store.save(args);
// Clear the row from grid 2 and add a new blank row
djxDataGrid2.store.deleteItem(newItem);
djxDataGrid2.store.newItem();
Lines 2-3 post the item from the second grid back to the REST service of the main grid. You don’t have to worry about properly formatting the JSON for the post, because the grid item is already formatted the way it needs to be.
Lines 6-7 shows how to add a callback function to display an error message if the update fails.
Lines 10-11 remove the row from the second grid and add a new blank one for a new entry.
Adding client-side validation
It’s easy to add some client-side validation to ensure that fields are filled in before saving the new document. Each column in the grid can be accessed as an attribute of the grid row, as shown in line 5 below.
// Read the first item from the 'new' grid
var newItem = djxDataGrid2.getItem(0);
// Validate that the first name is filled in
if (newItem.firstname == undefined) {
alert('error2 -- must fill in first name')
return;
}
djxDataGrid1.store.newItem(newItem);
// Post the new document to the main grid's REST service
var args = {onError: function() {alert('error!');}};
djxDataGrid1.store.save(args);
// Clear the row from grid 2 and add a new blank row
djxDataGrid2.store.deleteItem(newItem);
djxDataGrid2.store.newItem();
Other Options for Adding a Data Entry
If you don’t like this method, there are several other options for adding a new document.
You could pop up a dialog box or display an embedded form on the page. If you use client-side JavaScript, you could format the data and post it to the REST service. You would build the object like this:
var myNewItem = {firstname: "New First Name Value", lastname: "New Last Name Value"};
You could also use server-side code to create the document in the back end if using a dialog or form.