I recently came across a situation where I wanted to be able to restrict the Items that a user could select from when creating a relationship in an Item form.
This, it turns out, has a name. It is a Filtered Item Browser and this is one way of implementing one.
Scenario: I am trying to capture File Distribution information for electronic files sent out of the company. I would like to be able to see, from the Document Item Form that this Document has Files that have been distributed and want to be able to distribute Files without having to unlock the Document or File to do so.
Since a Document can have multiple Files related to it I can't just create a simple relationship between a Document Distribution Item and a Document. This wouldn't tell me what Files had been sent out.
So I created:
- New Item Type = Document Distribution.
- Relationship Item type = Distribution Document
- Source = Document Distribution
- Related = Document
- Relationship Item Type = File Distribution
- Source = Document Distribution
- Related = File
The intention is for the user to enter the general distribution information (reason, company etc) then create a number of Distriubtion Document relationships tying the Documents which hold the Files to the Document Distribution record. The user then creates a number of File Distriubtion relationships where they are limited to selecting files that are related to the Documents already listed on the first tab.
In order to implement the Filtered Item Browser we need to react to the user trying to create a new Relationship on the File Distribution Tab.
We do this by using the onSearchGrid event triggered from the "related_id" property of the "File Distribution" Item Type.

Right click on the "related_id" property and then click "view properties" to bring up the Property Dialog.

Select the onSearchDialog event and connect a method to this.
Save all of these changes and then we can write the method detail.
The problem that we face is that we are in one part of the User Interface and can't easily work out what information is in another part of the User Interface. It is possible to navigate through the UI "document.frames" structure and find the grid that belongs to the tab that holds the list of Distribution Document relationships. However, this is not all that safe as the "document.frames" structure can change as a result of user interaction which may mean that you are not looking where you think you are.
It is better to use the underlying "ItemContext" which is an XMLElement that represents the main item concerned with the opened tear off window
var myInnovator = this.NewInnovator();
// we need this later to create Innovator Items.
var itm = inArgs.itemContext;
// get the ItemContext from the inArgs parameter passed into the onSearchGrid method.
Retrieve all of the relationships from the other Tab that you are interested in. In this case we want all of the "Distribution Document" relationships.
var distDocs = itm.selectNodes("Relationships/Item[@type='Distribution Document']");
var idList = new Array();
// array to collect the File ids that we eventually want to limit the user to selecting from
var amlString = ""; // variable to build an AML string for retrieving additional data from the server.
// loop through all of the Distribution Documents (listed Relationships in
// Distribution Document tab) and retrieve the related_id.
// Once we have the related_id we can build the AML to retrieve the
// Document and finally the File that we want to offer to the user.
for (var i=0; i<distDocs.length; i++)
{
var relatedId = top.aras.getItemProperty(distDocs[i], "related_id");
if (relatedId)
{
amlString = "<Item type='Document' action='get' id='" + relatedId + "'>";
amlString += "<Relationships><Item type='Document File' action='get'></Item></Relationships></Item>";
// Retrieve the File items related to this Document from the Server.
// There is probably a more efficient way of doing this since I am
// querying the server once for each document.
// Can't just concatenate the AML as it gives a "The instance doesn't represent a single item"
// exception if you do that.
var distDoc = myInnovator.NewItem(); // create a temporary item to retrieve the Documents & related files from the server
distDoc.loadAML(amlString); // load the AML into the new item.
var returnItem = distDoc.apply(); // retrieve the data from the server.
if (returnItem.isError) // test if the AML retrieved a valid result
{
alert(returnItem);
return returnItem; // exit if it fails.
}
var files = returnItem.getItemsByXPath("//Item[@type='File']"); // get the File items that we want to limit the user to selecting from.
var numFiles = files.getItemCount();
for (j = 0; j < files.getItemCount(); j++)
{
var fileId = files.getItemByIndex(j).getProperty("id"); // get the id of the File.
if (fileId)
{
idList.push(fileId); // put this in the array
}
}
}
;
// for as many "Documents" as are listed in the Distribution Document tab.
}
We now have an array with all of the File id's for Files related to the Documents listed in the Distribution Document tab.
Put these into comma separated list ensuring that it is not empty should there not be any files.
var idListStr = (idList.length>0 ? idList.join(",") : "this_string_should_not_be_empty");
// Using setAttribute("idlist", list) causes the Search Dialog to perform an immediate search
// and also allows you to specify a number of ids to be returned.
// The "list" string should not be empty.
inArgs.QryItem.item.setAttribute("idlist", idListStr); //To display necessary items only.
That's it.