I have a fileUploader on one of my XPages. The problem which I have encountered is when I try to use it with xp.this.rendered property it actually REMOVES a DOM element which it's supposed to update. Without the property it works so well, but sometimes I have to display the fileUploader only when some condition is true:
What I did here:
- Opened a page with step №1 (default). It's just a table in the main
div_main
element (input_step
is 1) - Uploaded a file there
- Cliked the Next step button
- It refreshed
div_main
element and setinput_step
component value to 2 - The 2nd table is displayed (the rendered condition is
rendered="#{javascript:getComponent('input_step').getValue()=='2'}"
) - I tried to upload a file to the second table
- Then there's the code which triggers the refresh button (I'll post it below)
- It does upload file to the server, but removes the DOM element it's supposed to refresh and execute on
- Then just for experement I clicked the "Previous step" which refreshs the entire
div_main
- BUT! Instead of refreshing
div_main
it doesn't do anything! It only refreshes itself, but doesn't go into the code which setsinput_step
back to 1. - When I click again on the "Previous step" it goes back to the first step it works as it should
I absolutely have no IDEA why this happens. It's really irritating I have never come across such an eerie problem in my life.
Here's the div_main
<xp:div styleClass="doc_list" id="div_main">
<xp:table style="width:100.0%">
<xp:tr>
<xp:td style="width:25.0%" align="center" valign="top"
styleClass="background">
</xp:td>
<xp:td id="content" styleClass="background_field">
<xp:table id="table_nav" style="width:100.0%">
<xp:tr>
<xp:td style="width:100.0%" align="center"
styleClass="background_field">
<xp:label id="label152"
styleClass="doc_header_step_title">
<xp:this.value><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
switch (step) {
case "1":
return('Step1')
break;
case "2":
return('Step2')
break;
case "3":
return('Step3')
break;
case "4":
return('Step4')
break;
case "":
return('Step1')
break;
}}]]></xp:this.value>
</xp:label>
</xp:td>
</xp:tr>
</xp:table>
<xc:User_request_new_step_1></xc:User_request_new_step_1>
<xc:User_request_new_step_2></xc:User_request_new_step_2>
<!-- <xc:User_request_step_3></xc:User_request_step_3> -->
<xp:table id="table_step4" style="width:100.0%"
rendered="#{javascript:getComponent('input_step').getValue()=='4'}">
<xp:tr>
<xp:td style="width:50.0%" align="center">
<xc:Doc2_Tree_Structure
syselem="gecho_directory">
</xc:Doc2_Tree_Structure>
</xp:td>
</xp:tr>
</xp:table>
<xp:table id="table_step5" style="width:100.0%"
rendered="false">
<xp:tr id="tr_sign">
<xp:td id="td_sign">
<xc:Event2_cryptopro></xc:Event2_cryptopro>
</xp:td>
</xp:tr>
<xp:tr id="tr_sign_button">
<xp:td id="td_sign_button" align="center">
<xp:inputHidden id="gechoSign"
value="#{doc_source.gechoSign}">
</xp:inputHidden>
<xp:table style="width:1.0%">
<xp:tr>
<xp:td style="width:1.0%"
styleClass="doc_field_select" id="td10">
<xp:text
id="cf_create_button"
value="#{javascript:return('Sign')}" escape="false">
</xp:text>
<xp:eventHandler
event="onclick" submit="true" refreshMode="partial"
refreshId="table_step5">
<xp:this.action><![CDATA[#{javascript:getComponent('inputBase64').setValue(generateSignData(doc_source.getDocument()));
var tprint=getComponent('inputThumbprint').getValue()
var base64id=getComponent('inputBase64').getClientId(facesContext)
var resid=getComponent('gechoSign').getClientId(facesContext)
var csjs="signCryptoPro('"+tprint+"','"+base64id+"','"+resid+"')"
//print(csjs)
view.postScript(csjs)}]]></xp:this.action>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
</xp:td>
</xp:tr>
</xp:table>
<xp:table id="table_nav_bottom"
style="width:100.0%">
<xp:tr>
<xp:td style="width:25.0%" align="right">
<xp:table>
<xp:tr>
<xp:td
styleClass="doc_field_select" id="td1">
<xp:this.rendered><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
if (step=="" | step=="1") {return(false)}
return(true)}]]></xp:this.rendered>
<xp:text escape="false"
id="computedField1"
value="#{javascript:return(texticon('arrow-31-left',20,20,'Previous step',false))}">
</xp:text>
<xp:eventHandler
event="onclick" submit="true" refreshMode="partial"
refreshId="div_main" disableValidators="true">
<xp:this.action><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
print("step value before is " + getComponent('input_step').getValue());
switch (step) {
case "1":
getComponent('input_step').setValue('1')
break;
case "2":
getComponent('input_step').setValue('1')
break;
case "3":
getComponent('input_step').setValue('2')
break;
case "4":
getComponent('input_step').setValue('3')
break;
case "":
getComponent('input_step').setValue('1')
break;
}
print("step value after is " + getComponent('input_step').getValue());
}]]></xp:this.action>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
</xp:td>
<xp:td style="width:50.0%">
</xp:td>
<xp:td style="width:25.0%" align="left">
<xp:table>
<xp:this.rendered><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
if (step=="" | step=="4") {return(false)}
return(true)
}]]></xp:this.rendered>
<xp:tr>
<xp:td
styleClass="doc_field_select" id="NextStep">
<xp:text escape="false"
id="computedField2">
<xp:this.value><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
if (step=="" | step=="4") {return(texticon('check-mark-5-icon',20,20,'Save',false))}
return(texticon('arrow-31',20,20,'Next step',false))
}]]></xp:this.value>
</xp:text>
<xp:eventHandler
event="onclick" submit="true" refreshMode="partial"
refreshId="div_main">
<xp:this.action><![CDATA[#{javascript:var step=getComponent('input_step').getValue()
switch (step) {
case "1":
getComponent('input_step').setValue('2')
break;
case "2":
getComponent('input_step').setValue('3')
break;
case "3":
getComponent('input_step').setValue('4')
break;
case "4":
getComponent('input_step').setValue('4')
break;
case "":
getComponent('input_step').setValue('4')
break;
}}]]></xp:this.action>
<xp:this.script><![CDATA[var files='#{id:Files_from_pers_files_repeat}'
var hidden='#{id:inputText64}'
if (!!document.getElementById(files)){
var filesHtml=document.getElementById(files).innerHTML
if( filesHtml !=="" && filesHtml!=="\n" ){
document.getElementById(hidden).value="file"
}else{
document.getElementById(hidden).value=""
}
}]]></xp:this.script>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
</xp:td>
</xp:tr>
</xp:table>
</xp:td>
<xp:td style="width:15.0%" styleClass="background">
</xp:td>
</xp:tr>
</xp:table>
<xp:div styleClass="navigation_step">
<xp:table style="width:100.0%">
<xp:tr>
<xp:td style="width:15.0%;white-space:nowrap;"
styleClass="background">
<xp:inputHidden id="input_step" defaultValue="1"
value="#{doc_source.InputStep}">
</xp:inputHidden>
<xc:Field2_select_nav_readonly resultid="input_step"
refreshid="div_main" multiselect="false" icon="checkbox-12-icon"
icon_deselected="checkbox-19-icon">
<xc:this.valueslist><![CDATA[#{javascript:var arr = new Array();
arr.push('Purpose|1')
arr.push('Client|2')
arr.push('Conditions|3')
arr.push('Documentation|4')
//arr.push('Signing|5')
return(arr)}]]></xc:this.valueslist>
</xc:Field2_select_nav_readonly>
</xp:td>
<xp:td style="width:85.0%"></xp:td>
</xp:tr>
</xp:table>
</xp:div>
</xp:div>
Here's the fileUploader itself:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.resources>
<xp:script src="/fileUploader.js" clientSide="true">
</xp:script>
</xp:this.resources>
<xp:div id="${javascript:compositeData.ID+'refresh'}">
<xp:messages id="messages1"></xp:messages>
<!-- <xp: message id="message1" for="${javascript:compositeData.ID+'refresh'}"></xp:message> -->
<xp:table>
<xp:this.rendered><![CDATA[#{javascript:currentDocument.isEditable() && (!context.getUserAgent().isIE(6,9))
}]]></xp:this.rendered>
<xp:tr>
<xp:td id="td1" styleClass="doc_field_select">
<xp:text escape="false" id="cf_add">
<xp:this.value><![CDATA[#{javascript:return(texticon('plus-5-icon',25,25,'Add',false))
}]]></xp:this.value>
</xp:text>
<xp:eventHandler event="onclick" submit="false"
disableValidators="true">
<xp:this.script><![CDATA[document.getElementById("#{javascript:compositeData.ID+'_files_input'}").click();]]></xp:this.script>
</xp:eventHandler>
</xp:td>
<xp:td styleClass="doc_field_select" id="td2">
<xp:text escape="false" id="cf_deleteall">
<xp:this.value><![CDATA[#{javascript:return(texticon('x-mark-4-icon',25,25,'Delete all',false))
}]]></xp:this.value>
</xp:text>
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" disableValidators="true">
<xp:this.script><![CDATA[var id='#{javascript:
getClientId(compositeData.ID+"_files_upload")}';
var tst=document.getElementById(id);
tst.value='';]]></xp:this.script>
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
var doc:NotesDocument=doc_source.getDocument(true);
if (doc==null)
{
return(null);
}
if (!doc.hasItem(compositeData.FieldName))
{
return(null);
}
var rit1:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit1==null)
{
return(null);
}
try
{
var arr=rit1.getEmbeddedObjects();
}
catch(e)
{
return(null);
}
for(var i = 0; i < arr.length; i++)
{
doc_source.removeAttachment(compositeData.FieldName, arr[i].getName());
}
return;
var doc:NotesDocument=doc_source.getDocument(true);
var rit:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit==null)
{
return('');
}
var arr=rit.getEmbeddedObjects()
if (arr==null)
{
return('');
}
res=[]
for (var i = 0; i < arr.length; i++)
{
var att:NotesEmbeddedObject=arr[i];
//res.push(att.getName())
arr[i].remove();
}
//doc.save()
doc=doc_source.getDocument(true);
print('has RichText');
print(doc.hasItem(compositeData.FieldName));
return;}]]></xp:this.script>
</xp:executeScript>
<!-- <xp:saveDocument></xp:saveDocument> -->
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
<div style="height:0px;overflow:hidden">
<input type="file"
id="${javascript:compositeData.ID+'_files_input'}"
onchange="#{javascript:
var currentCustomID = compositeData.ID;
var filesInput = '\'' + currentCustomID + '_files_input' + '\'';
var filesUpload = '\'' + currentCustomID + '_files_upload' + '\'';
var filesButton = '\'' + currentCustomID + '_files_button' + '\'';
var filesProgress = '\'' + currentCustomID + '_files_progress' + '\'';
return 'files_onchange(' + filesInput + ',' + filesUpload + ',' + filesButton + ',' + filesProgress + ')';
}"
multiple="true" uploadOnSelect="true" name="uploadedfile"/>
<xp:fileUpload
id="${javascript:compositeData.ID+'_files_upload'}"
useUploadname="true">
<xp:this.value><![CDATA[#{doc_source[compositeData.FieldName]}]]></xp:this.value>
</xp:fileUpload>
<xp:button value="Refresh"
id="${javascript:compositeData.ID+'_files_button'}">
<xp:eventHandler event="onclick"
disableValidators="true"
refreshMode="partial"
refreshId="#{javascript:compositeData.ID+'refresh'}" execMode="partial"
execId="#{javascript:compositeData.ID+'refresh'}" submit="true">
<xp:this.action>
<xp:actionGroup>
<xp:actionGroup>
<xp:saveDocument></xp:saveDocument>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
if (compositeData.postUpload!=null)
{
compositeData.postUpload.getScript().invoke(facesContext, null)
}
}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:actionGroup>
</xp:this.action>
<xp:this.script>
<xp:executeClientScript
script="console.log('The refresh button has just been clicked')">
</xp:executeClientScript>
</xp:this.script>
</xp:eventHandler>
</xp:button>
</div>
<xp:repeat id="${javascript:compositeData.ID+'_files_repeat'}"
rows="30" var="rowData" indexVar="rowIndex">
<xp:this.value><![CDATA[#{javascript:
try
{
var doc:NotesDocument=doc_source.getDocument(true);
}
catch(e)
{
print(e);
var oss=new OsnovaSession();
oss.CreateError("Загрузка файлов", "Некорректное имя файла");
}
if (doc==null)
{
return(null);
}
if (!doc.hasItem(compositeData.FieldName))
{
return(null);
}
var rit1:NotesRichTextItem=doc.getFirstItem(compositeData.FieldName);
if (rit1==null)
{
return(null);
}
try
{
var arr=rit1.getEmbeddedObjects()
}
catch(e)
{
return(null);
}
return(arr)
}]]></xp:this.value>
<xp:table>
<xp:tr>
<xp:td styleClass="doc_field_select" id="td4">
<xp:text escape="false" id="cf_file">
<xp:this.value><![CDATA[#{javascript:
if (rowData==null)
{
return('');
}
var siz=(rowData.getFileSize()/1024).toFixed(1);
siz=siz.replace(/(\d)(?=(\d\d\d)+([^\d]|$))/g, '$1 ');
return(texticon('download-9-icon',compositeData.IconSize,compositeData.IconSize,rowData.getName()+' ('+siz+' KB) ',false));
}]]></xp:this.value>
<xp:this.style><![CDATA[#{javascript:
if(compositeData.IconColor==null)
{
return('')
}
else
{
return('fill:'+compositeData.IconColor+';')
}}]]></xp:this.style>
</xp:text>
<xp:link escape="true" text="Link"
id="link_test" target="_blank" style="display:none">
<xp:this.value><![CDATA[#{javascript:var oss=new OsnovaSession()
try
{
var db:NotesDatabase=session.getDatabase(null,null);
db.openByReplicaID(session.getCurrentDatabase().getServer(),compositeData.ReplicaID);
var doc=db.getDocumentByUNID(compositeData.DocumentUNID);
}
catch(e)
{
var doc=null;
}
if(doc==null)
{
var doc:NotesDocument=doc_source.getDocument();
var db=database;
}
if (doc==null)
{
return(null);
}
//http(s)://[yourserver]/[application.nsf]/[viewname|0]/[UNID| ViewKey]/$File/[AttachmentName]?Open
var res=oss.ServerURL()+'/';
res+=db.getFilePath().replace(/\\/g,'/');
res+='/0/'+doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open';
return(res);
//Old version
var res=oss.ServerURL()+'/'
res+=db.getFilePath().replace(/\\/g,'/')
res+='/xsp/.ibmmodres/domino/OpenAttachment/'
res+=db.getFilePath().replace(/\\/g,'/')+'/'
res+=doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open'
return(res)
}]]></xp:this.value>
</xp:link>
<xp:eventHandler event="onclick" submit="true"
refreshMode="norefresh" disableValidators="true">
<!-- <xp:this.action><![CDATA[#{javascript:/*
var res=oss.ServerURL()+'/'
res+=database.getFilePath().replace(/\\/g,'/')
res+='/xsp/.ibmmodres/domino/OpenAttachment/'
res+=database.getFilePath().replace(/\\/g,'/')+'/'
res+=doc.getUniversalID()+'/$File/'+rowData.getName()+'?Open'
facesContext.getExternalContext().redirect(res)
//view.postScript("window.open('" + res + "'),'_blank'")
*/}]]></xp:this.action> -->
<xp:this.script><![CDATA[
var linkID = '#{javascript:getClientId("link_test")}';
document.getElementById(linkID).click();
/*var refreshButton = '#{javascript:compositeData.ID+'_files_button'}';
console.log('а хули, увы ' + refreshButton);
document.querySelector('[id$=' + refreshButton + ']').click(); */
]]>
</xp:this.script>
</xp:eventHandler>
</xp:td>
<xp:td styleClass="doc_field_select" id="td3">
<xp:text escape="false" id="cf_del">
<xp:this.value><![CDATA[#{javascript:
return(texticon('minus-5-icon',compositeData.IconSize,compositeData.IconSize,'Delete',false));
}]]>
</xp:this.value>
<xp:this.style><![CDATA[#{javascript:
if(compositeData.IconColor==null)
{
return('');
}
else
{
return('fill:'+compositeData.IconColor+';');
}}]]></xp:this.style>
</xp:text>
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" disableValidators="true">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
doc_source.removeAttachment(compositeData.FieldName, rowData.getName())
}]]>
</xp:this.script>
</xp:executeScript>
<xp:save></xp:save>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:
if (compositeData.postDelete!=null)
{
compositeData.postDelete.getScript().invoke(facesContext, null);
}}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
<xp:this.script><![CDATA[XSP.allowSubmit();]]></xp:this.script>
</xp:eventHandler>
</xp:td>
</xp:tr>
</xp:table>
</xp:repeat>
<span id="${javascript:compositeData.ID+'_files_progress'}">
</span>
</xp:div>
</xp:view>
Just take a look at the Refresh button and hidden div besides these elements nothing should be wrong
The code which does the upload is here:
function files_onchange(filesInput, filesUpload, filesButton, filesProgress)
{
var urfiles = document.getElementById(filesInput).files;
files_upload(filesInput, filesUpload, urfiles, 0, filesButton, filesProgress);
}
function files_upload(filesInput, uploadID, files, counter, refreshID, filesProgress)
{
var url = window.location.href;
var formData = new FormData();
var file = null;
var form = XSP.findForm(filesInput);
if (!files) return;
var numberOfFiles = files.length;
file = files[counter];
var max = files.length;
if (counter >= max) return;
formData.append(document.querySelector('[id$=' + uploadID + ']').id, file);
formData.append("$$viewid", dojo.query("input[name='$$viewid']")[0].value);
formData.append("$$xspsubmitid", dojo.query("input[name='$$xspsubmitid']")[0].value);
formData.append("$$xspsubmitvalue", dojo.query("input[name='$$xspsubmitvalue']")[0].value);
formData.append("$$xspsubmitscroll", dojo.query("input[name='$$xspsubmitscroll']")[0].value);
formData.append(form.id, form.id);
console.log(form.id);
var xhr = new XMLHttpRequest();
/* event listners */
xhr.upload.addEventListener("progress", function(e)
{
if (e.lengthComputable)
{
var percentComplete = Math.round(e.loaded * 100 / e.total);
document.getElementById(filesProgress).innerHTML = percentComplete.toString()+'%, ( '+(counter+1).toString()+' / '+numberOfFiles.toString()+' )';
}
else
{
document.getElementById(filesProgress).innerHTML = '...';
}
}, false);
xhr.addEventListener("load", function()
{
counter++;
if (counter >= max)
{
document.getElementById(filesInput).value = "";
if (refreshID)
{
document.querySelector('[id$=' + refreshID + ']').click(); // Here's where the refresh button is triggered. It DOES work. Always
}
}
else
{
files_upload(filesInput, uploadID, files, counter, refreshID, filesProgress)
}
}, false);
xhr.addEventListener("error", function(e)
{
document.getElementById(filesProgress).innerHTML = "Error: "+e;
}, false);
xhr.addEventListener("abort", function()
{
document.getElementById(filesProgress).innerHTML = "Upload cancelled.";
}, false);
xhr.open("POST", url, true);
xhr.send(formData);
document.querySelector('[id$=' + uploadID + ']').value = '';
}
So, when document.querySelector('[id$=' + refreshID + ']').click();
is triggered it refreshes the element only if xp.this.rendered has been true since the beginning of the page. Otherwise, it removes the DOM element which it's supposed to refresh and I have to reload page or click the "Previous step" button in order to see the files which I've just uploaded.
This case is so esoteric, I don't even no what to do and why this happens. Hope you'll help. Thanks in advance.
div_main
. Please take a look – Randadiv_main
is to blame, I'm sure – Randa