I'm running around in circles...
I'll try to explain what I'm trying to do: we have an XPage in a Notes database for a specific document (all web). We also have defined our own forms inside the database. When the document is opened in XPages, the form is retrieved and the fields are populated. That works, I'm glad to say.
Then, we defined some kind of subform. The idea is that the subform displays specific fields in a different way. There can be multiple subforms attached to a form. All these elements are stored in custom controls, say ccForm, ccSubform and ccField.
Upon opening the document, I get the NotesXspDocument object which I can pass to ccForm. The custom control fetches the form definition, and uses a repeat control to generate ccField and a few ccSubform controls. These get passed a lot of parameters, e.g. the current document as a dataSource parameter. When there's a subform, data is copied from the main document and stored (differently) in a temporary document, declared inside ccSubform. The subform opens and reads a different form definition and generates its own ccField controls, using yet another repeat control.
So the NotesXspDocument is created at the top and passed to all controls using a DataSource parameter. The data related to the subform however is stored in a temporary NotesDocument.
My problems:
when the Save button is clicked, only the QuerySave event of the main XPage is triggered, and I can't find out how to trigger some sort of Save event for the temporary documents inside the subforms; I want to copy data back to the main document
is there some other event I can use to copy data back to the main document?
I have the usual compositeData issue in afterRestoreView; how can I get around it?
Awaiting your replies...
Thanks!
update
Current ccSubform, with some debugging:
<?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"
xmlns:xe="http://www.ibm.com/xsp/coreex" enableModifiedFlag="true" id="ccSubForm">
<xp:this.data>
<xp:dominoDocument var="docTemp" ignoreRequestParams="true">
<xp:this.querySaveDocument><![CDATA[#{javascript:dprint("subform qSD")}]]></xp:this.querySaveDocument>
<xp:this.postNewDocument><![CDATA[#{javascript:var sf= new ccAnyForm(docTemp,compositeData.formName);
viewScope.put(compositeData.formName, sf);}]]></xp:this.postNewDocument>
</xp:dominoDocument>
</xp:this.data>
<xp:this.afterRestoreView><![CDATA[#{javascript:try {
dprint("aRV: " + getClientId("ccSubForm"))
var sf= viewScope.get(compositeData.formName);
dprint("sf= " + sf);
if(!sf)
return;
var mdoc:NotesXspDocument= compositeData.dataSource;
var fields= sf.getFields();
for(var fi in fields) {
var fieldName= fields[fi].name;
var values= [];
for(var i= 0; i<rows.size(); i++) {
var tmp= docTemp.getItemValue(fieldName+"$"+i);
values.push(tmp);
dprint(fieldName + "[" + i + "]= " + tmp);
}
mdoc.replaceItemValue(fieldName, values)
}
}catch(e) {
dprint(e);
}}]]></xp:this.afterRestoreView>
<xp:this.beforePageLoad><![CDATA[#{javascript:dprint("bPL: " + getClientId("ccSubForm"))
}]]></xp:this.beforePageLoad>
<xp:tr>
<xp:td styleClass="label">
<xp:text escape="true" value="#{javascript:compositeData.label}"></xp:text>
</xp:td>
<xp:td>
<xp:panel styleClass="subform">
<xp:table style="width:100%" cellspacing="1" cellpadding="0">
<xp:tr>
<xp:repeat var="thisfield" indexVar="coli">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var mdoc:NotesXspDocument= compositeData.dataSource;
var fields= sf.getFields();
fields}]]></xp:this.value>
<xp:td styleClass="label">
<xp:text escape="true" value="#{javascript:thisfield.label}"></xp:text>
</xp:td>
</xp:repeat>
</xp:tr>
<xp:repeat rows="#{javascript:compositeData.rows}" disableTheme="true" var="row" indexVar="rowi">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var rows= [];
var fields= sf.getFields();
for(var fi in fields) {
var fieldName= fields[fi].name
var values:java.util.Vector= mdoc.getItemValue(fieldName);
if(values) {
for(var i= 0; i<values.size(); i++) {
rows[i]= i+1;
docTemp.replaceItemValue(fieldName+"$"+i, values[i])
}
}
}
return rows;}]]></xp:this.value>
<xp:tr>
<xp:repeat var="currfield" indexVar="coli">
<xp:this.value><![CDATA[#{javascript:var sf= viewScope.get(compositeData.formName);
if(!sf)
return;
var rows= [];
var fields= sf.getFields();
return fields}]]></xp:this.value>
<xp:td>
<xp:this.styleClass><![CDATA[#{javascript:compositeData.dataSource && compositeData.dataSource.isEditable && compositeData.dataSource.isEditable() && !compositeData.isEditable? "data readonly": "data"}]]></xp:this.styleClass>
<xc:ccfieldType="#{javascript:currfield.type}"
fieldLabel="#{javascript:currfield.label}" fieldTitle="#{javascript:currfield.title}"
fieldValue="#{javascript:currfield.value}" fieldIcon="#{javascript:currfield.icon}"
dataSource="#{javascript:docTemp}" formSource="#{javascript:compositeData.formSource}"
<xc:this.rendered><![CDATA[#{javascript:try {
return af? true: false;
} catch(e) {
return false;
}}]]></xc:this.rendered>
<xc:this.fieldName><![CDATA[#{javascript:currfield.name + "$" + rowi}]]></xc:this.fieldName>
<xc:this.fieldIdName><![CDATA[#{javascript:'id'+currfield.name+"$"+rowi}]]></xc:this.fieldIdName>
<xc:this.fieldUniqueName><![CDATA[#{javascript:'unique'+currfield.name+"$"+rowi}]]></xc:this.fieldUniqueName>
</xc:ccDynamicField>
</xp:td>
</xp:repeat>
</xp:tr>
</xp:repeat>
</xp:table>
</xp:panel>
</xp:td>
</xp:tr>
</xp:view>
You need to take one step back and revisit the approach. XPages doesn't limit you to Documents as data sources. It allows binding to Java beans .... and that points to the solution.
Step 1: for each 'special handling' custom control make one bean that gives you exactly what you need.
Step 2: Design one bean to be used as object data source in the main form. The object data source can be designed so you load a document. Don't try to store the document, only the field values and the unid so you can later save it back
Step 3: design properties in that object datasource that return the beans from step 1
Step 4: design your custom controls to take the bean a parmeter. Be specific with the datatype. You can use #{objDatasource.propname} to provide the parameter. Inside the custom controls use standard EL to bind the beans.
Now when you save the data source you have all data inside your main bean and a very clean layout.
Does that work for you?
I'm struggling to see the reason for creating the temp documents, copying the data across, then writing additional data back and not saving the document. I don't think you need to get that complicated because:
You can bind to and from the main document datasource within dependent custom controls. The currentDocument variable gets the nearest dominoDocument datasource, navigating back up the component tree. Alternatively, if your main datasource is always called document1, you can use that. All you need to ensure is that the relevant dominoDocument datasource is defined at a level above the custom control (if you visualise your components in a tree, with parents and children). You just won't be able to select fields in the drop-down.
If you set a value that's not in the main document, that can be computed on the defaultValue property of any controls on the custom control. Or you could set the relevant field on your main document during beforePageLoad / beforeRenderResponse etc.
Dynamic Content Control can be used to programmatically load only the relevant custom control(s).
Alternatively, if you want the temporary document approach, I'd recommend actually saving those documents with some key back to the main document. Then using a Save All Documents action, so you have them in the database, and retrieve them in postSaveDocument of the main document (personally I'd use script in the button instead) to retrieve the documents, write the values back to the main document and delete / flag so an agent can delete them. sessionAsSigner will get past any access limitations here.
If you have a reason for not wanting to clutter the database, don't forget XPages allows you to edit data from multiple databases, so you can always have a "temp store" where these sub-documents get created, edited and stored. The database can be computed, so it can be agnostic of the environment - dev, test, prod. Access can be set separately on that database, if you need to (e.g. allowing the users to delete from that temp store).
Every document data source has its own set of query type events. You could use those to get the data and then write it back to the main document.
Howard
Related
On an custom control I have data-source bounded to a panel control:
<xp:panel>
<xp:this.data>
<xp:dominoDocument var="attachDoc" formName="fAttachment"></xp:dominoDocument>
</xp:this.data>
...
</xp:panel>
Within the panel I have some Edit Box controls e.g.
<xp:inputText id="inpOfficial" value="#{attachDoc.migration}">
When I try to save the doc via SSJS the edit boxes are not saved:
function saveAttachment(){
try {
var doc:NotesDocument = attachDoc.getDocument();
doc.save();
}
}
What am I missing?
The custom control is repeated over the xpage. The custom control has it's own save button calling the saveAttachment() function
Your saveAttachment() function appears to be trying to save a back end notes document on the database. To pass through the changes in the UI you need to run attachDoc.save() which passes the NotesXSPDocument (UI doc) through to the back end NotesDocument saved to the database.
(Assuming your try statement has a catch but you've left that out)
https://www.ibm.com/support/knowledgecenter/en/SSVRGU_9.0.1/reference/r_wpdr_xsp_xspdocument_r.html
Andrew Norrie is right.
If you still wish to use the back-end NotesDocument, get it like this:
var doc:NotesDocument = attachDoc.getDocument(true);
The parameterized getDocument method will update the back-end NotesDocument with the model values before return.
I have created a simple xpage in Domino Designer/Server 9. When opening it, it give following error message:
Engine Exception
name can't be null
IBM WebSphere Application Server
I am not able to locate the source of this error. And strange thing is why IBM Websphere message is coming here!!
<xp:this.beforePageLoad>
<![CDATA[#{javascript:var catDb:NotesDatabase = session.getDatabase("<server name>","catalog.nsf");
requestScope.DocCol = catDb.search("Form='Notefile'"); }]]>
</xp:this.beforePageLoad>
<xp:dataTable id="dataTable1" rows="30" value="#{javascript:return requestScope.DocCol;}" var="repCol" indexVar="repIndex">
<xp:column id="column1">
<xp:text escape="true" id="computedField1" value="#{repCol.Pathname}">
</xp:text>
</xp:column>
</xp:dataTable>
You might want to rework your code a little bit. Along this lines:
<xp:dataTable id="dataTable1" rows="30"
value="#{javascript:return requestTools.getDocumentsByForm('Notefile');}"
var="repCol" indexVar="repIndex">
<xp:column id="column1">
<xp:text escape="true" id="computedField1" value="#{repCol.Pathname}">
</xp:text>
</xp:column>
</xp:dataTable>
Create a script library where you then implement the function. Something like:
var requestTools = {
"isDebug" : function() { return false; },
"debugDocumentsByForm" : function(formName) { return {"PathName" : "DemoPath"},
"getDocumentsByForm" : function(formName) {
if (requestTools.isDebug()) {
return requestTools.debugDocumentsByForm(formName);
} else if (!requestScope.DocCol) {
// optimize this, add only the fields needed to JSON objects, so
// recycling can happen
var catDb:NotesDatabase = session.getDatabase("<server name>","catalog.nsf");
requestScope.DocCol = catDb.search("Form='"+formName+"'");
}
return requestScope.DocCol;
}
}
This will allow you to tune the function without touching all XPages that use it. db.search is the slowest way to perform a search, so you only might use it for testing.
There is no code in the beforePageLoad event. You want to keep the data acquisition confined to your dataTable. Also consider to use a JSON object instead of a document collection and a view or at least an FTSearch. db.Search is way to slow.
There is a required field:
<xp:this.validators>
<xp:validateRequired
message="Required field. Please add some text.">
</xp:validateRequired>
</xp:this.validators>
Also, the value from this field is copied ( using the onChange event ) to other fields:
<xp:eventHandler event="onchange" submit="true"refreshMode="norefresh">
<xp:this.action><![CDATA[#{javascript:Cdoc.setValue("dlg_Localitate",Cdoc.getValue("txt_LocalitateCompanie"));
Cdoc.setValue("dlg_Localitate_1",Cdoc.getValue("txt_LocalitateCompanie"))}]]>
</xp:this.action>
</xp:eventHandler>
An inconvenient issue appears when I just click the field to fill it: the validation message appears. Is because the field initially is empty and the code I added is into the onChange event?
I'd like to use this field as required before users can save the doc.
I tried set the values by CSJS, but without a result...
var string = XSP.getElementById("#{id:inputText1}").value
XSP.getElementById("#{id:txt_LocalitateS}").value = string
XSP.getElementById("#{id:txt_LocalitateP}").value = string
Also, let say I enter a value for inputText1 and later on I enter a new value... How can I update automatically the other 2 fields with the new value?
I tried something like this:
<xp:inputText id="inputText1" value="#{Cdoc.txt_LocalitateCompanie}"
style="height:20.0px;width:122.0px;font-weight:bold;font-size:10pt;font-family:verdana"
required="true">
<xp:this.validators>
<xp:validateRequired message="Completarea localitatii este obligatorie.">
</xp:validateRequired>
</xp:this.validators>
<xp:typeAhead mode="full" minChars="1" ignoreCase="true"
id="typeAhead1">
<xp:this.valueList><![CDATA[#{javascript:#DbLookup(#DbName(),"vwLocalitati",Cdoc.txt_LocalitateCompanie,1,"[PARTIALMATCH]");}]]></xp:this.valueList>
</xp:typeAhead>
<xp:eventHandler event="onchange" submit="true"
refreshMode="norefresh">
<xp:this.action><![CDATA[#{javascript:Cdoc.setValue("dlg_Localitate",Cdoc.getValue("txt_LocalitateCompanie"));
Cdoc.setValue("dlg_Localitate_1",Cdoc.getValue("txt_LocalitateCompanie"))}]]></xp:this.action>
<xp:this.script><![CDATA[XSP.partialRefreshGet("#{id:txt_LocalitateS}", {
onComplete: function() {
XSP.partialRefreshGet("#{id:txt_LocalitateP}", {
onComplete: function(){ }
});
}
});]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
Thanks in advance
Two things here. First, you should disable validators for onChange event, therefore it won't display the validation error.
Second, when you use a CSJS script together with a SSJS, it will fire the CSJS one and if it returns true, proceed with the SSJS. So if you want your CSJS code run after SSJS, you can place it into oncomplete.
If I understood your question correctly, the following code would solve it.
<xp:inputText
id="inputText1"
value="#{Cdoc.txt_LocalitateCompanie}"
style="height:20.0px;width:122.0px;font-weight:bold;font-size:10pt;font-family:verdana"
required="true">
<xp:this.validators>
<xp:validateRequired
message="Completarea localitatii este obligatorie.">
</xp:validateRequired>
</xp:this.validators>
<xp:typeAhead
mode="full"
minChars="1"
ignoreCase="true"
id="typeAhead1">
<xp:this.valueList><![CDATA[#{javascript:#DbLookup(#DbName(),"vwLocalitati",Cdoc.txt_LocalitateCompanie,1,"[PARTIALMATCH]");}]]></xp:this.valueList>
</xp:typeAhead>
<xp:eventHandler
event="onchange"
submit="true"
refreshMode="norefresh"
disableValidators="true">
<xp:this.action><![CDATA[#{javascript:Cdoc.setValue("dlg_Localitate",Cdoc.getValue("txt_LocalitateCompanie"));
Cdoc.setValue("dlg_Localitate_1",Cdoc.getValue("txt_LocalitateCompanie"))}]]></xp:this.action>
<xp:this.onComplete><![CDATA[if(dojo.byId("#{id:txt_LocalitateP}")) {
XSP.partialRefreshGet("#{id:txt_LocalitateP}", {
onComplete: function() {
XSP.partialRefreshGet("#{id:txt_LocalitateS}", {
onComplete: function(){ }
});
}
});
}]]></xp:this.onComplete>
</xp:eventHandler>
</xp:inputText>
UPDATE: In your case, the field you want to refresh is on the second tab with partialRefresh="true". It means that at the time of partialRefreshGet, the target fields might not exist in the DOM. I have added a check now.
this is taken from my comments and put into an answer:
onChange events are generally frowned upon due to performance and user experience. If, however, the field is a listed control ie combobox it is not so dramatic. The following options/ideas are available
Take out the onChange() to test whether that makes a difference. If so, move your code.
Use an update button to change all the fields en masse also preventing information that is already inputted from being deleted unwanted-ly
create your own validation method and show/hide a label manually (hack-y)
Research how to manually put text into an errors control
If the field is in a dialog box, move the onChange() to the open/close methods of the dialog
FURTHER EDIT
An idea that I might suggest is using the xspDoc.getDocument(true) method to push all changes from the xpage to the background document. Something tells me that this might make a difference with the server reading the changes to the document and realizing that it is not empty.
ADDITIONAL IDEAS
I did not mention this because it is a bit more advanced, but should also get the job done assuming the refreshes are done. Even that is not that big of a deal. You could read all of your data from the document into a java bean. This bean is then the "data source" for your page and you bind all of your controls to the properties of this bean. You will then use EL to bind your controls to the bean. In the setters for those variables that trigger changes in other fields, change those values. So,
public PageBean(){
//read connection information out of the URL and get the correct information out of the document
//set all variables
firstName=doc.getItemValueString("firstName");
}
private String firstName;
public String getFirstName(){
return firstName;
}
public void setFirstName(String firstName){
this.firstName = firstName;
setLastName("Schmidt");
}
....
Once you register your bean with faces-config.xml, you can then use EL to access the data
#{PageBean.firstName}
#{PageBean.lastName}
Then you can get your document again in save and reset the values, save and release.
I wonder if I can get the parameters and/or properties of an xpage or custom control programmatically.
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" id="layout">
<xp:this.properties>
<xp:parameter name="testcc.xsp" value="Test 1"></xp:parameter>
<xp:parameter name="index.xsp" value="Main"></xp:parameter>
</xp:this.properties>
...
How can I access this parameter list to use it e.g. in a repeat control?
EDIT
You both are right, thank you! But this works only on a page, not in a custom control.
EDIT
You both are great :-)
BUT: I should revise my question:
I have a custom control where I defined the properties. Within the SAMe custom control I want to access these properties in a repeat control.
Both your answers seem to assume that the access to these properties is from the view (page) level, right?
I tested Svens way - this works if I access the props in the CC from the page level.
EDIT
So this is the code of the CC:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.properties>
<xp:parameter name="param" value="val"></xp:parameter>
</xp:this.properties>
<xp:label value="#{javascript:facesContext.getProperty('param')}"
id="label1">
</xp:label>
</xp:view>
As you can see I just want to access the property within the CC itselt, not from the page level.
You can get the properties by accessing facesContext:
facesContext.getProperty("index.xsp")
EDIT:
If you set the properties in a custom control, the properties are not added to the view root. The are set as attributes of the custom control (com.ibm.xsp.component.UIIncludeComposite).
To access them you first have to give your CC an Id:
<xc:ccProp id="myId" />
This allows you to access the custom control like a component with the getComponent() method and retrieve the attribute properties which contains the properties:
<xp:label id="labelProperty">
<xp:this.value><![CDATA[#{javascript:
var cc:com.ibm.xsp.component.UIIncludeComposite = getComponent("myId");
var arrList:java.util.ArrayList = cc.getAttributes().get("properties");
arrList.get(0).getName()}]]>
</xp:this.value>
</xp:label>
EDIT 2:
You can access the CC (which is the parent of the label in this example) this way if you don't want to give your CC an ID:
Code of the custom control:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.properties>
<xp:parameter name="param" value="val"></xp:parameter>
</xp:this.properties>
<xp:label id="label1">
<xp:this.value><![CDATA[#{javascript:
this.parent.getAttributes().get("properties").get(0).getName()
}]]></xp:this.value>
</xp:label>
<xp:label id="label2">
<xp:this.value><![CDATA[#{javascript:
this.parent.getAttributes().get("properties").get(0).getValue()
}]]></xp:this.value>
</xp:label>
</xp:view>
Hope this helps to clarify the issue.
To get the property list you can use the view.getProperties(). It returns an object of java.util.List which you can use to loop through individual properties (which are objects of com.ibm.xsp.complex.Parameter). Below is the snippet.
var allProperties:java.util.List = view.getProperties();
for (var i=0 ; i<allProperties.size() ; i++) {
var property:com.ibm.xsp.complex.Parameter = allProperties.get(i);
// property.getName();
// property.getValue();
}
If you want to put it in a repeat then you can bind it to view.getProperties() and then get its individual values. You code would then look something like this:
<xp:repeat rows="30" value="#{javascript:view.getProperties()}" var="property">
<xp:text escape="true">
<xp:this.value><![CDATA[#{javascript:property.getName() + " - " + property.getValue();}]]></xp:this.value>
</xp:text>
<xp:br></xp:br>
</xp:repeat>
If you've got values that you want to use on the various parts of an Xpage, whether directly on the page, in a custom control, or in a repeat, I would recommend that you put the values into sessionScope variables. This allows you to change them easily as the user enters information on the Xpage.
For example, sessionScope.PODocUNID = poDoc.getDocument().getUniversalID(); would put the UNID of the purchase order document that I'm working with into a sessionScope variable named PODocUNID. Then, you can pull up the value any time you want by simply referencing sessionScope.PODocUNID in your code.
Alternatively, you could use Russ Maher's current favorite toy, the Managed Bean (see his three-part video on Notes in 9, starting at: http://notesin9.com/index.php/2012/11/02/notesin9-084-sharing-managed-beans-in-xpages/ )
I want to use a comboBox to display several locations. All locations are stored in a view.
I want to have the default location to be displayed = location of the user in the person document in domino directory.
My problem is, the default value does not apply to the comboBox, but is correct if I display it in a computed field. If I hardcode a value as default it works.
Here is my code:
<xp:text escape="true" id="computedField1">
<xp:this.value><![CDATA[#{javascript:viewScope.get("UserLocation")}]]></xp:this.value>
</xp:text>
<xp:this.beforePageLoad><![CDATA[#{javascript:var sUserName:string=#Name("[ABBREVIATE]",#UserName());
var sServer:string=session.getCurrentDatabase().getServer();
if (sServer!=null)
{
var nDb:NotesDatabase=session.getDatabase(sServer,"names.nsf");
if (nDb!=null)
{
var vUser:NotesView=nDb.getView("($VIMPeople)");
if (vUser!=null)
{
var docUser:NotesDocument=vUser.getDocumentByKey(sUserName,true);
if (docUser!=null)
{
var sLocation:string=docUser.getItemValue("Location");
viewScope.put("UserLocation", sLocation);
}
}
}
}}]]></xp:this.beforePageLoad>
<xp:br></xp:br>
<xp:comboBox id="comboBox1">
<xp:this.defaultValue><![CDATA[#{javascript:viewScope.get("UserLocation")}]]></xp:this.defaultValue>
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:#DbColumn(#DbName(),"Standorte",1)}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
<xp:br></xp:br>
<xp:comboBox id="comboBox2" defaultValue="Hamburg">
<xp:selectItems>
<xp:this.value><![CDATA[#{javascript:#DbColumn(#DbName(),"Standorte",1)}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox></xp:view>
The view Standorte has cities in the first column, sortet ascending: Berlin, Frankfurt, Hamburg,...
The value in the users Person document is Frankfurt.
Output in the browser is:
The computedfield1 displays Frankfurt (as expected)
the ComboBox1 displays Berlin (the first value - not the computed default)
the ComboBox2 displays Hamburg (as expected, because of hard coded default value)
Any suggestions what is wrong with the code?
There are a few things I would do to make this work:
First: Make sure the viewScope entry for UserLocation is a string not a vector. Use getItemValueString() instead of getItemValue();
if (docUser!=null) {
var sLocation:string=docUser.getItemValueString("Location");
viewScope.put("UserLocation", sLocation);
}
Second: Make sure the UserLocation is part of the combobox pick list even if it does not exist in the lookup:
var list = #DbColumn(#DbName(),"Standorte",1);
list.push(viewScope.get("UserCompany"));
return #Unique(list);
Finally I would also make sure the user is not "Anonymous" and perhaps trap the session.getDatabase() in case there is an access issue to names.nsf.
if(sUserName == "Anonymous") return;
try {
var nDb:NotesDatabase=session.getDatabase(sServer,"names.nsf");
} catch(ex) {
return; // something went wrong opening the directory.
}
Happy coding.
/Newbs
Please check the following
ssjs is case-sensitive.
Are both values from the names.nsf and from the view the same?
Use .trim on both values to be sure they are the same