I have a navigation custom control that I want to link to specific documents in a database. I tried using a pageTreeNode but that opened the link when the page loaded. I was told to use a basicContainerNode which allows me to execute code to build the URL but I don't know the code to open the xPage. Can someone tell me how to open the xPage once I have a URL to a document?
<xp:eventHandler event="onItemClick" submit="true"
refreshMode="partial" refreshId="navigator1">
<xp:this.action><![CDATA[#{javascript:
if( context.getSubmittedValue() == "ArchitecturalChangeForm" )
{
// Open Page with queryString
var docUNID = eStarService.fetchDocLibraryDocumentUNID( sessionScope.get( "PropertyNox" ), "Architectural Change Form" );
if( isEmpty( docUNID ) )
{
sessionScope.put( "dialogOopsTitle", "Oopps!" );
sessionScope.put( "dialogOopsMessage", "\nUn-able to locate Architecture File! Please review My reference Library!" );
var dialogOops = getComponent( "dialogOops" );
dialogOops.show();
return "";
}
// WHAT GOES HERE FOR THE URL??
return "OpenDocument&docunid=" + docUNID;
}
You can use context.redirectToPage():
context.redirectToPage( "yourxpage.xsp?action=openDocument&docunid=" + docUNID);
Related
On my xPage I have just a panel and editBox inside.
<xp:panel id="panel1">
<xp:inputText id="inputText1">
<xp:eventHandler event="onkeydown" submit="true"
refreshMode="partial" refreshId="panel1">
</xp:eventHandler></xp:inputText>
</xp:panel>
by pressing Enter key in editBox I want to refresh my panel1 and then return focus to my edit box inputText1.
P.S. it's supposed there are other components on that panel this is why I want to refresh it once user enter something into editbox and press Enter key. Any focus() set code doesn't work once you refresh the panel either into onkeydown event or in onComplete of eventhandler. But you can set the focus if you ouside of that panel (e.g. new button with onclick event "...focus())"
Pressing the enter key is a normal function to receive via a JavaScript listener. Triggering a partial refresh can also be done from JavaScript via the client-side XSP object. Here's how a basic implementation would look.
<xp:panel
id="panel1">
<xp:inputText
id="inputText1">
<xp:eventHandler
event="onkeydown"
submit="false"
id="eventHandler1"
execMode="partial">
<xp:this.script><![CDATA[if(event.keyCode == 13){
event.preventDefault();
XSP.partialRefreshPost("#{id:panel1}",{
onComplete: function(){
document.getElementById("#{id:inputText1}").focus();
}
});
}]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
</xp:panel>
Edit:
I forgot to use event.preventDefault() on the enter action. I confirmed this as working in a sample XPage, shown here. Alternatively, in place of the focus call, you could use a select to highlight existing text, or do something else to put the cursor at the end of the field.
I wrote a general purpose snippet a while back that tries to counteract the effect of partial refresh on focus states. If I understand your issue correctly, this would remove the need to "hard code" which field you want to have focus after the refresh. You will also need the snippet for hijacking partial refreshes.
I think the only thing you need to to to the field after you've added the two snippets is to make sure that the event handler/partial refresh only fires on the enter key.
In client script: return ( thisEvent.keyCode === 13 );
Code snippet for hijacking partial refreshes:
function hijackAndPublishPartialRefresh(){
// Hijack the partial refresh
XSP._inheritedPartialRefresh = XSP._partialRefresh;
XSP._partialRefresh = function( method, form, refreshId, options ){
// Publish init
dojo.publish( 'partialrefresh-init', [ method, form, refreshId, options ]);
this._inheritedPartialRefresh( method, form, refreshId, options );
}
// Publish start, complete and error states
dojo.subscribe( 'partialrefresh-init', function( method, form, refreshId, options ){
if( options ){ // Store original event handlers
var eventOnStart = options.onStart;
var eventOnComplete = options.onComplete;
var eventOnError = options.onError;
}
options = options || {};
options.onStart = function(){
dojo.publish( 'partialrefresh-start', [ method, form, refreshId, options ]);
if( eventOnStart ){
if( typeof eventOnStart === 'string' ){
eval( eventOnStart );
} else {
eventOnStart();
}
}
};
options.onComplete = function(){
dojo.publish( 'partialrefresh-complete', [ method, form, refreshId, options ]);
if( eventOnComplete ){
if( typeof eventOnComplete === 'string' ){
eval( eventOnComplete );
} else {
eventOnComplete();
}
}
};
options.onError = function(){
dojo.publish( 'partialrefresh-error', [ method, form, refreshId, options ]);
if( eventOnError ){
if( typeof eventOnError === 'string' ){
eval( eventOnError );
} else {
eventOnError();
}
}
};
});
}
Code snippet for remembering focus states:
dojo.addOnLoad(function(){
dojo.subscribe( 'partialrefresh-init', function(){
// setTimeout needed to make it work in Firefox
setTimeout(function(){
var activeElementId = document.activeElement.id;
var focusSubscription = dojo.subscribe( 'partialrefresh-complete', function(){
// Only set focus if field hasn't been overwritten/lost focus
if( document.activeElement.id !== activeElementId ){
var activeElement = dojo.byId(activeElementId);
if( activeElement && /INPUT|SELECT|TEXTAREA/.test( activeElement.nodeName ) ){
// Set focus to element/select text
activeElement.focus();
if( activeElement.nodeName !== 'SELECT' ){
activeElement.select();
}
}
}
// Unsubscribe after focus attempt is done
dojo.unsubscribe( focusSubscription );
});
// In case of error -> remove subscription
var errorSubscription = dojo.subscribe( 'partialrefresh-error', function(){
dojo.unsubscribe( focusSubscription );
});
}, 0 );
} );
});
I've button which is rendered as designed in test environment. When same document copied to production server which has same configuration as development server does not display it.
Asked the amdin to restart the http task, compact database but nothing worked. The test and production server documents has same configuration.
What to check.
This screen shot is from production database:
This screen shot is of same document on same server but in Pilot folder:
Source of submit button:
<xp:button
value="Lab Man Approval"
id="button4">
<xp:this.rendered><![CDATA[#{javascript:document1.isEditable() & (sessionScope.get("flag")==0) & (document1.getItemValueDate("SECTION1DATECOMPLETED")!=null) & (document1.getItemValueString("DOC_STAGE_TX") == "Stage 2") & (#IsMember(#Name("[ABBREVIATE]",document1.getItemValueString("LABManager_NM")),#Name("[ABBREVIATE]",#UserName())))}]]></xp:this.rendered>
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete"
immediate="false"
save="true">
<xp:this.action>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var comboBox2:com.ibm.xsp.component.xp.XspSelectOneMenu = getComponent("comboBox2");
var a=comboBox2.getValue();
var f=sessionScope.get("flag");
if (f == 0){
sessionScope.put("flag",1);
}
var f=sessionScope.get("flag");
//sessionScope.put("ITDialog","flag value " + #Text(f));
//var d=getComponent('dialog1');
//d.show();
if (f == 1){
if ( a=="Accepted"){
var d=getComponent('dialog2');
d.show();
}
}
if (f == 1){
if ( a=="More information needed"){
var d=getComponent('dialog2');
d.show();
}
}
if (f == 1){
if ( a=="Cancelled"){
var d=getComponent('dialog2');
d.show();
}
}}]]></xp:this.script>
</xp:executeScript>
</xp:this.action>
</xp:eventHandler>
</xp:button>
You got quite a mouthful for your rendered condition, you might want to "outsource" that to a function call. Use something like this and use a computed field to see the result:
function renderApprovalButton(doc) {
var labManager = #Name("[ABBREVIATE]",doc.getItemValueString("LABManager_NM"));
var curUser = #Name("[ABBREVIATE]",#UserName());
/* Take this out when done */
print(doc.isEditable());
print(sessionScope.get("flag")==0);
print(doc.getItemValueDate("SECTION1DATECOMPLETED")!=null);
print(sessionScope.get("flag")==0);
print(doc.getItemValueString("DOC_STAGE_TX") == "Stage 2");
print(labManager);
print(curUser);
print(labManager==curUser);
/* End of debug to be taken out */
var result = doc.isEditable()
&& sessionScope.get("flag")==0
&& doc.getItemValueDate("SECTION1DATECOMPLETED")!=null
&& sessionScope.get("flag")==0
&& labManager == curUser;
return result;
}
That should do the trick to see what is going wrong
I've one required combobox "PriceList" associated with display error control.
I've anothe field "Price" with OnChange event to set required property of "Pricelist". If price is entered the "Pricelist" combobox required property set to false else on blank, "Pricelist" is enabled.
Both fields and xpage have disabled client validation off.
The combox displays error message in the beginning when document is created. If I change and blanked the value of "price", "pricelist" 's error control does not display message though required property is true.
What is issue here?
Pricelist code:
<xp:comboBox
id="comboBox7"
value="#{document1.PList1}"
style="width:99.0px"
disableClientSideValidation="true">
<xp:this.validators>
<xp:validateRequired
message="Required">
</xp:validateRequired>
</xp:this.validators>
<xp:this.required><![CDATA[#{javascript:var price11:com.ibm.xsp.component.xp.XspInputText = getComponent("price11");
var a=price11.getValueAsString()
if (a == ""){
return true;
}else{
return false;
}}]]></xp:this.required>
<xp:this.disabled><![CDATA[#{javascript:var price11:com.ibm.xsp.component.xp.XspInputText = getComponent("price11");
var a=price11.getValueAsString();
if ( a==""){
return false;
} else {
return true;
}}]]></xp:this.disabled>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:var result = [];
var pricelist = #DbLookup("" , "Keywords","Price List", 2)
result.push("")
for (var i = 0; i < pricelist.length; i++) {
var eachName = pricelist[i];
result.push(eachName);
}
return result;}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
Price code:
<xp:inputText
value="#{document1.Price1}"
id="price11"
style="width:80px"
required="true"
disableClientSideValidation="true">
<xp:this.validators>
<xp:validateRequired
message="Required field">
</xp:validateRequired>
</xp:this.validators>
<xp:eventHandler event="onchange" submit="true" refreshMode="complete">
<xp:this.action>
<xp:executeScript>
<xp:this.script><![CDATA[#{javascript:var comboBox7:com.ibm.xsp.component.xp.XspSelectOneMenu = getComponent("comboBox7");
var price11:com.ibm.xsp.component.xp.XspInputText = getComponent("price11");
var a=price11.getValueAsString();
if(a !=="" ){
//if(comboBox7.isRequired()==true){
//comboBox7.setRequired(false);
//}
//var result = [];
//var pricelist = #DbLookup("" , "Keywords","Price List", 2)
//result.push("")
//for (var i = 0; i < pricelist.length; i++) {
//var eachName = pricelist[i];
//result.push(eachName);
//}
//comboBox7.setValue(result);
comboBox7.setRequired(false);
comboBox7.setDisabled(true);
} else {
comboBox7.setDisabled(false);
comboBox7.setRequired(true);
}
}]]></xp:this.script>
</xp:executeScript>
</xp:this.action></xp:eventHandler></xp:inputText>
I suggest using the SSJS debugger or print statements to work out what's happening here. The code seems very convoluted. First of all, you have code that does setRequired on the ComboBox to true or false. But that can only run if validation passes. It also does a full refresh, so it appears you're reloading the page. Furthermore, you are calculating the required property on the combo box, so even if you do a partial refresh and you set it as required or not, the RenderResponse phase will recalculate the required property and override whatever state is set by the onChange event. The same is true for the disabled property.
If you set a component as required, validation for that refresh will already have occurred. So it will only be required the next time the page is submitted by the user. At which point validation will fail, so unless you're disabling validators, you cannot set it to not disabled. But disabling validators is done server-side, before values are entered by the user.
My recommendation would be to move your validation to your save method and work from the underlying datasource rather than the components. If you want to mark components as valid or not, then there is a setValid() method and there are blog posts about adding a FacesMessage to indicate an error and binding it to a component.
For a more advanced method, Tim Tripcony did a NotesIn9 about using the binding property to link components for this kind of related validation. But that will require Java.
The QueryDocumentDelete in Database script only seems to run from the Notes UI client when a document is deleted. Is there a similar event when a document is deleted with the Delete Selected Documents simple action?
You're right, QueryDocumentDelete in database script is a Notes UI function and runs only from the Notes client.
Unfortunately, there is no similar event in simple action Delete Selected Documents.
An easy workaround is to write the whole functionality of "Delete Selected Documents" on your own. This way you can do things you want to before documents get actually deleted or prevent certain documents from deletion.
Here is a sample code for a button "Delete Selected Documents" which deletes documents in a view panel (with id "viewPanel1"):
<xp:button
value="Delete Selected Documents"
id="button1">
<xp:eventHandler
event="onclick"
submit="true"
refreshMode="complete">
<xp:this.script><![CDATA[
if(!XSP.isViewPanelRowSelected("#{id:viewPanel1}", "_colcbox")){
XSP.alert("Please select one or more documents to delete.");
return false;
}
if (!XSP.confirm('Are you sure you want to delete selected documents?')){
return false;
}]]></xp:this.script>
<xp:this.action><![CDATA[#{javascript:
var viewPanel = getComponent("viewPanel1");
var selectedIds = viewPanel.getSelectedIds();
for(i=0; i < selectedIds.length; i++) {
var docId = selectedIds[i];
var doc = database.getDocumentByID(docId);
// do things here you would do on QueryDocumentDelete
doc.remove(true);
doc.recycle();
}}]]></xp:this.action>
</xp:eventHandler>
</xp:button>
I haven't made any changes to this database, and all of a sudden, I get an (500) error when loading various Xpages. On this one, when I switch to "Display the Xpage runtime error" on xpages tab of the database properties, it displays the errors below web.
If I remove the button that this Client side code is contained (it had worked perfectly to validate an Edit Box before), the error just moves to the next piece of JavaScript on the page and gives a similar error.
I've tried to "CLEAN" project. I've tried to Sign the entire database with the server id.
Any help would be much appreciated!
The runtime has encountered an unexpected error.
Error source
Page Name:/msr.xsp
Control Id: _id20
Exception
Error while executing JavaScript computed expression
Script interpreter error, line=3, col=8: [ReferenceError] 'XSP' not found
------the button control:
<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
<xp:actionGroup>
<xp:actionGroup>
<xp:modifyField
name="Status">
<xp:this.value><![CDATA[#{javascript:if (document1.isNewNote()) {
"Submitted to Project Officer";
}
else if (document1.Status == "Submitted to Project Officer"){
"Submitted to Supervisor";
}
else{
"Completed";
}}]]></xp:this.value>
</xp:modifyField>
<xp:saveDocument
var="document1">
</xp:saveDocument>
<xp:changeDocumentMode
mode="readOnly" var="document1">
</xp:changeDocumentMode>
</xp:actionGroup>
</xp:actionGroup>
</xp:this.action>
<xp:this.script>
<xp:executeClientScript>
<xp:this.script><![CDATA[#{javascript:
if(XSP.getElementById("#{id:ProjectTitle}").value == ""){
XSP.getElementById("#{id:ProjectTitle}").focus();
XSP.getElementById("#{id:ProjectTitle}").style.backgroundColor = "pink";
alert("Please enter a Project Title.");
return false;
}
else{
XSP.getElementById("#{id:ProjectTitle}").style.backgroundColor = "#ffe";
}
///NOT sole source
if(XSP.getElementById("#{id:RT}").innerHTML == "MSR"){
if(XSP.getElementById("#{id:SoleSource}").checked == false){
if(XSP.getElementById("#{id:SS_Name1}").value == ""){
XSP.getElementById("#{id:SS_Name1}").focus();
XSP.getElementById("#{id:SS_Name1}").style.backgroundColor = "pink";
alert("Please fill in the Name of Suggested Source 1.");
return false;
}
else{
XSP.getElementById("#{id:SS_Name1}").style.backgroundColor = "#ffe";
}
}
}
}]]></xp:this.script>
</xp:executeClientScript>
</xp:this.script></xp:eventHandler>
</xp:button>
The script property of your executeClientScript action looks like it is being computed. The source should look something like this:
<xp:executeClientScript>
<xp:this.script>
<![CDATA[if(XSP.getElementById("#{id:ProjectTitle}").value == ""){...
]]></xp:this.script>
</xp:executeClientScript>
Instead, you have this:
<xp:executeClientScript>
<xp:this.script>
<![CDATA[#{javascript:if(XSP.getElementById("#{id:ProjectTitle}").value == ""){...
}]]></xp:this.script>
</xp:executeClientScript>
That syntax implies that, instead of simply entering client-side JavaScript to execute, you're running server-side JavaScript to compute what the client-side JavaScript should be. Server-side JavaScript does not define a global XSP object like client-side JavaScript does, which is why you're getting a ReferenceError.
Remove #{javascript: from the beginning of your CDATA block and the final } from the end, and your code will execute in the context you intended.