I have a quiz form, which lets to create different psychological tests. Now it hardcoded to 50 questions. I need some questions to have embedded images, that's why I use RichText. When I bind it dynamically, with value="#{document1[viewScope.FieldName]}" it works fine with custom text formatting, but don't let me import an image into richtext. Binding with value="${document1[viewScope.FieldName]}" lets, but I can't dynamically change fields.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex"
xmlns:xc="http://www.ibm.com/xsp/custom">
<xp:this.data>
<xp:dominoDocument var="document1" formName="test">
</xp:dominoDocument>
</xp:this.data>
<xp:this.beforePageLoad><![CDATA[#{javascript:if (!viewScope.qNum || viewScope.qNum == 0) {
viewScope.qNum = 1;
}
viewScope.qFNCount = 'Q'+viewScope.qNum + 'Count';
viewScope.qFNCorrect = 'Q'+viewScope.qNum + 'Correct';
viewScope.qFNTitle = 'Q'+viewScope.qNum + 'Title';
viewScope.qFNA1 = 'Q'+viewScope.qNum + 'A1';
viewScope.qFNA2 = 'Q'+viewScope.qNum + 'A2';
viewScope.qFNA3 = 'Q'+viewScope.qNum + 'A3';
viewScope.qFNA4 = 'Q'+viewScope.qNum + 'A4';
viewScope.qFNA5 = 'Q'+viewScope.qNum + 'A5';}]]></xp:this.beforePageLoad>
<xp:this.beforeRenderResponse><![CDATA[#{javascript:
viewScope.qFNCount = 'Q'+viewScope.qNum + 'Count';
viewScope.qFNCorrect = 'Q'+viewScope.qNum + 'Correct';
viewScope.qFNTitle = 'Q'+viewScope.qNum + 'Title';
viewScope.qFNA1 = 'Q'+viewScope.qNum + 'A1';
viewScope.qFNA2 = 'Q'+viewScope.qNum + 'A2';
viewScope.qFNA3 = 'Q'+viewScope.qNum + 'A3';
viewScope.qFNA4 = 'Q'+viewScope.qNum + 'A4';
viewScope.qFNA5 = 'Q'+viewScope.qNum + 'A5';}]]></xp:this.beforeRenderResponse>
<xp:scriptBlock id="scriptBlock2">
<xp:this.value>
<![CDATA[
CKEDITOR.config.removeButtons = 'TextColor,BGColor,Find,Font,Underline,Subscript,Superscript,Scayt,Anchor,Table,HorizontalRule,SpecialChar,Maximize,Strike,NumberedList,BulletedList,Indent,Outdent,Blockquote,Styles,Format,About';
]]>
</xp:this.value>
</xp:scriptBlock>
<xp:this.resources>
<xp:styleSheet href="/application.css"></xp:styleSheet>
<xp:script src="/core.ssjs.jss" clientSide="false"></xp:script>
<xp:script src="/client.js" clientSide="true"></xp:script>
<xp:script src="/form.js" clientSide="true"></xp:script>
</xp:this.resources>
<xp:panel styleClass="container form-horizontal" id="container">
<xe:djHorizontalSlider id="djHorizontalSlider1"
value="#{viewScope.qNum}" clickSelect="true" maximum="50" minimum="1"
pageIncrement="1" showButtons="true" required="true"
style="overflow:hidden" readOnly="false" discreteValues="50"
lang="ru" slideDuration="50">
<xe:this.converter>
<xp:convertNumber integerOnly="true"></xp:convertNumber>
</xe:this.converter>
<xe:djSliderRuleLabels
style="height:14px;font-size:75%;color:gray" count="50"
container="bottomDecoration" id="djSliderRuleLabels1" maximum="50"
minimum="1" labels="#{javascript:rangeStr(1,51)}">
</xe:djSliderRuleLabels>
<xp:eventHandler event="onChange" submit="true"
refreshMode="complete">
<xe:this.action><![CDATA[#{javascript:viewScope.qFNTitle = 'Q'+viewScope.qNum + 'Title';
viewScope.qFNCount = 'Q'+viewScope.qNum + 'Count';
viewScope.qFNCorrect = 'Q'+viewScope.qNum + 'Correct';
viewScope.qFNA1 = 'Q'+viewScope.qNum + 'A1';
viewScope.qFNA2 = 'Q'+viewScope.qNum + 'A2';
viewScope.qFNA3 = 'Q'+viewScope.qNum + 'A3';
viewScope.qFNA4 = 'Q'+viewScope.qNum + 'A4';
viewScope.qFNA5 = 'Q'+viewScope.qNum + 'A5';}]]></xe:this.action>
</xp:eventHandler>
</xe:djHorizontalSlider>
<xp:panel styleClass="panel panel-default" id="quests">
<xp:panel styleClass="panel-body">
<xc:ccSectionPanel panel_id="ccSection"
initClosed="false" panel_class="panel-default" footer="false"
disable_collapse="true"
titleBarText="#{javascript:'Вопрос номер ' + viewScope.qNum;}"
custom_title="true">
<xp:this.facets>
<xp:panel xp:key="customTitle">
<xp:text escape="true" id="computedField1"
value="#{javascript:'Вопрос номер ' + viewScope.qNum;}"
styleClass="panel-title">
</xp:text>
<xp:button value="Редактировать" id="button2"
rendered="#{javascript:document1.isEditable()==#False()}"
styleClass="pull-right"
style="margin-top:-7px;margin-right:-12px;">
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:changeDocumentMode
mode="edit" var="document1">
</xp:changeDocumentMode>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:viewScope.put("editmode", true)}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button value="Сохранить" id="button1"
rendered="#{javascript:document1.isEditable()}"
styleClass="pull-right"
style="margin-top:-7px;margin-right:-12px;">
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:actionGroup>
<xp:saveDocument
var="document1">
</xp:saveDocument>
<xp:changeDocumentMode
mode="readOnly" var="document1">
</xp:changeDocumentMode>
</xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:viewScope.put("editmode", false)}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:panel>
<xp:panel xp:key="panelBody">
<xc:ссFormGroup fg_id="fgTitle"
editmode="true" label_target="inputRichTextTitle">
<xc:this.label_text><![CDATA[#{javascript:'Заголовок вопроса [' + viewScope.qFNTitle + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextTitle" xp:key="fieldFacet"
value="#{document1[viewScope.qFNTitle]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgCountAnswers"
editmode="true" label_target="radioGroup1">
<xc:this.label_text><![CDATA[#{javascript:'Количество вариантов ответа [' + viewScope.qFNCount + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:radioGroup id="radioGroup1"
xp:key="fieldFacet" defaultValue="4"
value="#{document1[viewScope.qFNCount]}">
<xp:selectItem itemLabel="1"></xp:selectItem>
<xp:selectItem itemLabel="2"></xp:selectItem>
<xp:selectItem itemLabel="3"></xp:selectItem>
<xp:selectItem itemLabel="4"></xp:selectItem>
<xp:selectItem itemLabel="5"></xp:selectItem>
<xp:eventHandler
event="onchange" submit="true" refreshMode="partial"
refreshId="container">
</xp:eventHandler>
</xp:radioGroup>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgA1" editmode="true"
label_target="inputRichTextA1">
<xc:this.label_text><![CDATA[#{javascript:'Ответ 1 [' + viewScope.qFNA1 + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextA1" xp:key="fieldFacet"
value="#{document1[viewScope.qFNA1]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgA2" editmode="true"
label_target="inputRichTextA2">
<xc:this.rendered><![CDATA[#{javascript:count = document1.getItemValueString(viewScope.qFNCount);
if (!count || count == '') {count = 4}
count > 1}]]></xc:this.rendered>
<xc:this.label_text><![CDATA[#{javascript:'Ответ 2 [' + viewScope.qFNA2 + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextA2" xp:key="fieldFacet"
value="#{document1[viewScope.qFNA2]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgA3" editmode="true"
label_target="inputRichTextA3">
<xc:this.rendered><![CDATA[#{javascript:count = document1.getItemValueString(viewScope.qFNCount);
if (!count || count == '') {count = 4}
count > 2}]]></xc:this.rendered>
<xc:this.label_text><![CDATA[#{javascript:'Ответ 3 [' + viewScope.qFNA3 + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextA3" xp:key="fieldFacet"
value="#{document1[viewScope.qFNA3]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgA4" editmode="true"
label_target="inputRichTextA4">
<xc:this.rendered><![CDATA[#{javascript:count = document1.getItemValueString(viewScope.qFNCount);
if (!count || count == '') {count = 4}
count > 3}]]></xc:this.rendered>
<xc:this.label_text><![CDATA[#{javascript:'Ответ 4 [' + viewScope.qFNA4 + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextA4" xp:key="fieldFacet"
value="#{document1[viewScope.qFNA4]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fgA5" editmode="true"
label_target="inputRichTextA5">
<xc:this.rendered><![CDATA[#{javascript:count = document1.getItemValueString(viewScope.qFNCount);
if (!count || count == '') {count = 4}
count > 4}]]></xc:this.rendered>
<xc:this.label_text><![CDATA[#{javascript:'Ответ 5 [' + viewScope.qFNA5 + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:inputRichText
id="inputRichTextA5" xp:key="fieldFacet"
value="#{document1[viewScope.qFNA5]}">
</xp:inputRichText>
</xp:this.facets>
</xc:ссFormGroup>
<xc:ссFormGroup fg_id="fg1" editmode="true"
label_target="radioGroupCorrect">
<xc:this.label_text><![CDATA[#{javascript:'Верный ответ [' + viewScope.qFNCorrect + ']'}]]></xc:this.label_text>
<xp:this.facets>
<xp:radioGroup
id="radioGroupCorrect" xp:key="fieldFacet"
value="#{document1[viewScope.qFNCorrect]}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var count = document1.getItemValueString(viewScope.qFNCount);
if (!count || count == '') {count = 4}
count++;
rangeStr(1,count)}]]></xp:this.value>
</xp:selectItems>
</xp:radioGroup>
</xp:this.facets>
</xc:ссFormGroup>
</xp:panel>
</xp:this.facets>
</xc:ccSectionPanel>
</xp:panel>
</xp:panel>
</xp:panel></xp:view>
The simplest and most brutal solution is to create 50*7 static fields with dynamic render state. Is there any other way?
An alternative and probably better approach then is to create questions in separate documents. Then you don't have to dynamically bind to a field. It's one I've used on at least two similar occasions.
The driver for using fields in one document is often habit. Traditional Domino web or Notes Client typically required everything to be in the same document. XPages doesn't. Break the habit and you remove the problem.
One change that will be required is to create and save the quiz before adding questions. There are a variety of reasons why this is actually a better approach, for a web app and a quiz with a number of questions.
Related
I have following custom control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.beforePageLoad><![CDATA[#{javascript:compositeData.id = this.getId();
if (!compositeData.body_class) {compositeData.body_class='panel-body'};
if (!compositeData.panel_id) {compositeData.panel_id='section'+compositeData.id};}]]></xp:this.beforePageLoad>
<xp:panel>
<xp:this.styleClass><![CDATA[#{javascript:"ccSectionPanel panel " + compositeData.panel_class + ""}]]></xp:this.styleClass>
<xp:this.attrs>
<xp:attr name="id">
<xp:this.value><![CDATA[#{javascript:compositeData.panel_id}]]></xp:this.value>
</xp:attr>
</xp:this.attrs>
<xp:panel styleClass="panel-heading" style="cursor:pointer;">
<xp:this.attrs>
<xp:attr name="id">
<xp:this.value><![CDATA[#{javascript:compositeData.panel_id + "_heading"}]]></xp:this.value>
</xp:attr>
<xp:attr name="href">
<xp:this.value><![CDATA[#{javascript:"#" + compositeData.panel_id + "_section"}]]></xp:this.value>
</xp:attr>
<xp:attr name="data-toggle" value="collapse"></xp:attr>
</xp:this.attrs>
<xp:link escape="true" styleClass="panel-title"
text="#{javascript:compositeData.titleBarText}">
<xp:this.attrs>
<xp:attr name="id">
<xp:this.value><![CDATA[#{javascript:compositeData.panel_id + "_title"}]]></xp:this.value>
</xp:attr>
</xp:this.attrs>
<xp:this.id><![CDATA[${javascript:compositeData.panel_id + "_title"}]]></xp:this.id>
</xp:link>
</xp:panel>
<xp:panel>
<xp:this.styleClass><![CDATA[#{javascript:"panel-collapse collapse" + (compositeData.initClosed ? "" : " in")}]]></xp:this.styleClass>
<xp:this.attrs>
<xp:attr name="id">
<xp:this.value><![CDATA[#{javascript:compositeData.panel_id + "_section"}]]></xp:this.value>
</xp:attr>
</xp:this.attrs>
<xp:panel
styleClass="#{javascript:compositeData.body_class}">
<xp:callback facetName="panelBody" id="panelBody"></xp:callback>
</xp:panel>
<xp:panel rendered="#{javascript:compositeData.footer}"
styleClass="panel-footer">
<xp:callback facetName="panelFooter" id="panelFooter"></xp:callback>
</xp:panel>
</xp:panel>
</xp:panel>
</xp:view>
I use it in a repeat control:
<xp:repeat id="repeat1" rows="30" value="#{view1}"
var="repEntry" indexVar="index" repeatControls="false">
<xp:panel>
<xp:this.data>
<xp:dominoDocument var="doc"
action="openDocument"
documentId="#{javascript:repEntry.getNoteID()}"
ignoreRequestParams="true">
</xp:dominoDocument>
</xp:this.data>
<xc:ccSectionPanel initClosed="false"
panel_class="#{javascript:repEntry.getColumnValue('class')}"
footer="#{javascript:sessionScope.isAdmin}"
rendered="#{javascript:repEntry.getColumnValue('Status') == '1' || sessionScope.isAdmin}">
<xc:this.titleBarText><![CDATA[#{javascript:repEntry.getColumnValue('Title') + (repEntry.getColumnValue('Status') != '1' ? ' (скрыто)' : '')
}]]></xc:this.titleBarText>
<xp:this.facets>
<xp:panel xp:key="panelFooter">
<xp:button value="Редактировать"
id="button2" styleClass="btn btn-xs">
<i
class="glyphicon glyphicon-pencil">
</i>
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete">
<xp:this.action>
<xp:openPage
name="/index.xsp" target="editDocument"
documentId="#{javascript:repEntry.getNoteID()}">
</xp:openPage>
</xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:button
value="#{javascript:repEntry.getColumnValue('Status') != '1' ? 'Показать' : 'Скрыть'}"
id="button3" styleClass="#{javascript:'btn btn-xs'}">
<i
class="#{javascript:repEntry.getColumnValue('Status') != '1' ? 'glyphicon glyphicon-eye-open' : 'glyphicon glyphicon-eye-close'}">
</i>
<xp:eventHandler event="onclick"
submit="true" refreshMode="partial" disableValidators="true"
refreshId="content">
<xp:this.action><![CDATA[#{javascript:if (repEntry.getColumnValue('Status') == '1') {
doc.replaceItemValue('Status','0');
doc.replaceItemValue('Author',sessionScope.User.UserName);
doc.save();
} else {
doc.replaceItemValue('Status','1');
doc.replaceItemValue('Author',sessionScope.User.UserName);
doc.save();
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:text escape="false"
id="computedField2" styleClass="btn btn-xs">
<xp:this.value><![CDATA[#{javascript:'<i class="glyphicon glyphicon-user"></i>' + repEntry.getColumnValue('Author') + ' <i class="glyphicon glyphicon-time"></i>' + repEntry.getColumnValue('$1')
}]]></xp:this.value>
</xp:text>
</xp:panel>
<xp:panel xp:key="panelBody">
<!-- <xp:this.data>
<xp:dominoDocument var="doc" action="openDocument"
documentId="#{javascript:repEntry.getNoteID()}"
ignoreRequestParams="true">
</xp:dominoDocument>
</xp:this.data> -->
<xp:inputRichText
id="inputRichText2" value="#{doc.Body}" readonly="true"
rendered="false">
</xp:inputRichText>
<xp:text escape="false"
id="computedField1">
<xp:this.value><![CDATA[#{javascript:doc.getDocument().getFirstItem("Body").getMIMEEntity().getContentAsText(); }]]></xp:this.value>
</xp:text>
</xp:panel>
</xp:this.facets>
</xc:ccSectionPanel>
</xp:panel>
</xp:repeat>
When i set cumputed properties,
It works, but when i set panel_id to something relative to repEntry or doc, it throws error (repEntry is undefined). I can set "Create controls at page creation", but then I lose advantages of partial refresh.
The main question, why one costom property can work with repEntry, but other can't?
The answer comes down to when the property gets calculated. Compute it and add a print statement in the SSJS code and you'll see. IDs need to be calculated when the components get loaded, so at the earliest part of the processing. And most importantly this is when it's generating a single abstract set of components, not associated to a particular row entry, because it's not yet built the collection. Think of it like creating an abstract class before creating objects from it.
My Xpage is in read mode. There is a Notes field with a "Add Notes" button. Click the button, user adds notes in dialogbox and clicks "Add Notes". The button does the work of adding the notes and saving the document.
I want to update the underlying notes field so the user will see their additions. How can I accomplish this?
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:panel id="pnlAll">
<xp:this.data>
<xe:objectData saveObject="#{javascript:PCModel.save()}"
var="PCModel">
<xe:this.createObject><![CDATA[#{javascript:var pc = new com.scoular.model.PC();
var unid = sessionScope.get("key");
if (unid != null) {
pc.loadByUnid(unid);
sessionScope.put("key","");
viewScope.put("readOnly","Yes");
} else {
pc.create();
viewScope.put("readOnly","No");
}
viewScope.status = pc.status;
return pc;}]]></xe:this.createObject>
</xe:objectData>
</xp:this.data>
<xp:inputTextarea id="inputTextarea3" cols="1" rows="10"
disabled="true" value="#{PCModel.notes}">
</xp:inputTextarea>
<xp:br></xp:br>
<xp:button value="Add Notes" id="button1">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:getComponent("dialogAddNotes").show()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xp:div styleClass="modal fade" id="model1" role="dialog">
<xe:dialog id="dialogAddNotes" styleClass="modal-dialog"
title="Add Notes">
<xp:div style="margin-left:10.0px;margin-right:10.0px">
<xp:inputTextarea id="inputTextarea4" value="#{viewScope.addNotes}"
cols="1" rows="18">
</xp:inputTextarea>
</xp:div>
<xp:div styleClass="modal-footer">
<xp:button type="button" styleClass="btn btn-primary" id="button17"
value="Add Notes">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="dialogAddNotes">
<xp:this.action><![CDATA[#{javascript:var newLne = "\n";
var oldNte = PCModel.notes;
var usrNme:String = userBean.displayName;
var dte = session.createDateTime(#Now());
var lnkStr:String = "Notes added by " + usrNme + " at " + dte + newLne + newLne + viewScope.addNotes + newLne + newLne + oldNte;
var newNotes:String = lnkStr
PCModel.notes = newNotes;
PCModel.save();}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
</xp:div>
</xe:dialog>
</xp:div>
</xp:panel>
</xp:view>
You need to partially refresh the updated text area field called inputTextarea3 instead of the dialog.
I have an value picker in a dialog box. The user selects a value and that value is entered into an Edit Box, which is bound to a scope variable. So far so good.
I then have a button where I want to ask the access the value that is in the edit box.
I have tried using
var satLoc:String = viewScope.get("selLoc");
var satLoc:String = getComponent("selLoc").getValue();
neither of which works - I just get null.
My code is below. I would appreciate some help.
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core"
xmlns:xe="http://www.ibm.com/xsp/coreex">
<xp:button id="button15" style="font-weight:bold;font-size:8pt" value="Load Satellite Dialog">
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="dialogAddSat">
<xp:this.action><![CDATA[#{javascript:var d = getComponent('dialogAddSat')d.show()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
<xp:br></xp:br>
<xe:dialog id="dialogAddSat" style="width:300px">
<xe:this.title><![CDATA[#{javascript:"Make This Location A Hub"}]]></xe:this.title>
<xe:dialogButtonBar>
<xp:table id="tblCrd" style="width:99.0%">
<xp:tr>
<xp:td>
<xp:label id="label24" for="region" value="Hub Location Number" />
</xp:td>
<xp:td>
<xe:djTextBox id="djTextBox2"
style="width:35px;text-align:right">
<xe:this.dojoAttributes>
<xp:dojoAttribute name="readOnly"
value="true">
</xp:dojoAttribute>
</xe:this.dojoAttributes>
<xe:this.value><![CDATA[#{javascript:"0002"}]]></xe:this.value><xp:eventHandler event="onChange"
submit="true" refreshMode="partial" refreshId="tblCrd">
</xp:eventHandler>
</xe:djTextBox>
</xp:td>
<xp:td style="text-align:right">
<xp:button id="button13" value="Attach Satellite">
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete" id="eventHandler7"
disableValidators="true">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialogMakeHub}');]]></xp:this.script>
<xp:this.action>
<xp:actionGroup>
<xp:confirm>
<xp:this.message><![CDATA[#{javascript:try {
var satLoc:String = viewScope.get("selLoc");
//var satLoc:String = getComponent("selLoc").getValue();
var hubLoc = "0002";
//var hubLoc:String = document1.getDocument().getItemValueString("locNum");
return "Make Location " + satLoc + " a Satellite for Location Number " + hubLoc
} catch(e){
return e;
}
}]]></xp:this.message>
</xp:confirm>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:print ("Here")}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button></xp:td>
</xp:tr>
<xp:tr>
<xp:td>
<xp:label id="label25" for="region" value="Select Location..." />
</xp:td><xp:td>
<xp:inputText id="selLoc" value="#{viewScope.selLoc}"></xp:inputText>
<xe:valuePicker id="valuePicker77"
dialogTitle="Choose A Location To Add As A Satellite"
pickerIcon="/picker.png" for="selLoc">
<xe:this.dataProvider>
<xe:simpleValuePicker>
<xe:this.valueList><![CDATA[#{javascript:import xpUtilities
var tmpLocView:NotesView = database.getView("(DbLocsOperActiveLOnly)");
var arr = new Array();
var tmpLocNum:String;
var hubLocNum:String;
//hubLocNum = padToFour(document1.getDocument().getItemValueString("locNum"));
hubLocNum = "0002;"
//arr[0] = hublocNum
var tmpLocDoc:NotesDocument = tmpLocView.getFirstDocument();
while (tmpLocDoc != null) {
tmpLocNum = tmpLocDoc.getItemValueString("locNum");
if (tmpLocNum != hubLocNum)
{arr.push(tmpLocDoc.getItemValueString("locNum"));}
var tmpdoc = tmpLocView.getNextDocument(tmpLocDoc);
tmpLocDoc.recycle();
tmpLocDoc = tmpdoc;
}
return arr
}]]></xe:this.valueList>
</xe:simpleValuePicker>
</xe:this.dataProvider>
</xe:valuePicker></xp:td>
<xp:td style="text-align:right">
<xp:button value="Cancel" id="button10">
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete" id="eventHandler4">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialogAddSat}')]]></xp:this.script>
</xp:eventHandler>
</xp:button></xp:td>
</xp:tr>
<xp:tr>
<xp:td>
</xp:td>
<xp:td>
</xp:td>
<xp:td style="text-align:right">
</xp:td>
</xp:tr>
</xp:table>
</xe:dialogButtonBar>
</xe:dialog>
</xp:view>
I have found a solution. I had an action group with a Confirmation Action. I was trying to get the value in the confirmation action. For some reason, it doesn't work there. I just ignore it in the confirmation action and now it work.
The problem is about the timing. On the following code, you compute a confirmation text. But this is being computed at the server side, when it's being rendered. At the time of rendering, the viewScope variable is empty.
<xp:button
id="button13"
value="Attach Satellite">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
id="eventHandler7"
disableValidators="true">
<xp:this.script><![CDATA[XSP.closeDialog('#{id:dialogMakeHub}');]]></xp:this.script>
<xp:this.action>
<xp:actionGroup>
<xp:confirm>
<xp:this.message><![CDATA[#{javascript:try {
var satLoc:String = viewScope.get("selLoc");
//var satLoc:String = getComponent("selLoc").getValue();
var hubLoc = "0002";
//var hubLoc:String = document1.getDocument().getItemValueString("locNum");
return "Make Location " + satLoc + " a Satellite for Location Number " + hubLoc
} catch(e){
return e;
}}]]>
</xp:this.message>
</xp:confirm>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:print ("Here")}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
</xp:eventHandler>
</xp:button>
If you refresh the button component when the input value changes, it will show the correct value. However, I'd prefer computing the value of the confirmation on the client side, in the script attribute. Closing dialog should be the final action (if the user does not confirm the value, it shouldn't be closed. Here is the modified version.
<xp:button
id="button13"
value="Attach Satellite">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
id="eventHandler7"
onComplete="XSP.closeDialog('#{id:dialogAddSat}');"
disableValidators="true">
<xp:this.action>
<xp:actionGroup>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:print ("Here")}]]></xp:this.script>
</xp:executeScript>
</xp:actionGroup>
</xp:this.action>
<xp:this.script><![CDATA[return confirm("Location will be set "+dojo.byId('#{id:selLoc}').value+". Confirm?")]]></xp:this.script>
</xp:eventHandler>
</xp:button>
I have a page bound to a doc data source. At the top of the page is a panel where the fields for the doc is set. In the bottom of the page is a view of the docs.
Let's say the fields are [A] and [B], and [B]'s value depends on [A], which partial refreshes [B] on some value change. When I just set [A] that doesn't trigger the partial refresh then press submit/save, the doc is saved and the page updates fully and the doc appears in the view below.
BUT if I set [A] such that [B] refreshes then press submit/save, the doc is saved BUT the doc doesn't appear in the view. I need to reload the page by pressing ENTER in the URL bar to update the view. Tried to do a research on this but to no avail.
What do you think I can do to update the view on the last scenario?
Here is the simplified code:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" xmlns:xc="http://www.ibm.com/xsp/custom"
style="font-size:11pt;font-weight:bold">
<xp:this.beforePageLoad>
<![CDATA[#{javascript:var currLocation=context.getUrl();
var webDBPath=#LeftBack(currLocation,"/");
sessionScope.jQuery=webDBPath+"/jquery.min.js";
sessionScope.jQueryUI=webDBPath+"/jquery-ui.min.js";
sessionScope.jQueryBlockUI=webDBPath+"/jquery.blockUI.js"}]]>
</xp:this.beforePageLoad>
<xp:this.data>
<xp:dominoDocument var="attachmentDoc" formName="Attachment"></xp:dominoDocument>
</xp:this.data>
<xp:this.resources>
<xp:script src="#{javascript:sessionScope.jQuery}"
clientSide="true">
</xp:script>
<xp:script src="#{javascript:sessionScope.jQueryUI}"
clientSide="true">
</xp:script>
<xp:script src="#{javascript:sessionScope.jQueryBlockUI}"
clientSide="true">
</xp:script>
<xp:script src="/home.js" clientSide="true"></xp:script>
<xp:styleSheet href="/style.css"></xp:styleSheet>
<xp:styleSheet href="/jquery-ui.css"></xp:styleSheet>
<xp:script src="/utils.jss" clientSide="false"></xp:script>
</xp:this.resources>
<xp:span style="font-weight:bold;font-size:11pt"></xp:span>
<xp:span style="font-size:14pt"></xp:span>
<xp:span style="font-weight:bold;font-size:11pt"></xp:span>
<xp:inputText id="reUploadAttachmentID" style="display: none;"
styleClass="reUploadAttachmentID"></xp:inputText>
<xp:br style="font-size:11pt"></xp:br>
<xp:panel style="margin-left:auto;margin-right:auto;width:940.0px"
id="mainPanel">
<xp:span style="font-size:14pt"></xp:span>
<xp:span style="font-size:14pt"></xp:span>
<xp:br style="font-weight:bold"></xp:br>
<xp:br></xp:br>
<xp:inputText id="errorMessage" value="#{requestScope.errorMessage}"
styleClass="errorMessage"></xp:inputText>
<xp:span style="font-weight:bold"></xp:span>
<xp:span style="font-weight:bold">
<xp:span style="font-weight:bold"></xp:span>
</xp:span>
<xp:br></xp:br>
<xp:panel styleClass="upload-details-panel">
<xp:span>Upload:</xp:span>
<xp:fileUpload id="fileUpload1" value="#{attachmentDoc.Attachment}"></xp:fileUpload>
</xp:panel>
<xp:panel styleClass="upload-details-panel">
<span>Type:</span>
<xp:comboBox id="cbUploadType" value="#{attachmentDoc.File_Type}"
styleClass="cbUploadType">
<xp:selectItem itemLabel="Attachment"></xp:selectItem>
<xp:selectItem itemLabel="eCR Master File"></xp:selectItem>
<xp:selectItem itemLabel="Financial Analysis"></xp:selectItem>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial" refreshId="panelUploadDetails">
</xp:eventHandler>
</xp:comboBox>
</xp:panel>
<xp:panel id="panelUploadDetails">
<xp:panel styleClass="upload-details-panel">
<xp:this.rendered><![CDATA[#{javascript:var uploadType = getComponent("cbUploadType").getValue();
if(uploadType == "Attachment" || uploadType == null){
return false;
}
return true;}]]></xp:this.rendered>
<span>Division:</span>
<xp:comboBox id="comboBox1" value="#{attachmentDoc.File_Database}"
styleClass="cbUploadDatabase">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var options = ["---"];
return options.concat(#Unique(#DbColumn("", "eCR Database Settings", 1)));}]]></xp:this.value>
</xp:selectItems>
<xp:eventHandler event="onchange" submit="true"
refreshMode="partial"
refreshId='#{javascript:var uploadType = getComponent("cbUploadType").getValue();
if(uploadType == "Financial Analysis"){
return "panelFAType";
}
return "panelExtra";
}'>
</xp:eventHandler>
</xp:comboBox>
</xp:panel>
<xp:panel id="panelExtra">
<!--
this is just used to redirect partial refresh of Division
Selection for non-FA
-->
</xp:panel>
<xp:panel styleClass="upload-details-panel" id="panelFAType">
<xp:this.rendered><![CDATA[#{javascript:var uploadType = getComponent("cbUploadType").getValue();
if(uploadType == "Financial Analysis"){
return true;
}
return false;}]]></xp:this.rendered>
<span>Financial Analysis Type:</span>
<xp:comboBox id="comboBoxFAType" value="#{attachmentDoc.FAType}">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var division = getComponent("comboBox1").getValue();
if(division != null){
return getFATypeOptions(getComponent("comboBox1").getValue());
}
return "---";}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
</xp:panel>
</xp:panel>
<xp:panel styleClass="upload-details-panel">
<span></span>
<xp:button id="btnUpload" value="Upload" styleClass="btnUpload"
style="height:26.0px">
<xp:eventHandler event="onclick" submit="true"
refreshMode="complete" immediate="false" save="true">
<xp:this.action><![CDATA[#{javascript:
var fileData:com.ibm.xsp.http.UploadedFile = facesContext.getExternalContext().getRequest().getParameterMap().get(getClientId('fileUpload1'));
var db:NotesDatabase = session.getCurrentDatabase();
var agent = database.getAgent("Import Data to Document");
//var attDoc:NotesDocument = attachmentDoc.getDocument();
//var doc:NotesDocument = db.createDocument();
var doc:NotesDocument = attachmentDoc.getDocument();
var settingsDoc:NotesDocument = db.getProfileDocument("eCRFilesDBConfiguration", "");
var repositoryPath:String;
if (fileData != null) {
//doc.replaceItemValue('Form', 'Attachment');
doc.computeWithForm(true, false);
var clientFileName:String = fileData.getClientFileName();
var newFile:java.io.File = new java.io.File(fileData.getServerFileName());
var filePath:string = doc.getItemValueString("File_Path");
doc.replaceItemValue('File_Name', clientFileName);
// get file extension
var extension:string = '';
var newFileName:string = '';
var i:int;
i = clientFileName.lastIndexOf('.');
if (i > 0) {
extension = clientFileName.substring(i+1);
}
doc.replaceItemValue('File_Extension', extension);
newFileName = doc.getUniversalID() + '.' + extension;
//var savedFile:java.io.File = new java.io.File('C:\\' + newFileName);
//var savedFile:java.io.File = new java.io.File('C:\\' + clientFileName);
repositoryPath = settingsDoc.getItemValueString("FileRepositoryPath")
var savedFile:java.io.File = new java.io.File(repositoryPath + newFileName);
newFile.renameTo(savedFile);
doc.replaceItemValue("File_Size", savedFile.length())
doc.replaceItemValue("Processed_eCR_Template", "");
// Save the new file
if (savedFile.exists()) {
// this is used to retain the icon/appearance of the attachment
// in the document
//doc.replaceItemValue('Attachment', attDoc.getItemValue('Attachment'));
doc.save();
} else {
//requestScope.errorMessage = 'Server file not found';
print('Server file not found');
}
} else {
requestScope.errorMessage = 'No File found';
print('No File found');
}
// this code prevents resubmit of the uploaded file when the user refreshes
// the page
// var curURL = window.location.href;
// var NSFURL = curURL.toLowerCase().split( '.nsf')[0] + '.nsf';
// window.location.href = NSFURL}]]></xp:this.action>
<xp:this.script><![CDATA[//validate fields before submission
var uploadType = document.getElementById("#{id:cbUploadType}").value;
if(uploadType == "Attachment"){
return true;
}else{
var division = document.getElementById("#{id:comboBox1}").value;
if(division == "---"){
alert("Please specify the division.");
return false;
}
if(uploadType == "eCR Master File"){
return true;
}else if(uploadType == "Financial Analysis"){
var faType = document.getElementById("#{id:comboBoxFAType}").value;
if(faType == "---"){
alert("Please specify the Financial Analysis Type.");
return false;
}else{
return true;
}
}
}
//if upload type not rcognized
alert("Upload Type not recognized. Please contact you administrator.");
return false;
]]></xp:this.script>
</xp:eventHandler>
</xp:button>
</xp:panel>
<xp:panel id="panelUploadedFiles">
<xp:viewPanel rows="30" id="viewPanel1" viewStyle="width:100%">
<xp:this.facets>
<xp:pager partialRefresh="true" layout="Previous Group Next"
xp:key="headerPager" id="pager1">
</xp:pager>
</xp:this.facets>
<xp:this.data>
<xp:dominoView var="view1" viewName="Attachments For Web"
keys="#{javascript:#UserName()}" categoryFilter="File_Owner">
</xp:dominoView>
</xp:this.data>
<xp:viewColumn columnName="File_Name" id="viewColumn2">
<xp:viewColumnHeader value="File Name"
id="viewColumnHeader2">
</xp:viewColumnHeader>
</xp:viewColumn>
<xp:viewColumn columnName="Date_Uploaded" id="viewColumn3">
<xp:viewColumnHeader value="Date Uploaded"
id="viewColumnHeader3">
</xp:viewColumnHeader>
</xp:viewColumn>
<xp:viewColumn columnName="Last_Attached" id="viewColumn4">
<xp:viewColumnHeader value="Last Attached"
id="viewColumnHeader4">
</xp:viewColumnHeader>
</xp:viewColumn>
</xp:viewPanel>
</xp:panel>
</xp:panel>
<xp:br></xp:br>
</xp:view>
The elements that triggers the partial refresh are comboboxes (onchange). The save button is the "Upload" button. The panel panelUploadedFiles contains the view.
You need to post sample code, as there is no way to diagnose your issue from your initial question.
I would recommend to take the "XPages MasterClass" training. It is roughly about four hours. It will show you how to use the XPages Toolbox, which you can use to debug these kinds of issues.
I would like to set focus + place cursor to an Edit Box (the last one) within a repreat control. The repeat is inside a panel (panelRep). I then have a button outside the panel.
This is the client side code for the button which almost works.. Focus is set (blue border around field), but cursor is not placed in field.
User must still click the field to be able to write input.
Example without focus:
Example with focus:
Client side code for button which sets focus to last Edit Box in which id contains the string inputKode:
try {
var el = dojo.query('div[id*="inputKode"]');
var node = el[el.length-1];
setTimeout(function() { node.focus(); }, 500);
//node.focus();
} catch (e) { }
Code for panelRep:
<xp:panel id="panelRep">
<xp:repeat id="repeat1" rows="12" var="row" indexVar="idx"
value="#{view1}" repeatControls="false">
<xp:panel id="panelLinje">
<xp:this.data>
<xp:dominoDocument formName="frmPBudKodeVerdi"
var="dsdoc" action="editDocument" computeWithForm="both"
documentId="#{javascript:row.getUniversalID();}">
</xp:dominoDocument>
</xp:this.data>
<xp:table style="width:800.0px">
<xp:tr>
<xp:td style="width:100px">
<xp:inputText id="inputKode"
value="#{dsdoc.KodeNr}" style="width:62px">
<xp:this.attrs>
<xp:attr name="tabindex"
value="#{javascript:return idx + '1';}">
</xp:attr>
</xp:this.attrs>
<xp:typeAhead mode="partial"
minChars="1" var="lukey" valueMarkup="true" id="typeAhead1">
<xp:this.valueList><![CDATA[#{javascript://var type = compositeData.type;
return TypeAheadKode2(sessionScope.type,lukey);
}]]></xp:this.valueList>
</xp:typeAhead>
<xp:eventHandler event="onchange"
submit="true" refreshMode="partial" refreshId="panelLinje">
<xp:this.action><![CDATA[#{javascript:onChangeKode();}]]></xp:this.action>
</xp:eventHandler>
</xp:inputText>
</xp:td>
<xp:td style="width:450px">
<xp:inputText id="inputNavn"
value="#{dsdoc.KodeNavn}" style="width:440px"
readonly="true">
</xp:inputText>
</xp:td>
<xp:td style="width:60px">
<xp:inputText id="inputNorm"
style="width:45px" value="#{dsdoc.NormPrProd}"
rendered="#{javascript:viewScope.visNorm}" readonly="true">
<xp:this.attrs>
<xp:attr name="tabindex"
value="#{javascript:return idx + '2';}">
</xp:attr>
</xp:this.attrs>
<xp:this.converter>
<xp:convertNumber
type="number">
</xp:convertNumber>
</xp:this.converter>
</xp:inputText>
</xp:td>
<xp:td style="width:50px">
<xp:inputText id="inputAntall"
style="width:45px" value="#{dsdoc.NormAntall}"
rendered="#{javascript:viewScope.visNorm}">
<xp:this.converter>
<xp:convertNumber
type="number">
</xp:convertNumber>
</xp:this.converter>
<xp:eventHandler
event="onchange"
submit="true"
refreshMode="partial"
refreshId="inputTimer">
<xp:this.action><![CDATA[#{javascript:onChangeAntall()}]]></xp:this.action>
</xp:eventHandler>
<xp:this.attrs>
<xp:attr name="tabindex"
value="#{javascript:return idx + '3';}">
</xp:attr>
</xp:this.attrs>
</xp:inputText>
</xp:td>
<xp:td
style="width:50px;text-align:right">
<xp:inputText id="inputTimer"
value="#{dsdoc.Timer}" style="width:45px;text-align:right">
<xp:this.converter>
<xp:convertNumber
type="number">
</xp:convertNumber>
</xp:this.converter>
<xp:this.attrs>
<xp:attr name="tabindex"
value="#{javascript:return idx + '4';}">
</xp:attr>
</xp:this.attrs>
</xp:inputText>
</xp:td>
<xp:td>
</xp:td>
</xp:tr>
</xp:table>
<xp:eventHandler event="onClientLoad" submit="true"
refreshMode="norefresh">
</xp:eventHandler>
</xp:panel>
</xp:repeat>
</xp:panel>
Update 22.09.2012:
#MarkyRoden - Thanks for pointing me in the right direction.
After refining the dojo.query selector, I ended up with 1 line of code.
var el = dojo.query('div[id*="inputKode"] .dijitInputField > input').at(-1)[0].focus();
Original post:
I found out that the element being set focus on was not an INPUT element.
Element id started with widget_
E.g widget_view:_id1:_id2:_id3:repeat1:8:inputKode if there are 8 rows in the repeat
I then discovered that the nodeType of the element was DIV
By viewing the element.innerHTML, I discovered that it had multiple children.
I tried to use element.querySelector or element.querySelectorAll, but I couldn't get them to work for the element, so I ended up looping through element.childNodes.
Not very pretty, but it does the work for now..
I'm sure it can be done much nicer by adding elements to the dojo.query selector, or by using jquery. Have to look into that later..
Well, here's the code I put in the onClientLoad event for my CC:
var el = dojo.query('div[id*="inputKode"]');
var node = el[el.length-1];
node.focus();
var activeElementId = document.activeElement.id;
var activeElement = dojo.byId( activeElementId );
var kids = activeElement.childNodes;
for(var i=0; i < kids.length; i++)
{
if(kids[i].className == 'dijitReset dijitInputField dijitInputContainer')
{
var elementDiv = kids[i];
var elementDivKids = elementDiv.childNodes;
for(var j=0; j < elementDivKids.length; j++)
{
var elementInput = elementDivKids[j];
elementInput.focus();
}
}
}
regards,
Petter