gpt4 book ai didi

javascript - XPages execMode 部分在渲染时移除 DOM 元素

转载 作者:数据小太阳 更新时间:2023-10-29 04:51:50 26 4
gpt4 key购买 nike

我的一个 XPage 上有一个 fileUploader。我遇到的问题是当我尝试将它与 一起使用时xp.this.rendered 属性它实际上删除了它应该更新的 DOM 元素。如果没有该属性,它运行得很好,但有时我必须仅在某些条件为真时才显示 fileUploader:

这就是我的意思:enter image description here

我在这里做了什么:

  • 以第 1 步(默认)打开一个页面。它只是主中的一张 table div_main元素( input_step 是 1)
  • 在那里上传文件
  • 点击下一步按钮
  • 刷新了div_main元素和集合 input_step组件值变为 2
  • 显示第二个表(渲染条件为 rendered="#{javascript:getComponent('input_step').getValue()=='2'}" )
  • 我尝试将文件上传到第二个表
  • 然后是触发刷新按钮的代码(我将在下面发布)
  • 它确实将文件上传到服务器,但删除了它应该在
  • 上刷新和执行的 DOM 元素。
  • 然后只是为了实验,我点击了刷新整个 div_main 的“上一步”。
  • 但!而不是刷新 div_main它什么都不做!它只会刷新自己,但不会进入设置 input_step 的代码。回到 1。
  • 当我再次单击“上一步”时,它会返回到第一步,它应该正常工作

  • 我绝对不知道为什么会发生这种情况。真的很烦人
    我一生中从未遇到过如此诡异的问题。

    这是 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>

    这是 fileUploader 本身:
    <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>

    看看 刷新 按钮和隐藏 div 除了这些元素,没有什么应该是错的

    上传的代码在这里:
    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 = '';

    }

    所以,当 document.querySelector('[id$=' + refreshID + ']').click();仅在 时才触发它刷新元素xp.this.rendered 自页面开始以来一直如此。否则,它会删除应该刷新的 DOM 元素,我必须重新加载页面或单击“上一步”按钮才能查看我刚刚上传的文件。

    这个案例太深奥了,我什至不知道该怎么做以及为什么会发生这种情况。希望你会有所帮助。提前致谢。

    最佳答案

    这里有很多附带的东西,SoC 完全缺乏。你有 html 标记散布着用于不同目的的 SSJS,这使得检查代码不必要地繁重(如果 XSP + SSJS 不刺耳,我不知道是什么)。
    我建议退后几步,更深入地了解正在发生的事情以及如何处理事情以减少代码失控(和眼睛)。
    首先,理解为什么 MVC 和 SoC 是重要概念很重要:换句话说,有代码来检索和保存您的后端数据和代码来呈现它。您不想在呈现数据的同一位置操作后端数据。为了实现这样的目标,代码应该被组织成“层”:一层用于与数据库对话,一层用于业务逻辑,一层用于表示。为简洁起见,我不会过多讨论前 2 层 - 我剥离了大部分其他层 - 但我将以更简单的方式组织代码,提供可用于完成该部分的钩子(Hook)。
    托管 Bean
    托管 bean 可以被视为应用程序的助手:如果它们足够通用或“绑定(bind)”到页面以用作特定 Controller ,则它们可以在整个应用程序中使用。在这种情况下,我们将设置一个 bean 作为页面的 Controller 。
    绑定(bind)
    通常,您不应该与组件方法本身对话,而应该更改这些组件绑定(bind)到的属性值。您将看到的是此类规则的应用。
    编码
    faces-config.xml我们这样定义它:

    <managed-bean>
    <managed-bean-name>wam</managed-bean-name>
    <managed-bean-class>demo.bean.WhatAMess
    </managed-bean-class>
    <managed-bean-scope>view</managed-bean-scope>
    </managed-bean>
    wam是用于引用它的友好名称。 demo.bean.WhatAMess是包含包的类的名称。 view定义只要您停留在页面上,bean 就会一直存在。我注意到您的演示文稿被认为是一个向导,您可以在其中来回切换。在 Controller 中,我创建了一个 enum这应该会促进这种方法。我们可以使用 switchFacet,而不是使用数字并评估是否因为您处于给定的编号步骤而显示某些内容。与该枚举配对并易于理解。
    package demo.bean;

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import javax.faces.context.FacesContext;

    import com.ibm.xsp.component.UIFileuploadEx.UploadedFile;
    import com.ibm.xsp.util.FacesUtil;

    public class WhatAMess implements Serializable {

    public enum Step {
    // The string param is a dead-simple to handle labels for the various phases
    // It could be handled differently, especially if your app is multi-language
    PURPOSE, CLIENT, CONDITIONS, DOCUMENTATION("Docs"), SIGNING;

    private final String label;

    private Step() {
    this(null);
    }

    private Step(String label) {
    this.label = label;
    }

    public String getLabel() {
    return label != null ? label : name();
    }

    // This method returns the step next to the current one
    // in the order the enums are actually declared above
    public Step getNext() {
    return (ordinal() < values().length - 1) ? values()[ordinal() + 1] : this;
    }

    // This method returns the step previous to the current one
    // in the order the enums are actually declared above
    public Step getPrevious() {
    return (ordinal() > 0) ? values()[ordinal() - 1] : this;
    }

    // This method says whether there's a step previous to the current one
    public boolean isGoingBackward() {
    return getPrevious() != this;
    }


    // This method says whether there's a step next to the current one
    public boolean isGoingForward() {
    return getNext() != this;
    }

    }

    private static final long serialVersionUID = 1L;

    // Let's step the initial first step
    private Step step = Step.values()[0];

    // This is a variable used as a proof of concept instead of your business logic
    private Map<Step, List<String>> stepFileNames;

    public Step getStep() {
    return step;
    }

    public Map<Step, List<String>> getStepFileNames() {
    if (stepFileNames == null) {
    stepFileNames = new HashMap<Step, List<String>>();
    }

    return stepFileNames;
    }

    public void removeStepFileName(String name) {
    getStepFileNames().get(step).remove(name);
    }

    // This action commands the wizard and moves it to the previous step
    public void stepBack() {
    step = step.getPrevious();
    }

    // This action commands the wizard and moves it to the next step
    public void stepForward() {
    step = step.getNext();
    }

    // This method is your entry point to deal with the uploaded file
    public void uploadFile() {
    // uploadedFile is an arbitrary variable we assigned
    // to the fileUpload control on the page
    UploadedFile uploadedFile = (UploadedFile) FacesUtil.resolveVariable(
    FacesContext.getCurrentInstance(), "uploadedFile");

    if (uploadedFile == null) {
    return;
    }

    // Here you are supposed to do something
    // more interesting than what I am doing here

    List<String> fileNames = getStepFileNames().get(step);

    if (fileNames == null) {
    fileNames = new ArrayList<String>();

    getStepFileNames().put(step, fileNames);
    }

    fileNames.add(uploadedFile.getFilename());
    }

    }
    然后我们将这个类的方法绑定(bind)到页面上的各种组件属性:
    <xp:div id="containerSteps"
    style="width: 500px; background-color: #F0F0F0; padding: 20px">
    <xp:text tagName="h1" value="#{wam.step.label}" style="margin-bottom: 20px" />

    <xe:switchFacet selectedFacet="#{javascript:wam.step.name()}">
    <xp:this.facets>
    <xp:div xp:key="PURPOSE">
    <xc:whatamessupload />
    </xp:div>

    <xp:div xp:key="CLIENT">
    <xc:whatamessupload />
    </xp:div>

    <xp:div xp:key="CONDITIONS">
    <xc:whatamessupload />
    </xp:div>

    <xc:whatamessupload xp:key="DOCUMENTATION" />

    <xp:div xp:key="SIGNING">
    <xc:whatamessupload />
    </xp:div>
    </xp:this.facets>
    </xe:switchFacet>

    <hr />

    <xp:link id="linkStepNext" text="Go to Next" rendered="#{wam.step.goingForward}"
    style="float: right">
    <xp:eventHandler event="onclick" submit="true"
    execMode="partial" execId="containerSteps" refreshMode="partial"
    refreshId="containerSteps" action="#{wam.stepForward}" />
    </xp:link>

    <xp:link id="linkStepBack" text="Go to Previous" rendered="#{wam.step.goingBackward}">
    <xp:eventHandler event="onclick" submit="true"
    execMode="partial" execId="containerSteps" refreshMode="partial"
    refreshId="containerSteps" action="#{wam.stepBack}" />
    </xp:link>

    <br />
    </xp:div>
    xe:switchFacet将确保只显示当前步骤的容器。 xp:key可以分配给任何 XPage 组件的属性采用枚举名称本身的值 ( #{javascript:wam.step.name()} )。在这一点上,您可以更好地组织您的代码,而无需一次又一次地评估同一件事。
    现在, <xc:whatamessupload />是一个自定义控件,我在其中移植了您的上传逻辑,我认为您将竭尽全力使其对用户更有趣,正常 onchange fileUpload 控件上的操作将产生相同的结果,同时简化相同的过程。无论如何,我理解一种更用户友好的方法。话虽如此,自定义控件目前没有任何特定属性,我只是想让事情变得简单和简短。
    <xp:this.resources>
    <xp:script src="js/uploader.js" clientSide="true" />
    </xp:this.resources>

    <xp:div id="containerUpload">
    <xp:fileUpload id="fileUpload" value="#{requestScope.uploadedFile}"
    style="display: none"
    onchange="file_onchange(this, '#{id:eventOnFileUpload}', '#{id:uploadButton}', '#{id:containerFiles}')">
    <xp:eventHandler id="eventOnFileUpload" event="onfileupload"
    submit="true" execMode="partial" refreshMode="norefresh" action="#{wam.uploadFile}" />
    </xp:fileUpload>

    <xp:button id="uploadButton" type="button" onclick="dojo.byId('#{id:fileUpload}').click()"
    value="Add" />

    <xp:div id="containerFiles">
    <ul>
    <xp:repeat value="#{wam.stepFileNames[wam.step]}" var="fileName"
    disableOutputTag="true">
    <li>
    <xp:text value="#{fileName}" />
    <xp:text value="&#160;-&#160;" />
    <xp:link id="linkRemoveFileName" text="Remove">
    <xp:eventHandler event="onclick" submit="true"
    execMode="partial" refreshMode="partial" refreshId="containerUpload"
    action="#{javascript:wam.removeStepFileName(fileName)}" />
    </xp:link>
    </li>
    </xp:repeat>
    </ul>
    </xp:div>
    </xp:div>
    上面这段代码假设 wam已经存在,但可以重构以确保 wam 作为 compositeData 传递属性,从而提高代码的可重用性。
    最后上传器js函数:
    function update_button_label(buttonId, text, enable) {
    var button = dojo.byId(buttonId);

    button.innerText = text;

    if (enable) {
    button.disabled = !enable;
    }
    }

    function file_onchange(inputFile, actionId, buttonId, refreshId) {
    if (!inputFile || !actionId || !buttonId || !refreshId) {
    return;
    }

    var button = dojo.byId(buttonId);
    var buttonOriginalLabel = button.innerText;

    // Request
    var xhr = new XMLHttpRequest();

    // Event listeners
    xhr.upload.addEventListener("abort", function() {
    update_button_label(buttonId, "Upload cancelled.");

    setTimeout(update_button_label.bind(this, buttonId, buttonOriginalLabel, true), 1000);
    }, false);

    xhr.upload.addEventListener("error", function(e) {
    update_button_label(buttonId, "An error occurred. See console log!");

    console.log(e);

    setTimeout(update_button_label.bind(this, buttonId, buttonOriginalLabel, true), 1000);
    }, false);

    xhr.upload.addEventListener("progress", function(e) {
    if (!e.lengthComputable) {
    return;
    }

    update_button_label(buttonId, buttonOriginalLabel + ": "
    + Math.round(e.loaded * 100 / e.total) + "%");
    }, false);

    xhr.onreadystatechange = function(res) {
    if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
    update_button_label(buttonId, buttonOriginalLabel, true);

    if (refreshId) {
    XSP.partialRefreshGet(refreshId);
    }

    /*
    * Here something else could be done with the same request if only
    * one is willing to process xhr.response. In it there's the new HTML to replace
    * plus scripts to be processed. The above lazy approach requires another request
    * instead of be done with the one at hand.
    *
    * If you want to explore more you should replace "?$$ajaxid=" + "none" with
    * "?$$ajaxid=" + refreshId
    *
    * The below code is copied from the XSP object but it's not complete
    */
    // var _23a = xhr.response;
    //
    // var extractScripts = function xrn_e(_23e, _23f) {
    // var _240 = _23a.indexOf(_23e);
    //
    // if (_240 >= 0) {
    // var _241 = _23a.lastIndexOf(_23f);
    // if (_241 >= 0) {
    // var _242 = _23a.substring(_240 + _23e.length, _241);
    // _23a = _23a.substring(0, _240) + _23a.substring(_241 + _23f.length);
    // return _242;
    // }
    // }
    // };
    //
    // var _246 = extractScripts(
    // "<!-- XSP_UPDATE_SCRIPT_START -->", "<!-- XSP_UPDATE_SCRIPT_END -->\n");
    //
    // var refreshElement = document.getElementById(refreshId);
    //
    // refreshElement.innerHTML = _23a;
    }
    }

    xhr.open("POST", location.origin + location.pathname
    + "?$$ajaxid=" + "none", true);

    // Payload
    var form = XSP.findForm(inputFile.id);
    var formData = new FormData();

    formData.append(inputFile.id, inputFile.files[0]);

    formData.append("$$viewid", dojo.query("input[name='$$viewid']")[0].value);
    formData.append("$$xspsubmitid", actionId);
    formData.append("$$xspexecid", inputFile.id);
    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);

    button.disabled = true;

    xhr.send(formData);

    inputFile.value = '';
    }
    您在编写稍后要使用的 id 时所做的使用是不必要的,并且更容易出错。没有什么是当前框架和语法无法处理的,而且是绝对可重复的(页面上可以有多个自定义控件)。您也不需要 input type="file"和上传控件。你可以用后者处理一切。在 xp:fileUpload control值绑定(bind)到 #{requestScope.uploadedFile}这是我在 Controller 方法上解决的问题 uploadFile方法。如您所见,我利用了 xp:eventHandler组件来绑定(bind)将在服务器端执行的特定操作。还有很多要讨论的,但你很可能很快就会放弃我的答案,因此没有必要写更多,否则你需要一些时间来消化所有内容并提出最终的问题。到那个时候我就写这么多了。

    关于javascript - XPages execMode 部分在渲染时移除 DOM 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53186692/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com