I have the following LINK control on the form and would like to call the managed bean method onclick and do partial refresh (refreshing specifing part of the page). But I just found out, that this doesnt work, I can see that clicking on link sends XHR request to server, but the managed bean method call (entire onClick SSJS event) is not triggered. If I redesign thi as button controll, thigs are working properly, but I need link in this case. Is it some bug or my misuse of concept?
<xp:link escape="true" text="" id="link2" >
<xp:eventHandler event="onclick" submit="true" refreshMode="partial" disableValidators="true" refreshId="create_recipe_form_panel">
<xp:this.action><![CDATA[#{javascript:F.getRecipe().adjustWt()}]]></xp:this.action>
</xp:eventHandler>
</xp:link>
I would say: misuse of concept. A links should "send you somewhere else" while a button "does something for you". So most likely the link destination and the click action get in each others way. Use a button and give it a class. Play with the css until you have the visual you desire.
Related
I have a form displayed in read mode using custom control which is bound to a view scoped bean. I need to have a picker on this CC so that users can select other documents. These display as links (generated using repeat control).
I planned to trigger a method in my view scoped bean to save this value when selection changes.
Now I am stuck with:
onChange event of multi-valued field (used with picker) does not trigger SSJS code
I tried creating a button which I clicked using CSJS on onChange of above field - this does not work either.
In short, SSJS code is not being triggered.
This is troubling me as I have a created a file download control wherein I have added a remove button calling a method in bean and it works just fine.
I am using Debugtoolbar by Mark Leusink and I am not able to display a simple message or set any scope variable. this is happening for onChange and onClick events!!
I have provided my CC code below. If you want you can put it in any Xpage bound to a view scoped bean.
<?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="panel1">
<xp:inputTextarea id="inputTextarea1" style="display:none" value="#{viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]}"
multipleSeparator=","
>
<xp:eventHandler event="onchange" submit="true" refreshMode="partial" refreshId="repeatLinks">
<xp:this.action><![CDATA[#{javascript://viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]= getComponent("inputTextarea1").getValue();
//viewScope.get(compositeData.pickerDetails.beanName).setValue(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());
//viewScope[compositeData.pickerDetails.beanName].linkDocs(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());}]]></xp:this.action>
<xp:this.script><![CDATA[//console.log("Btn found : "+document.getElementById(getID("btnLinks")));
document.getElementById(getID("btnLinks")).click();]]></xp:this.script>
</xp:eventHandler>
</xp:inputTextarea>
<xe:valuePicker id="valuePicker1" listHeight="auto" listWidth="auto" dialogTitle="#{javascript:compositeData.pickerDetails.title}" for="inputTextarea1">
<xe:this.dataProvider>
<xe:simpleValuePicker labelSeparator="|">
<xe:this.valueList><![CDATA[#{javascript:var cd = compositeData.pickerDetails;
getPickerList(cd.viewName,cd.filter,cd.filterField);}]]></xe:this.valueList>
</xe:simpleValuePicker>
</xe:this.dataProvider>
</xe:valuePicker>
<xp:repeat id="repeatLinks" rows="30" var="docLink">
<xp:this.value><![CDATA[#{viewScope[compositeData.pickerDetails.beanName][compositeData.pickerDetails.saveToField]}]]></xp:this.value>
<xp:text escape="false" id="computedField1">
<!-- Link is generated here -->
</xp:text>
<xp:br></xp:br>
</xp:repeat>
<xp:button value="Click Me" id="btnLinks" refreshId="repeatLinks" refreshMode="partial">
<xp:this.onclick><![CDATA[#{javascript:viewScope[compositeData.pickerDetails.beanName].linkDocs(compositeData.pickerDetails.saveToField,getComponent("inputTextarea1").getValue());}]]></xp:this.onclick>
</xp:button>
</xp:panel>
</xp:view>
You mention this is a custom control. The most likely cause then is validation failure elsewhere on the page. Your button calls SSJS without execMode="partial" and an execId. This means the complete XPage is validated during the partial refresh. Your refreshId doesn't include an errors block, so there's nothing to alert the user (and you!) if there is a validation error.
Setting execMode="partial" and execId="panel1" on your button should resolve the problem.
If that's the case, for the future I would recommend adding a PhaseListener into your applications so you can easily output what phases are being triggered and/or always ensuring the refreshArea includes an errors control.
If you remove the style "display:none;" does the code then trigger?
There might be a validation failure that's taking place. What happens if you select "process data without validation" for these events?
I have a Xpage with two custom controls containing editable fields tied to the single data source on the Xpage. On the Xpage I use a xe:dialog that contains a button to save the data source document1 (using SSJS). No validation is occurring yet. I use a xe:dialogButtonBar to call the xe:dialog (using CSJS) which opens fine and then click the OK button containing Action Save Document data source.
diablogButtonBar onClick call to open dialog.
XSP.openDialog("#{id:dialogSaveAsDraft}");
With this configuration the document is saved but the editable fields are not created nor data saved. The Xpage has the following two properties set, computeWithForm: onsave, action:editDocument but have tried createDocument too.
Here is the twist: If I take the button in the xe:dialog and place it outside the xe:dialog, the button works and the Xpage and all editable fields save properly.
What am I missing? I have done almost exactly the same thing before but instead of using the xe:dialogButtonBar I used a string of buttons. I wanted to use the xe:dialogButton Bar to organize the UI.
Can some one explain why that would occur?
The problem is about the form submission. When you launch the dialog, editable fields on the other parts of the page are not submitted (dialog is launched upon partial refresh). Therefore the back-end component tree is not aware of the field updates of the client-side.
You can either open the dialog from the SSJS (so it submits the page) or create a "noupdate" submission with onComplete script to launch the dialog.
<xp:link
escape="true"
text="Open Dialog with SSJS"
id="link1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="norefresh"
action="#{javascript:getComponent('dialogSaveAsDraft').show()}">
</xp:eventHandler>
</xp:link>
<xp:link
escape="true"
text="Open Dialog with onComplete"
id="link2">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="norefresh"
onComplete="XSP.openDialog('#{id:dialogSaveAsDraft}');">
</xp:eventHandler>
</xp:link>
If you use ComputeWithForm then you have to have a DisplayErrors control. That is where validation error messages will appear. Do you have that? If not you could be getting a validation error from the formulas on the form and they have no place to display the error messages. By the way, using ComputeWithForm is not really a good thing to do. You should repeat your validation logic directly on the XPage. Otherwise, you got too many things going on, the validation/translation that happens at the XPage level and again at the form level.
My scenario:
There is a navigator, having some links which redirect the user to some .xsp. Those .xsp contains some views listing certain documents. The users can create new documents using:
<xp:this.action>
<xp:openPage name="/doc.xsp" target="newDocument"></xp:openPage>
</xp:this.action>
Inside this doc., they can create other docs. ( with other datasource declared ) inside a <xe:dialog>. It has only one save and close button, which redirects me: into the current doc. if I opened the dialog from there or it directs me to the .xsp described above.
The problem: if I create a new Doc. and from its inside I create some docs from the dialog, with my Save button, I must hit it 2 times ( in most cases ) to redirect me to those .xsp described above. Why? because in this case my desired destination .xsp is not the PreviousPage, but the PreviousPreviousPage, the PreviousPage being doc.xsp?action=newDocument and the current page it is doc.xsp?documentId=E1141A490316FD88C2257D3400322723&action=openDocument, considering the fact that the doc. was already saved to open the dialog and from the save and close button I just redirect the users back to the main doc.
<xp:button value="Save" id="buttonSave" styleClass="lotusFormButton"
rendered="#{javascript:currentDocument.isEditable()}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" immediate="false" save="false"
id="eventHandler1">
<xp:this.action>
<xp:actionGroup>
<xp:saveDocument var="Cdoc"></xp:saveDocument>
<xp:openPage name="$$PreviousPage"></xp:openPage>
</xp:actionGroup>
</xp:this.action></xp:eventHandler>
</xp:button>
How can I resolve this issue?
I found this solution and for my case it seems to be the most useful.
Return-to-last-view
You just log the page name in a scope variable ( when you're opening a view - in my case the principal Xpage which contains the view ) , and from the Save button I just return to the last view opened ( contained by the xpage ).
I hope I got it right:
You may want to have a look at "navigation rules". Your save button e.g. could return a SSJS value:
return "home"
where 'home' is the name of your rule, directing you to your index.xsp.
So no matter what you did when you used your doc.xsp, how many dialogs you opened, if you click this button that uses the nav rule it will bring you to the page. You used the $$PreviousPage placeholder which simply generates a simple CSJS
history.go(-1)
which then will get you in the trouble you face now.
Try replacing the code for the Save button in the dialog with the following, assuming the id for the xe:dialog is dialog1:
<xp:button value="Save" id="buttonSave" styleClass="lotusFormButton"
rendered="#{javascript:currentDocument.isEditable()}">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action><![CDATA[#{javascript:
Cdoc.save();
var c = getComponent("dialog1");
c.hide("refreshPanel1");
}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
The optional "refreshPanel1" passed to the hide method is the id of the containing element on the XPage to perform a partial refresh when the dialog is closed.
My button code :
<xp:button value="Raport" id="button1" styleClass="lotusFormButton"
style="float:right;">
<xp:eventHandler event="onclick"
submit="true" refreshMode="complete" immediate="false"
save="true" id="eventHandler2">
<xp:this.action><![CDATA[#{javascript:context.redirectToPage("export_hidden.xsp");
getcomponent('exampleDialog').hide()}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
It just go to the export_hidden.xsp ( XAgent for creating an excel file ) but without closing the dialog.
I tried reverse the 2 actions, but same results.
I appreciate your time.
Add a client-side call to XSP.closeDialog('#{id:exampleDialog}') in the onComplete event of the eventHandler.
If I understand you correctly you want to send an attachment to the user but remain on the same page. and after the attachment is delivered close the dialogbox.
the problem above is that your code tries to do two things at once. both clse the dialog and deliver the attachment. That isn't possible.
I see two solutions I would try.
Remove the getcomponent('exampleDialog').hide() and execute that thru a button onclick on a second hidden button in the oncomplete event.
If that don't work, set the url to the export_hidden.xsp in an hidden iframe in your dialogbox and also do a on button click on a hidden button the closes the dialogbox
Doing the CSJS with partial update on the dialog box, along with context.redirectToPage(xAgentName) will work, Domino 9.0.1 FP9.
I am using the toolbar control and that has several actions on it to allow the user to switch document modes, save, return to the view, etc.
I want to add a cancel button to allow the user to cancel their edits and switch them back to read mode.
Since the same event is shared by all these actions (I am using simple actions in computed action groups) I can't check off the "Do not validate or update data". If I do a context.redirectToPage("newpage.xsp") that will cause validation to happen.
I want to be able "cancel" the validation and then perform some action like switch to read mode or to another XPage. Any suggestions?
I guess I need a context.DontSave() method...Is there a method I can use to disable the validation/updating when submitting?
Thanks,
Howard
You can create a standalone cancel button that discards changes and reloads the current page. In the example below I have not taken into account that the current page can contain parameters such as editDocument, documentId etc.
<xp:button id="cancel" value="Cancel" rendered="#{javascript:document.isEditable()}">
<xp:eventHandler event="onclick" submit="true" refreshMode="complete" immediate="true" save="false" id="eventHandler1">
<xp:this.action>
<xp:actionGroup>
<xp:openPage name="#{javascript:view.getPageName()}"></xp:openPage>
</xp:actionGroup>
</xp:this.action></xp:eventHandler>
</xp:button>