export data from panel - xpages

I read this great help 'tool' from David Leedy regarding Export to excel.:
http://notesin9.com/wp-content/uploads/2011/01/XPagesCheatSheet-85x11-v1.pdf
My scenario: I have a ftsearch modulo which offers its results into a viewpanel. I want ONLY those results to be exported into excel. I follow the steps from the .pdf but in that case it will export all the documents listed in the respective view, not the search results.
Is there any possibility to have only the search results into the excel file, after the search is submited?
var myView:NotesView = database.getView('MyView');
Here I get the view which holds the search results, but I want to get the view contents/those docs. after the Search button was submitted. The problem is I don't get the 'updated' view only with the search results, but all the DOCS contained in that view. ( Before the Search button was clicked ... )
Thanks for your time!

You say that you already have a view panel that shows the search results. I'm assuming that you're using the search attribute on the view panel object to do that. Another assumption is that you're computing the full text query in the search attribute based on an input field that's bound to a scoped variable (possibly the sessionScope). So your datasource on the search XPage would look something like this:
<xp:this.data>
<xp:dominoView
var="view1"
viewName="yourSearchView">
<xp:this.search><![CDATA[#{javascript:"[subject]=\"" + sessionScope.searchField + "*\"";}]]></xp:this.search>
</xp:dominoView>
</xp:this.data>
In the Export XPage you can restrict the entries that are exported by applying the same query to the view before exporting the results. To do that you can use the 'FTSearch()' function on the view:
myView.FTSearch("[subject]=\"" + sessionScope.searchField + "*\");
Based on the code on David's cheatsheet I tested this and it turns out that for some reasons if you add this row, the NotesViewNavigator that is constructed based on the (filtered) view isn't limited to the search results, but still contains all entries. The solution to that is to remove the NotesViewNavigator object and use a NotesViewEntryCollection:
var exCon = facesContext.getExternalContext();
var writer = facesContext.getResponseWriter();
var response = exCon.getResponse();
var myView:NotesView = database.getView('vwKlanten');
var query = "[subject]=\"em*\"";
myView.FTSearch(query);
var vec:NotesViewEntryCollection = myView.getAllEntries()
var viewEnt:NotesViewEntry = vec.getFirstEntry();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Cache-Control", "no-cache");
writer.write("<table>");
writer.write("<thead><tr>");
writer.write("<td><b>Column1Header</b></td>");
writer.write("<td><b>Column2Header</b></td>");
writer.write("<td><b>Column3Header</b></td>");
writer.write("</tr></thead>");
while (viewEnt != null) {
writer.write("<tr>");
writer.write("<td>" + viewEnt.getColumnValues()[0] + "</td>");
writer.write("<td>" + viewEnt.getColumnValues()[1] + "</td>");
writer.write("<td>" + viewEnt.getColumnValues()[2] + "</td>");
writer.write("</tr>");
var tmp = vec.getNextEntry(viewEnt);
viewEnt.recycle();
viewEnt = tmp;
}
writer.write("</table>");
writer.endDocument();
(BTW: I added a 'recycle()' call to deal with possible memory errors)

Have You already tried http://poi4xpages.openntf.org/ ?
A custom control for exporting data to excel or word

For me, rather then trying to get ahold of the search results from the code that produces the report, I'd just have that code run the same search again. At least to get it working. Then I'd deal with trying to cut it back to 1 search call. You might find that running 2 searches just isn't a big deal.

Related

How do I get the filename programmatically to use with this code?

The code below is the computed image source for an image control on my custom control. If I run it just like it stands it puts in photo.jpg and works fine. The problem is I want to pass that value programmatically. I have an upload control (fileUpload1) and a download control (fileDownload1) on the custom control as well. I've tried document1.photo which is where the jpg file is stored. I've tried several variations of currentdocument.getitemvalue, getitem, getattachments. But, so far, I have found no way to do this. In addition, I have tried setting the value of filename to the value of the upload control and the download control with no success.
I know this is probably simple, but, as a client developer, it's not simple to me.
Any help would be greatly appreciated.
var doc:NotesDocument = currentDocument.getDocument ();
var UID:string = doc.getUniversalID().toString();
var fp:string = database.getFilePath();
var filename = "photo.jpg"
return '/0/' + UID + '/$file/' + filename
Thanks,
MJ
There may be other ways to achieve this but here's what I usually do:
with image controls I need to be aware that computed resource URLs are in most cases prepended with the database's relative path ending with the database filename. So all I have to add is the usual file attachment URL as in
/0/docUnid/$File/imageFileName
If there is a chance that you have more than one file attached to your doc I need to find out which one of them is the one I wish to display. This can be done by looping through
currentDocument.getAttachmentList(fieldName)
which delivers a java.util.List of NotesEmbeddedObject elements. Using methods like .getName() I then can find the one file you're looking for.
EDIT:
quick example using a repeat to display multiple images sattached to a single richtext field (there may be better solutions esp. regarding the way to filter unwanted file types; I'm using file extensions, only allowing .jpg, .png and .gif). Images are displayed as simple html list elements:
<ul>
<xp:repeat id="repeat1" rows="30" var="pic">
<xp:this.value><![CDATA[#{javascript:
var att:java.util.List=docCar.getAttachmentList("Body");
var it=att.listIterator();
//new empty array, to be used as the repeater's datasource
var arr=[];
//build base path for each image file
var unid=docCar.getDocument().getUniversalID();
var p="/0/" + unid + "/$File/";
while(it.hasNext()){
var e:NotesEmbeddedObject=it.next();
if(e.getName().endsWithIgnoreCase(".png") ||
e.getName().endsWithIgnoreCase(".jpg") ||
e.getName().endsWithIgnoreCase(".gif")){
//push complete filepath + image filename to array
arr.push(p + e.getName());
}
}
return arr;}]]></xp:this.value>
<li>
<xp:image url="#{javascript:pic}" id="image1">
</xp:image>
</li>
</xp:repeat>
</ul>
Hope this helps
Well, I think I have it figured out. Here is the code that now works:
var doc:NotesDocument = currentDocument.getDocument ();
var UID:string = doc.getUniversalID().toString(); var fp:string =
database.getFilePath();
var filename = #AttachmentNames()
return '/0/' + UID + '/$file/' + filename
MJ

Highlight Duplicate list item in SharePoint 2013

I have a SharePoint 2013 (The Cloud version) custom list where 1 column is a text field where contact numbers are keyed in.
How can I get SharePoint to highlight duplicate values in that column so that every time a new item is added to the list, I'll know if the contact number has been used previously?
Ideally, here's what I'd get if I were to enter 816's details for the 2nd time:
CNO....Name.......Issue
816.....Blink........Login Problem (highlighted in red)
907.....Sink.........Access Denied
204.....Mink.........Flickering Screen
816.....Blink........Blank Screen (highlighted in red)
I've been struggling with this for awhile and would be very grateful for any advice. Thanks!
Since SharePoint 2013 uses Client Side Rendering (CSR) as a default rendering mode I would recommend the following approach. Basically the idea is to customize List View on the client side as demonstrated below.
Assume the Requests list that contains RequestNo column.
The following JavaScript template is intended for highlighting the rows when list item with RequestNo column occurs more then once:
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function(ctx) {
var rows = ctx.ListData.Row;
var counts = getItemCount(rows,'RequestNo'); //get items count
for (var i=0;i<rows.length;i++)
{
var count = counts[rows[i]["RequestNo"]];
if (count > 1)
{
var rowElementId = GenerateIIDForListItem(ctx, rows[i]);
var tr = document.getElementById(rowElementId);
tr.style.backgroundColor = "#ada";
}
}
}
});
function getItemCount(items,propertyName)
{
var result = {};
for(var i = 0; i< items.length; i++) {
var groupKey = items[i][propertyName];
result[groupKey] = result[groupKey] ? result[groupKey] + 1 : 1;
}
return result;
}
How to apply the changes
Option 1:
Below is demonstrated probably one of easiest way how to apply those changes:
Open the page in Edit mode
Add Content Editor or Script Editor web part on the page
Insert the specified JavaScript template by enclosing it using
script tag into web part
Option 2:
Save the specified JavaScript template as a file (let's name it duplicatehighlight.js) and upload it into Site Assets library
Open the page in Edit mode and find JSLink property in List View web part
Specify the value: ~sitecollection/SiteAssets/duplicatehighlight.js and save the changes.
Result
SharePoint has some basic conditional formatting for Data View Web Parts and XSLT List Views, but the conditions you can use are rather limited. You can compare a field in the current item with a value that you specify. There are no formulas to count the number of items with the same name or similar, which would be the approach to use to identify duplicates.
If you need to identify duplicates, you may want to create a view that groups by the CNO number. Grouping will also include an item count, so you can run down the list and spot groups with more than one item.

getting a list of forms that contain a specified field, is there a better method

The following code is a script object on an XPage in it I loop through an array of all the forms in a database, looking for all the forms that contain the field "ACIncludeForm". My method works but it takes 2 - 3 seconds to compute which really slows the load of the XPage. My question is - is there a better method to accomplish this. I added code to check to see if the sessionScope variable is null and only execute if needed and the second time the page loads it does so in under a second. So my method really consumes a lot of processor time.
var forms:Array = database.getForms();
var rtn = new Array;
for (i=0 ; i<forms.length; ++i){
var thisForm:NotesForm = forms[i];
var a = thisForm.getFields().indexOf("ACIncludeForm");
if (a >= 0){
if (!thisForm.isSubForm()) {
if (thisForm.getAliases()[0] == ""){
rtn.push(thisForm.getName() + "|" + thisForm.getName() );
}else{
rtn.push(thisForm.getName() + "|" + thisForm.getAliases()[0] );
}
}
}
thisForm.recycle()
}
sessionScope.put("ssAllFormNames",rtn)
One approach would be to build an index of forms by yourself. For example, create an agent (LotusScript or Java) that gets all forms and for each form, create a document with for example a field "form" containing the form name and and a field "fields" containing all field names (beware of 32K limit).
Then create a view that displays all these documents and contains the value of the "fields" field in the first column so that each value of this field creates one line in this view.
Having such a view, you can simply make a #DbLookup from your XPage.
If your forms are changed, you only need to re-run the agent to re-build your index. The #DbLookup should be pretty fast.
Place the form list in a static field of a Java class. It will stay there for a long time (maybe until http boot). In my experience applicationScope values dissappear in 15 minutes.

How to display results of Smartsearch

I'm creating a webpart that uses the SearchHelper to get smart search results based on the search paramaters to display in a live search via Ajax.
I am looking for a way to display the results using the dataset that
SearchHelper.Search(SearchParameters)
returns in the same manner that the SearchResults webparts work.
Ok never mind, found the answer. The answer is to just use the BasicRepeater.
var results = SearchHelper.Search(sp);
BasicRepeater br = new BasicRepeater();
br.DataSource = results;
br.ItemTemplate = CMSDataProperties.LoadTransformation(this, CMS.Root.SmartSearchResults", false);

How can I set the default value in a SharePoint list field, based on the value in another field?

I have a custom list in SharePoint (specifically, MOSS 2007.) One field is a yes/no checkbox titled "Any defects?" Another field is "Closed by" and names the person who has closed the ticket.
If there are no defects then I want the ticket to be auto-closed. If there are, then the "Closed by" field ought to be filled in later on.
I figured I could set a calculated default value for "Closed by" like this:
=IF([Any defects?],"",[Me])
but SharePoint complains I have referenced a field. I suppose this makes sense; the default values fire when the new list item is first opened for entry and there are no values in any fields yet.
I understand it is possible to make a calculated field based on a column value but in that case the field cannot be edited later.
Does anyone have any advice how to achieve what I am trying to do?
Is it possible to have a "OnSubmit" type event that allows me to execute some code at the point the list item is saved?
Thank you.
Include a content editor web part in the page (newform.aspx / editform.aspx) and use jQuery (or just plain javascript) to handle the setting of default values.
Edit: some example code:
In the lists newform.aspx, include a reference to jquery. If you look at the html code, you can see that each input tag gets an id based on the field's GUID, and a title that's set to the fields display name.
now, using jquery we can get at these fields using the jQuery selector like this:
By title:
$("input[title='DISPLAYNAMEOFFIELD']");
by id (if you know the field's internal guid, the dashes will ahve to be replaced by underscores:
// example field id, notice the guid and the underscores in the guid ctl00_m_g_054db6a0_0028_412d_bdc1_f2522ac3922e_ctl00_ctl04_ctl15_ctl00_ctl00_ctl04_ctl00_ctl00_TextField
$("input[id*='GUID']"); //this will get all input elements of which the id contains the specified GUID, i.e. 1 element
We wrap this in the ready() function of jQuery, so all calls will only be made when the document has fully loaded:
$(document).ready(function(){
// enter code here, will be executed immediately after page has been loaded
});
By combining these 2 we could now set your dropdown's onchange event to the following
$(document).ready(function(){
$("input[title='DISPLAYNAMEOFFIELD']").change(function()
{
//do something to other field here
});
});
The Use jQuery to Set A Text Field’s Value on a SharePoint Form article on EndUserSharePoint.com shows you how to set a default value for a field using JavaScript/jQuery.
They also have a whole series of articles on 'taming calculated columns' that will show you many more powerful options you have for calculated fields with the use of jQuery.
One thing to be aware of when inserting JavaScript into a SharePoint page and modifying the DOM is support. There is a small chance that a future service pack will break the functionality you add, and it is quite likely that the next version of SharePoint will break it. Keeping this mind however, I believe it's a good solution at this time.
I've got a walk through with sample code that may help
Setting a default duration for new calendar events
It sets the End Time/Date fields to Start Time + 1.5 hours when you create a new event.
Its complicated a little by the steps need to do the time/date work, but you'll see examples of how to find the elements on the form and also one way to get your script onto the newform.aspx without using SPD.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/javascript">
// Set the hours to add - can be over 24
var hoursToAdd = 1;
// Mins must be 0 or div by 5, e.g. 0, 5, 10, 15 ...
var minutesToAdd = 30;
// JavaScript assumes dates in US format (MM/DD/YYYY)
// Set to true to use dates in format DD/MM/YYYY
var bUseDDMMYYYYformat = false;
$(function() {
// Find the start and end time/minutes dropdowns by first finding the
// labels then using the for attribute to find the id's
// NOTE - You will have to change this if your form uses non-standard
// labels and/or non-english language packs
var cboStartHours = $("#" + $("label:contains('Start Time Hours')").attr("for"));
var cboEndHours = $("#" + $("label:contains('End Time Hours')").attr("for"));
var cboEndMinutes = $("#" + $("label:contains('End Time Minutes')").attr("for"));
// Set Hour
var endHour = cboStartHours.attr("selectedIndex") + hoursToAdd;
cboEndHours.attr("selectedIndex",endHour % 24);
// If we have gone over the end of a day then change date
if ((endHour / 24)>=1)
{
var txtEndDate = $("input[title='End Time']");
var dtEndDate = dtParseDate(txtEndDate.val());
if (!isNaN(dtEndDate))
{
dtEndDate.setDate( dtEndDate.getDate() + (endHour / 24));
txtEndDate.val(formatDate(dtEndDate));
}
}
// Setting minutes is easy!
cboEndMinutes.val(minutesToAdd);
});
// Some utility functions for parsing and formatting - could use a library
// such as www.datejs.com instead of this
function dtParseDate(sDate)
{
if (bUseDDMMYYYYformat)
{
var A = sDate.split(/[\\\/]/);
A = [A[1],A[0],A[2]];
return new Date(A.join('/'));
}
else
return new Date(sDate);
}
function formatDate(dtDate)
{
if (bUseDDMMYYYYformat)
return dtDate.getDate() + "/" + dtDate.getMonth()+1 + "/" + dtDate.getFullYear();
else
return dtDate.getMonth()+1 + "/" + dtDate.getDate() + "/" + dtDate.getFullYear();
}
</script>

Resources