0

I have a repeat control which displays documents in a particular view. For each document (row of data) a user can edit and save these items in-line. I have additional button which marks a single document as default and this is visible only in Edit Mode, before it marks the current document as default, it goes through all the other documents and un-marks them from being default. This mark as default works the first time, but when I try it again (second time), it creates replication conflicts.

The edit button just changes the mode to edit mode.

Save does the following (partial refresh):

<xp:this.action>
    <xp:actionGroup>
        <xp:saveDocument var="deliveryDocument"></xp:saveDocument>
        <xp:changeDocumentMode mode="readOnly"
            var="deliveryDocument">
        </xp:changeDocumentMode>
    </xp:actionGroup>
</xp:this.action>

Set default does the following (full refresh):

<xp:this.action>
    <xp:actionGroup>
        <xp:executeScript
            script="#{javascript:markAsDefault(deliveryDocument);}">

        </xp:executeScript>
        <xp:saveDocument var="deliveryDocument"></xp:saveDocument>
        <xp:changeDocumentMode mode="readOnly"
            var="deliveryDocument">
        </xp:changeDocumentMode>
    </xp:actionGroup>
</xp:this.action>

markAsDefault first of all goes through all existing delivery documents and sets isDefault to be blank (except the current document) and then sets the isDefault value for the current document (it doesn't save the back-end document and the loop does doc.recycle()).

Any help would be appreciated.

Update:

function markAsDefault(deliveryDoc) {
    try {
        var db:NotesDatabase = deliveryDoc.getParentDatabase();
        var vwDeliveryAddress:NotesView = db.getView("viewName");

        var dc:NotesDocumentCollection = vwDeliveryAddress.getAllDocumentsByKey(deliveryDoc.getItemValueString("fldID"), true);

        var strUniversalID:String;

        strUniversalID = deliveryDoc.getDocument().getUniversalID();

        if (dc.getCount() > 0) {
            var doc:NotesDocument = dc.getFirstDocument()
            var nextDoc:NotesDocument;

            // mark all other docs as not default
            while (doc != null) {
                nextDoc = dc.getNextDocument();

                if (doc.getUniversalID() != strUniversalID) {
                    doc.replaceItemValue("isDefault", "");
                    doc.save();

                    doc.recycle();
                }

                doc = nextDoc;
            }
        }

        deliveryDoc.replaceItemValue("isDefault", "Yes");
    } catch (e) {
        log.logError(e.toString(), SEVERITY_HIGH, e.toString(), null, "website.nsf", "markAsDefault()", null, null);
    }
}
pipalia
  • 911
  • 1
  • 12
  • 46

1 Answers1

2

I think the reason for save conflicts is because you're dealing with the same documents in memory (on the XPage), and on disk. The time stamp for the in memory document is before the on disk document was saved, hence the save conflict when you save the in memory document.

If you don't mind things overwriting each other without conflicts, you can set a property in the form that prevents save conflicts. In form properties, on the first tab: Conflict Handling - Do not create conflicts.

The simplest way to work around the issue without setting the property is to only have one document editable at a time. Have a viewScope variable that contains the unid of the currently editable document. Set the form rendered based on this property. Bind the fields to requestScope, with default value from document. When user clicks save, look up the document by unid/update from requestScope values. This way, you're only dealing with the documents on disk.

Edit - Sample code:

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:this.data>
        <xp:dominoView var="peopleView" viewName="People"></xp:dominoView>
    </xp:this.data>
    <xp:table id="peopleTable">
        <xp:repeat id="peopleRepeat" rows="30" value="#{peopleView}" var="personRow">
            <xp:panel rendered="#{javascript:return ( viewScope.editableUnid === personRow.getUniversalID() );}"
                tagName="tr">
                <td>
                    <xp:inputText value="#{requestScope.firstName}" defaultValue="#{personRow.first_name}" />
                </td>
                <td>
                    <xp:inputText value="#{requestScope.lastName}" defaultValue="#{personRow.last_name}" />
                </td>
                <td>
                    <xp:button id="saveButton" value="Save">
                        <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="peopleTable">
                            <xp:this.action><![CDATA[#{javascript:var doc = database.getDocumentByUNID( viewScope.editableUnid );
doc.replaceItemValue( 'first_name', requestScope.firstName );
doc.replaceItemValue( 'last_name', requestScope.lastName );
doc.save();
viewScope.editableUnid = null;}]]></xp:this.action>
                        </xp:eventHandler>
                    </xp:button>
                    <xp:button id="cancelButton" value="Cancel">
                        <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="peopleTable">
                            <xp:this.action><![CDATA[#{javascript:viewScope.editableUnid = null;}]]></xp:this.action>
                        </xp:eventHandler>
                    </xp:button>
                </td>
            </xp:panel>
            <xp:panel rendered="#{javascript:return ( viewScope.editableUnid != personRow.getUniversalID() );}" tagName="tr">
                <td>
                    <xp:text value="#{personRow.first_name}" />
                </td>
                <td>
                    <xp:text value="#{personRow.last_name}" />
                </td>
                <td>
                    <xp:button id="editButton" value="Edit">
                        <xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="peopleTable">
                            <xp:this.action><![CDATA[#{javascript:viewScope.editableUnid = personRow.getUniversalID();}]]></xp:this.action>
                        </xp:eventHandler>
                    </xp:button>
                </td>
            </xp:panel>
        </xp:repeat>
    </xp:table>
</xp:view>
Tommy Valand
  • 868
  • 6
  • 10
  • How will this work with a repeat control? Will I have to display a dialog to amend each document or will it work in-line as it does at the moment? – pipalia Aug 31 '12 at 10:15
  • If you bind the repeat control to a view, show the values in computed fields. Have a form that contains the same fields also in the repeat. You can use the view values as default value for the form fields. The unid for the documents can be fetched from the row var. This way you get good performance/small memory usage as the values are read from view. When the "editable" unid is the same as a row, hide the computed fields+edit control, and show the form fields+save control. – Tommy Valand Aug 31 '12 at 10:22
  • is it possible to update your answer with same simple code sample that demonstrates this using a repeat control (where the data source for the repeat control is a view filtered by column value) – pipalia Sep 03 '12 at 09:35
  • I have a panel within the repeat control, which get's the back-end document and that is being used as the data source. I tried setting the scope for that data source to view scope but that didn't help. – pipalia Sep 03 '12 at 19:26
  • I updated my answer with a sample of what I mean. As it's purely for demo, the underlying document only has two fields. first_name and last_name. The view that the repeat uses has two columns bound to these fields. – Tommy Valand Sep 04 '12 at 05:35
  • Many thanks Tommy, this could work, although the down-side is that I will have to manually save all the fields and I can only amend one delivery address at a time. I have fixed the problem for the time being by using "openpage" and opening the same page when a user clicks on the set default button. I will accept this answer as the best answer, many thanks for your help Tommy. – pipalia Sep 04 '12 at 10:58