We have an XPages application that is setup with help of Notes keyword documents. These keywords are made available via sessionScopes. An example of a scope variable is:
name scope: key_customer_sv
values:
default
values [Yes, No]
For the values I am using a LinkedHashSet to guarantee the insertion order:
var values:java.util.LinkedHashSet = new java.util.LinkedHashSet();
var iterator = keyValues.iterator();
while (iterator.hasNext()) {
var itemvalue = iterator.next();
values.add(itemvalue);
}
map.put("values",values);
The values are stored as as HashMap and the pair names are default and values.
For my xp:radioGroup control I want to read the scope variable and return the values of the value entry.
How must I do this?
Here is what I tried:
var language = "_" + context.getLocaleString();
var languageDefault = "_" + "sv";
var key = "customer";
var values;
try{
values = sessionScope.get("key_" + key + language )['values'];
}catch(e){
print(e);
}
if (null == values){
values = sessionScope.get("key_" + key + language Default)['values'];
}
return values
This works for me:
var language = "_" + context.getLocaleString();
var languageDefault = "_" + "sv";
var key = "customer";
var values;
try{
values = sessionScope.get("key_" + key + language ).get('values');
}catch(e){
print(e);
}
if (null == values){
values = sessionScope.get("key_" + key + languageDefault).get('values');
}
return values==null?"":values.toArray();
It is important by getting values using .get('values') instead of ['values'] , because it returns something different.
I tested is by filling sessionScope with this code:
var key_customer_sv:java.util.HashMap = new java.util.HashMap();
var values:java.util.LinkedHashSet = new java.util.LinkedHashSet();
values.add("Yes");
values.add("No");
key_customer_sv.put("values",values);
key_customer_sv.put("default", "Yes");
sessionScope.put("key_customer_sv", key_customer_sv)
Related
I'm returning values from two different columns but will like to narrow down the results by using a key.
And below is my code which returns all. Efforts to use keys returns in mistypes.
var v:NotesView = database.getView("myView");
var key = getComponent("key").getValue();
var nav:NotesViewNavigator = v.createViewNavFromCategory(key);
//solved by replacing-v.createViewNav();
var entry:NotesViewEntry = nav.getFirst();
var list = new java.util.Vector();
while (entry != null) {
var tabs:string = "";
for (var i=0; i<entry.getIndentLevel(); i++) tabs = tabs + "\t";
requestScope.status += "\n" + tabs + entry.getColumnValues().elementAt(entry.getIndentLevel()).toString();
list.addElement(entry.getColumnValues().elementAt(entry.getIndentLevel()).toString());
var tmpentry:NotesViewEntry = nav.getNextCategory();
entry.recycle();
entry = tmpentry;
}
print(requestScope.status);
return list;
Will be pleased with your help.
Below is code I came up with to run a Saved Search in NetSuite using SuiteScript, create a CSV with the Saved Search results and then email the CSV. The trouble is, the results are limited to 1000 records. I've researched this issue and it appears the solution is to run a loop that slices in increments of 1000. A sample of what I believe is used to slice searches is also below.
However, I cannot seem to be able to incorporate the slicing into my code. Can anyone help me combine the slicing code with my original search code?
var search = nlapiSearchRecord('item', 'customsearch219729');
// Creating some array's that will be populated from the saved search results
var content = new Array();
var cells = new Array();
var temp = new Array();
var x = 0;
// Looping through the search Results
for (var i = 0; i < search.length; i++) {
var resultSet = search[i];
// Returns an array of column internal Ids
var columns = resultSet.getAllColumns();
// Looping through each column and assign it to the temp array
for (var y = 0; y <= columns.length; y++) {
temp[y] = resultSet.getValue(columns[y]);
}
// Taking the content of the temp array and assigning it to the Content Array.
content[x] += temp;
// Incrementing the index of the content array
x++;
}
//Inserting headers
content.splice(0, 0, "sku,qty,");
// Creating a string variable that will be used as the CSV Content
var contents;
// Looping through the content array and assigning it to the contents string variable.
for (var z = 0; z < content.length; z++) {
contents += content[z].replace('undefined', '') + '\n';
}
// Creating a csv file and passing the contents string variable.
var file = nlapiCreateFile('InventoryUpdate.csv', 'CSV', contents.replace('undefined', ''));
// Emailing the script.
function SendSSEmail()
{
nlapiSendEmail(768, 5, 'Inventory Update', 'Sending saved search via scheduled script', 'cc#email.com', null, null, file, true, null, 'cc#email.com');
}
The following code is an example of what I found that is used to return more than a 1000 records. Again, as a novice, I can't seem to incorporate the slicing into my original, functioning SuiteScript. Any help is of course greatly appreciated.
var filters = [...];
var columns = [...];
var results = [];
var savedsearch = nlapiCreateSearch( 'customrecord_mybigfatlist', filters, columns );
var resultset = savedsearch.runSearch();
var searchid = 0;
do {
var resultslice = resultset.getResults( searchid, searchid+1000 );
for (var rs in resultslice) {
results.push( resultslice[rs] );
searchid++;
}
} while (resultslice.length >= 1000);
return results;
Try out this one :
function returnCSVFile(){
function escapeCSV(val){
if(!val) return '';
if(!(/[",\s]/).test(val)) return val;
val = val.replace(/"/g, '""');
return '"'+ val + '"';
}
function makeHeader(firstLine){
var cols = firstLine.getAllColumns();
var hdr = [];
cols.forEach(function(c){
var lbl = c.getLabel(); // column must have a custom label to be included.
if(lbl){
hdr.push(escapeCSV(lbl));
}
});
return hdr.join(",");
}
function makeLine(srchRow){
var cols = srchRow.getAllColumns();
var line = [];
cols.forEach(function(c){
if(c.getLabel()){
line.push(escapeCSV(srchRow.getText(c) || srchRow.getValue(c)));
}
});
return line.join(",");
}
function getDLFileName(prefix){
function pad(v){ if(v >= 10) return v; return "0"+v;}
var now = new Date();
return prefix + '-'+ now.getFullYear() + pad(now.getMonth()+1)+ pad(now.getDate()) + pad( now.getHours()) +pad(now.getMinutes()) + ".csv";
}
var srchRows = getItems('item', 'customsearch219729'); //function that returns your saved search results
if(!srchRows) throw nlapiCreateError("SRCH_RESULT", "No results from search");
var fileLines = [makeHeader(srchRows[0])];
srchRows.forEach(function(soLine){
fileLines.push(makeLine(soLine));
});
var file = nlapiCreateFile('InventoryUpdate.csv', 'CSV', fileLines.join('\r\n'));
nlapiSendEmail(768, 5, 'Test csv Mail','csv', null, null, null, file);
}
function getItems(recordType, searchId) {
var savedSearch = nlapiLoadSearch(recordType, searchId);
var resultset = savedSearch.runSearch();
var returnSearchResults = [];
var searchid = 0;
do {
var resultslice = resultset.getResults(searchid, searchid + 1000);
for ( var rs in resultslice) {
returnSearchResults.push(resultslice[rs]);
searchid++;
}
} while (resultslice.length >= 1000);
return returnSearchResults;
}
I looked into your code but it seems you're missing the label headers in the generated CSV file. If you are bound to use your existing code then just replace
var search = nlapiSearchRecord('item', 'customsearch219729');
with
var search = getItems('item', 'customsearch219729');
and just use the mentioned helper function to get rid off the 1000 result limit.
Cheers!
I appreciate it has been a while since this was posted and replied to but for others looking for a more generic response to the original question the following code should suffice:
var search = nlapiLoadSearch('record_type', 'savedsearch_id');
var searchresults = search.runSearch();
var resultIndex = 0;
var resultStep = 1000;
var resultSet;
do {
resultSet = searchresults.getResults(resultIndex, resultIndex + resultStep); // retrieves all possible results up to the 1000 max returned
resultIndex = resultIndex + resultStep; // increment the starting point for the next batch of records
for(var i = 0; !!resultSet && i < resultSet.length; i++){ // loop through the search results
// Your code goes here to work on a the current resultSet (upto 1000 records per pass)
}
} while (resultSet.length > 0)
Also worth mentioning, if your code is going to be updating fields / records / creating records you need to bear in mind script governance.
Moving your code to a scheduled script to process large volumes of records is more efficient and allows you to handle governance.
The following line:
var savedsearch = nlapiCreateSearch( 'customrecord_mybigfatlist', filters, columns );
can be adapted to your own saved search like this:
var savedsearch = nlapiLoadSearch('item', 'customsearch219729');
Hope this helps.
Passing few values through querystring, to testFn() in controller using below code. But in testFn, I am getting null values. When I keep alert on companyName, rdVal,etc. it is showing correct values. but those are not passing to controller. Please let me know what went wrong.
View:
#Html.ActionLink("Search", null, null, new { id = "lnkSearchMaster", #class = "btn btn-success", onclick = "return lnkgotoAction();" })
function lnkgotoAction() {
$('#grdSearchResults').show();
$('#searchdetails').show();
var rdVal = $("input[name = SearchType]:checked").attr("id");
if (rdVal == "CompanyList" || rdVal == "CompanyHistory" || rdVal == "ApplicationSatatus" || rdVal == "Certificates") {
$('#grdSearchResults').show();
var companyName = $('#companyname').val();
var status = $('#status').val();
var regNo = $('#registrationno').val();
var appRegNo = $('#applicationrefferenceno').val();
var url = '#Url.Content("~/")' + "Search/testFn?test='" + rdVal + "'&companyName='" + $('#companyname').val() +
"'®Num='" + $('#registrationno').val() + "'&appRegNum='" + $('#applicationrefferenceno').val() + "'";
alert(url);
}
$('#grdSearchResults').load(url + ' #grdSearchResults');
TempData.clear();
$('#grdSearchResults').show();
$('#searchdetails').show();
return false;
}
Controller:
public ActionResult testFn(string test, string companyName, string regNum, string appRegNum)
{}
Try as below, it will help you, also always take care the variable name passed to querystring must match controller action parameter names.
#Html.Raw(Url.Action("testFn", "Search"), new{ test= rdVal , companyName= companyName , regNum= regNo , appRegNum= appRegNo })
Suppose I have 2 Lists: Teams and Employees. Each team has a number of employees:
Teams
ID
Name
Employees
ID
Name
TeamID (foreign key of Teams)
Is it possible to write a query in SharePoint JSOM such that I could do something along the following lines (after the query executes/loads):
var employeesListItems = teamListItem.get_item("Employees")
Does SharePoint Object Model support this in any way?
Clarification: my intent is to reuse the ClientObject as much as I can. I understand that I could query for all employees and all teams, create an array of custom objects for each, and then iterate over employees and push them to onto the "Employees" field of the related Team object. I would like to avoid doing so.
Even though SharePoint CAML supports List Joins and Projections, in that case I would suggest you a different approach.
The following example demonstrates how to retrieve parent/child items using a single request:
function getItemWithDetails(parentListTitle,childListTitle,lookupFieldName,lookupFieldValue,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var lists = web.get_lists();
var parentList = lists.getByTitle(parentListTitle);
var parentItem = parentList.getItemById(lookupFieldValue);
var childList = lists.getByTitle(childListTitle);
var childItems = childList.getItems(createLookupQuery(lookupFieldName,lookupFieldValue));
ctx.load(parentItem);
ctx.load(childItems);
ctx.executeQueryAsync(
function() {
success(parentItem,childItems);
},
error
);
}
function createLookupQuery(lookFieldName,lookupFieldValue)
{
var queryText =
"<View>" +
"<Query>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name='{0}' LookupId='TRUE'/>" +
"<Value Type='Lookup'>{1}</Value>" +
"</Eq>" +
"</Where>" +
"</Query>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,lookFieldName,lookupFieldValue));
return qry;
}
Usage
var parentListTitle = 'Teams';
var childListTitle = 'Employees'
var lookupFieldValue = 1;
var lookupFieldName = 'Team';
getItemWithDetails(parentListTitle,childListTitle,lookupFieldName,lookupFieldValue,
function(teamItem,employeeItems){
//print parent item
console.log(teamItem.get_item('Title'));
//print child items
for(var i = 0; i < employeeItems.get_count(); i++){
var employeeItem = employeeItems.getItemAtIndex(i);
console.log(employeeItem.get_item('Title'));
}
},
function(sender,args){
console.log(args.get_message());
});
Another option is to utilize List Joins and Projections. The following example demonstrates how to retrieve employee list items with projected team items
function getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createJoinQuery(joinListTitle,joinFieldName,projectedFields));
ctx.load(items);
ctx.executeQueryAsync(
function() {
success(items);
},
error
);
}
function createJoinQuery(joinListTitle,joinFieldName,projectedFields)
{
var queryText =
"<View>" +
"<Query/>" +
"<ProjectedFields>";
for(var idx in projectedFields) {
queryText += String.format("<Field Name='{0}_{1}' Type='Lookup' List='{0}' ShowField='{1}' />",joinListTitle,projectedFields[idx]);
}
queryText +=
"</ProjectedFields>" +
"<Joins>" +
"<Join Type='INNER' ListAlias='{0}'>" +
"<Eq>" +
"<FieldRef Name='{1}' RefType='Id'/>" +
"<FieldRef List='{0}' Name='ID'/>" +
"</Eq>" +
"</Join>" +
"</Joins>" +
"</View>";
var qry = new SP.CamlQuery();
qry.set_viewXml(String.format(queryText,joinListTitle,joinFieldName));
return qry;
}
Usage
var listTitle = 'Employees';
var joinListTitle = 'Teams'
var joinFieldName = 'Team';
var projectedFields = ['ID','Title'];
getListItems(listTitle,joinListTitle,joinFieldName,projectedFields,
function(employeeItems){
//print items
for(var i = 0; i < employeeItems.get_count(); i++){
var employeeItem = employeeItems.getItemAtIndex(i);
var employeeName = employeeItem.get_item('Title');
var teamName = employeeItem.get_item('Teams_Title').get_lookupValue();
console.log(employeeName + ',' + teamName);
}
},
function(sender,args){
console.log(args.get_message());
});
Probably you can not achieve what you want, because of lookup configuration. But you could do the following:
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var lists = web.get_lists();
var teams = lists.getByTitle("Teams");
var employees = lists.getByTitle("Employees");
//just get the first item
var employee = employees.getItemById(1);
ctx.load(employee)
ctx.executeQueryAsync(function() {
var team = employee.get_item("TeamID");
// both the id and the value of the lookup field
var lookupId = team.get_lookupId();
var lookupValue = team.get_lookupValue();
// let's grab all the fields
var fullTeam = teams.getItemById(lookupId)
ctx.load(fullTeam)
ctx.executeQueryAsync({
var name = fullTeam.get_item("Name");
alert("We can get the Name field of the lookup field: " + name);
});
});
I guess, it a bit reverse of what you really intent to achieve but still this way you will exploit CSOM.
I had this problem on my three sharepoint sites and i manage to resolve this problem by modifying CSS code (cf http://social.msdn.microsoft.com/Forums/en-US/sharepoint2010general/thread/64796605-bcbb-4a87-9d8d-9d609579577f/) on two of them.
I don't know why this doesn't work on my third one which has same updates, same CSS and same html code...
I tried several solutions such as adding indesign="true"(this can't be use because the lists got more than 75 columns). cf
http://www.codeproject.com/Articles/194254/Advanced-fixing-SharePoint-2010-large-lookup-dropd
The only solutions i found required javascript but i don't really want to use it...
If someone have another solution to propose, i would really appreciate.
EDIT:
Thanks to moontear i found something quite great.
I replace the beginning of the script by :
$(document).ready(function () {
$('.ms-lookuptypeintextbox').each(function(){
OverrideDropDownList($(this).attr('title'));
});
// Main Function
function OverrideDropDownList(columnName) {
...
By this way, i just have to include the script and don't care about what columns got problems...
This script seems to be quite great to solve this problem...
Thank you moontear for your comment
The original script come from : http://sharepointegg.blogspot.de/2010/10/fixing-sharepoint-2010-lookup-drop-down.html
$(document).ready(function () {
$('.ms-lookuptypeintextbox').each(function(){
OverrideDropDownList($(this).attr('title'));
});
// Main Function
function OverrideDropDownList(columnName) {
// Construct a drop down list object
var lookupDDL = new DropDownList(columnName);
// Do this only in complex mode...
if (lookupDDL.Type == "C") {
// Hide the text box and drop down arrow
lookupDDL.Obj.css('display', 'none');
lookupDDL.Obj.next("img").css('display', 'none');
// Construct the simple drop down field with change trigger
var tempDDLName = "tempDDLName_" + columnName;
if (lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").length == 0) {
lookupDDL.Obj.parent().append("<select name='" + tempDDLName + "' id='" + tempDDLName + "' title='" + tempDDLName + "'></select>");
lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").bind("change", function () {
updateOriginalField(columnName, tempDDLName);
});
}
// Get all the options
var splittedChoices = lookupDDL.Obj.attr('choices').split("|");
// get selected value
var hiddenVal = $('input[name=' + lookupDDL.Obj.attr("optHid") + ']').val();
if (hiddenVal == "0") {
hiddenVal = lookupDDL.Obj.attr("value")
}
// Replacing the drop down object with the simple drop down list
lookupDDL = new DropDownList(tempDDLName);
// Populate the drop down list
for (var i = 0; i < splittedChoices.length; i++) {
var optionVal = splittedChoices[i];
i++;
var optionId = splittedChoices[i];
var selected = (optionId == hiddenVal) ? " selected='selected'" : "";
lookupDDL.Obj.append("<option" + selected + " value='" + optionId + "'>" + optionVal + "</option>");
}
}
}
// method to update the original and hidden field.
function updateOriginalField(child, temp) {
var childSelect = new DropDownList(child);
var tempSelect = new DropDownList(temp);
// Set the text box
childSelect.Obj.attr("value", tempSelect.Obj.find("option:selected").val());
// Get Hidden ID
var hiddenId = childSelect.Obj.attr("optHid");
// Update the hidden variable
$('input[name=' + hiddenId + ']').val(tempSelect.Obj.find("option:selected").val());
}
// just to construct a drop down box object. Idea token from SPServces
function DropDownList(colName) {
// Simple - when they are less than 20 items
if ((this.Obj = $("select[Title='" + colName + "']")).html() != null) {
this.Type = "S";
// Compound - when they are more than 20 items
} else if ((this.Obj = $("input[Title='" + colName + "']")).html() != null) {
this.Type = "C";
// Multi-select: This will find the multi-select column control on English and most other languages sites where the Title looks like 'Column Name possible values'
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).html() != null) {
this.Type = "M";
// Multi-select: This will find the multi-select column control on a Russian site (and perhaps others) where the Title looks like '????????? ????????: Column Name'
} else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).html() != null) {
this.Type = "M";
} else
this.Type = null;
} // End of function dropdownCtl
});
The code in the solution above is great, but it has two major shortcomings:
1) Doesn't play nicely with Required Field Validators
2) Doesn't play nicely with Cascading Dropdowns via SPServices.
I've fixed these two problems at work, and put my solution here:
http://craigvsthemachine.blogspot.com/2013/04/fixing-complex-dropdown-bug-in.html