XPage Ajax文档创建

This might seem like a duplicate but please read first and let me know if you have questions. I have a single xpage with two data sources, one form for information and the other for image attachments. Now unlike typical applications I do not want to attach the image to the existing main data source (the first one) I want to asynchronously upload images and create separate documents for each image with the main datasource's UNID as the subID of the new image document. This is the just the way of the current data structure and I have little to no say on changing this so here's the challenge is presented.

I have successfully been able to create xhr requests (with the guide of various async uploader previous works of Julian and Sven) and create new documents with images with the custom control I have written but once I embed it into the XPage with two datasources and attempt to upload and create a new document, it creates a duplicate of the main datasource and wipes out all the other field values (expected behavior of a duplicate with empty fields). I suspect it's because I use the $$submitid and all the required form values for my upload request and they're somehow tied or shared with the first datasource but I can't be too sure.

My custom control has it's own datasource and the xpage has a panel with a datasource as part of it. Custom Control below.


    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
        <xp:this.data>
            <xp:dominoDocument var="imgAttach" formName="mImageAttach"
                concurrencyMode="force">
            </xp:dominoDocument>
        </xp:this.data>
        <xp:inputText id="inputText2" style="width:657.0px"><xp:this.defaultValue><![CDATA[#{javascript:facesContext.getExternalContext().getRequest().getRequestURI();
    context.getUrl()}]]></xp:this.defaultValue></xp:inputText>
        <xp:br></xp:br>
        <xp:br></xp:br>
        <xp:inputText id="parentId" value="#{imgAttach.ParUNID}"
            style="width:333.0px">

            <xp:this.defaultValue><![CDATA[#{javascript:var url = context.getUrl().toString();
    /*
    if(url.indexOf("createComponent.xsp") > 0 && context.getUrlParameter("documentId") != ""){
        var doc:NotesDocument = newComponent.getDocument();
        return doc.getUniversalID();
    } else {
        return "";
    }
    */}]]></xp:this.defaultValue>
            <xp:this.rendered><![CDATA[#{javascript:var url = context.getUrl().toString();
    if(url.indexOf("createComponent.xsp") > 0){
        return true;
    } else {
        return false;
    }}]]></xp:this.rendered>
        </xp:inputText>
        <xp:br></xp:br>
        <xp:br></xp:br>
        <xp:inputText id="inputText1"
            defaultValue="#{javascript:imgAttach.getDocument().getUniversalID()}"
            style="width:333.0px; display:none;">
        </xp:inputText>
        <xp:br></xp:br>
        <xp:br></xp:br>
        <xp:inputText id="Created" style="width:297.0px; display:none;"
            value="#{imgAttach.Created}"
            defaultValue="#{javascript:@Created()}">
            <xp:this.converter>
                <xp:convertDateTime type="date" dateStyle="short"></xp:convertDateTime>
            </xp:this.converter>
        </xp:inputText>
        <xp:br></xp:br>
        <xp:div styleClass="file-input">
            <div class="file-preview ">
                <div class="close fileinput-remove">×</div>
                <div class="">
                    <div class="file-preview-thumbnails" id="file-thumbs">
                    </div>
                    <div class="clearfix"></div>
                    <div
                        class="file-preview-status text-center text-success">
                    </div>
                    <div class="fileinput-error file-error-message"
                        style="display: none;">
                    </div>
                </div>
            </div>
            <div class="input-group-btn">
                <button type="button" tabindex="500"
                    title="Clear selected files"
                    class="btn btn-default fileinput-remove fileinput-remove-button">
                    <i class="glyphicon glyphicon-trash"></i>
                    Remove
                </button>
                <button tabindex="500" id="upload-files"
                    title="Upload selected files"
                    class="btn btn-default fileinput-upload fileinput-upload-button">
                    <i class="glyphicon glyphicon-upload"></i>
                    Upload
                </button>
                <div tabindex="500" class="btn btn-primary btn-file"
                    id="files-container">
                    <i class="glyphicon glyphicon-folder-open"></i>
                    &#160;Browse …
                    <input name="add-files[0]" id="add-files" type="file"
                        multiple="true" class="file-input">
                    </input>

                    <xp:fileUpload id="FileUploadCtrl"
                        value="#{imgAttach.Body}" useUploadname="true"
                        style="display:none">
                    </xp:fileUpload>
                    <xp:eventHandler event="onsaveDoc" submit="false"
                        refreshMode="norefresh" immediate="false" save="true" id="saveDoc" />
                </div>
            </div>
        </xp:div>


        <xp:br></xp:br>
        <xp:br></xp:br>
        <xp:scriptBlock id="scriptBlock2" type="text/javascript">
            <xp:this.value>
                <![CDATA[
    $(function() {

       $("#files-container").delegate('input', "change", function() {  
            var files = !!this.files ? this.files : [];
            if (!files.length || !window.FileReader){
                //console.log("No file selected or no file reader suppport");
                 return; // no file selected, or no FileReader support
            }


                for(i=0; i<files.length; i++) {
                    if (/^image/.test( files[i].type)){ // only image file
                        var reader = new FileReader(); // instance of the FileReader
                        reader.readAsDataURL(files[i]); // read the local file

                        var img = document.createElement("img");
                        img.file = files[i];
                        img.name = 'no_'+ i;
                        img.classList.add("file-preview-image");
                        reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
                        $("#file-thumbs").append(img);                  
                    }                       
                }

                /*
                //add new upload button
                var currentInput = $('#add-files');
                var nextInput = $('#files-container');
                var inputsCount = $('.file-input').length;

               // now we change the 'id' attribute of said element because id's should be unique
                currentInput.attr('id','add-files'+inputsCount);

                // and finally we hide the old element
                currentInput.hide();

                // now, we append a new input element with an incremented array key defined by the length of already existing input elements
                nextInput.append('<input type="file" name="add-files['+inputsCount+']" id="add-files" multiple="true" class="file-input" />');          
                */

        });

     $("#upload-files").on("click", function(e) {
            e.preventDefault();
            e.stopPropagation();
            var all_files = [];
            try {
              var files = document.querySelectorAll(".file-preview-image");

              for(var i = 0; i < files.length; i++) {
                  //
                  a_uploader(files[i].file, "#{id:saveDoc}", 0, 10);
              }

            } catch(e) {
                console.log(e);
            }
        });

      function a_uploader(file, uploadID, counter, maxSize){
            try {
                var formData = new FormData();          

                formData.append("#{id:FileUploadCtrl}", file);
                formData.append("#{id:Created}", document.getElementById("#{id:Created}").value);
                formData.append("$$viewid", dojo.query("input[name='$$viewid']")[0].value);
                formData.append("$$xspsubmitid", uploadID);
                formData.append( "view:_id1", "view:_id1");


                if(document.getElementById("#{id:parentId}") != undefined ){
                    formData.append("#{id:parentId}", document.getElementById("#{id:parentId}").value);
                }

                var xhr = new XMLHttpRequest();

                  /* event listners */
                  xhr.upload.addEventListener("progress", function(e) {
                      if (e.lengthComputable) {
                            var percentComplete = Math.round(e.loaded * 100 / e.total);
                            console.log("Uploading... " +percentComplete.toString() + "%)");
                          }
                          else {
                            console.log("Uploading...")
                          }

                  }, false);
                 xhr.addEventListener("error", function(e) {
                    //insert error between error div
                     console.log("error: " + e);
                 }, false);
                 xhr.addEventListener("abort", function() {
                     //insert cancelled between div
                     console.log("Upload cancelled");
                 }, false);
                  xhr.open("PATCH", "#{javascript:context.getUrl()}");
                  xhr.send(formData);



            } catch (e) {
                console.log("a_uploader: "+e);
            }       
        }

        function clear_inputFiles(){
            try {
              var files = document.querySelectorAll(".file-preview-image");

              for(var i = 0; i < files.length; i++) {

              }     
            } catch(e) {

            }
        }   

     });]]>
            </xp:this.value>
        </xp:scriptBlock>
        <xp:this.resources>
            <xp:script src="/x$.js" clientSide="true"></xp:script>
        </xp:this.resources>
    </xp:view>

I thought I had set my first datasource to ignore request params as well as the data source inside of the component control. After setting the ignore request params to true on the first data source and finagling the datasource to get the document ID if it was edit mode, I was then able to use the custom control to upload images independently of the first/main datasource.

Now that they are uploading independently there is still a duplicate being created which seems odd to me. If I click the save button the first data source I don't create any image attachments but if I upload images it creates a duplicate of the primary doc.


Edit: I had to remove the editDocument and documentId from the URL and specify my own docId as a parameter. I guess the HTTP referrer was the culprit in this case for creating the duplicate....or at least the way the page was set up from creating the doc to saving the doc.