Sharepoint: Lookup against a large list with CAML Query - javascript

I have a SharePoint List (list_dls) which has all the Email addresses. The list has a single column with Field name "Title". I need to validate that the Item in the "LookupField" is contained in the 'list_dls'. The list has over 5000 emails, hence I will need to do a CAML query. The script does not seem to find the item. Any ideas to get it to work would be really appreciated.
Here is the code.
<input type='button' value='get Lists' onclick="PopulateLookupField();"/>
<p id="demo"></p>
<script language="javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
var LookupField = 'lnam#xyz.com';
function PopulateLookupField()
{
var clientContext = new SP.ClientContext.get_current();
var LookupList = clientContext.get_web().get_lists().getByTitle('list_dls');
var camlQuery_list = new SP.CamlQuery();
camlQuery_list.ViewXml = #"<View Scope='RecursiveAll'><ViewFields><FieldRef Name='ID'/><FieldRef Name='Title'/></ViewFields><RowLimit Paged='TRUE'>5000</RowLimit></View>";
LookupList<ListItem> allListItems = new LookupList<ListItem>();
do
{
var listItemCollection = LookupList.GetItems(camlQuery_list);
clientContext.Load(listItemCollection);
clientContext.ExecuteQuery();
allListItems.AddRange(listItemCollection);
var ItemFound = listItemCollection.Where(item => item.FieldValues["Title"].ToString().Contains(LookupField);
if(ItemFound !== null){break;}
camlQuery_list.ListItemCollectionPosition = listItemCollection.ListItemCollectionPosition;
} while (camlQuery_list.ListItemCollectionPosition != null);
clientContext.load(ItemFound);
alert("ItemFound = " + ItemFound);
}
</script>

First, go to the SharePoint list "list_dls" and create a new index for Title column (maybe is already done)
https://support.microsoft.com/en-us/office/add-an-index-to-a-list-or-library-column-f3f00554-b7dc-44d1-a2ed-d477eac463b0
Also, you can search immediately with caml query in a list
camlQuery_list.ViewXml = $"<View><Query><Where><Eq><FieldRef Name='Title' /><Value Type='Text'>{LookupField}</Value></Eq></Where></Query></View>";
ListItemCollection collection = LookupList.GetItems(camlQuery_list);
context.Load(collection);
context.ExecuteQuery();
if (collection.Count > 0)
{
var yourItem = collection[0];
}

Related

SharePoint JavaScript Display Value from Lookup Field

Existing system has HTML, JavaScript forms with the following:
SharePoint List, "CustomerType" with values
SharePoint List, "Customer" with lookup column named, "CustomerType" pulling values from "CustomerType"
Need to add a new field so I mirrored the "CustomerType" by creating:
SharePoint List, "CustomerSegmentation" with values
SharePoint List, "Customer" with lookup column named, "CustomerSegmentation" pulling values from "CustomerSegmentation"
I copied the HTML, JavaScript, etc. - It is all working well for selecting a value and creating the item in the "customer" list. However, when I try to display the selected value on a 'display' HTML form using:
var CustomerSegmentationField = oListItem.get_item('CustomerSegmentationField');
if (checkNotEmpty(CustomerSegmentationField)) {
$("#selCustomerSegmentationField").val(CustomerSegmentationField.get_lookupId());
}
I get this error:
Uncaught Error: The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
at Function.Error.create (ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:177)
at SP.ListItem.$1D_2 (sp.js:formatted:15164)
at SP.ListItem.get_item (sp.js:formatted:14868)
at onQuerySucceeded (Display-New-Request.aspx?itemID=9076:1678)
at Array. (ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:23)
at ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:2555
at SP.ClientRequest.$3K_0 (sp.runtime.js:2)
at Array. (ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:23)
at ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:2555
at Sys.Net.WebRequest.completed (ScriptResource.axd?d=k5RfMmPNK2hWIceXJ8-ajx3E8J_9Fwh_cmdsa2b8w5b_6SdxoV5CP7PTQYU2geZFptqlColfo4USOXQsdBih3W0VS_49yn_5vEAL69UdI91yC-tDiYJ5qy_HJzfGk6ituovIGh_kYQ43NWRInP8bleYrT4aM9uWrD_zUrKaOdVSegfYI0_gHDDpmP74zGEwh0&t=ffffffffecf19baa&ctag=200622:formatted:4336)
I would greatly appreciate help - thank you!!
<script>
function retrieveListItems(ID) {
var clientContext = new SP.ClientContext("https://xxxxxxx/DIG/Customer/");
var oList = clientContext.get_web().get_lists().getByTitle('Customer');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View>\
<Query>\
<Where>\
<Eq>\
<FieldRef Name='ID' />\
<Value Type='Counter'>"+ ID +
"</Value>\
</Eq>\
</Where>\
</Query>\
</View>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}
function onQuerySucceeded(sender, args) {
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var color = new Object();
var oListItem = listItemEnumerator.get_current();
// Add Section wise set items here.
// Section 1
$("#selRequestType").val(oListItem.get_item('RequestType'));
$("#txtCustomerNumber").val(oListItem.get_item('CustomerNumber'));
var salesCont = (oListItem.get_item('ArdentSalesContact')).get_lookupValue();
$("#txtArdentSalesContact").val(salesCont);
var csr = (oListItem.get_item('CSR')).get_lookupValue();
$("#txtCSR").val(csr);
$("#txtAdditionalComments").val(oListItem.get_item('AdditionalComments'));
var company = oListItem.get_item('Company');
var companyArray = company.split('~');
for (var i = 0 ; i < companyArray.length; i++) {
$.each($("input[name='company']"), function () {
if ($(this).val() == companyArray[i]) {
$(this).prop('checked', true);
}
});
}
var OrderSystem = oListItem.get_item('OrderSystem');
OrderSystemArray = OrderSystem.split('~');
for (var i = 0 ; i < OrderSystemArray.length; i++) {
$.each($("input[name='OrderSystem']"), function () {
if ($(this).val() == OrderSystemArray[i]) {
$(this).prop('checked', true);
}
});
}
$("#selDoesExistInSFDC").val(oListItem.get_item('DoesLeadAccountExistInSFDC'))
;
$("#txtPasteURL").val(oListItem.get_item('PasteAccountURLFromSFDC'));
$("#txtParentNationalAccount").val(oListItem.get_item('ParentNationalAccount'));
$("#txtSoldToName").val(oListItem.get_item('SoldToName'));
$("#txtSoldToLegalName").val(oListItem.get_item('SoldToLegalName'));
$("#txtShortName").val(oListItem.get_item('ShortName'));
$("#selCustomerChannel").val(oListItem.get_item('CustomerChannel'));
//New field
var CustomerSegmentationField = oListItem.get_item('CustomerSegmentationField');
if (checkNotEmpty(CustomerSegmentationField)) {
$("#selCustomerSegmentationField").val(CustomerSegmentationField.get_lookupId());
function onQueryFailed(sender, args) {
alert('Request failed. ' + args.get_message() + '\n' +
args.get_stackTrace());
}
</script>
Does this cover that part?
The error mentions you have not loaded the field.
Make sure you loaded the item and the field static name matches ‘CustomerSegmentationField’
clientContext.load(listItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.OnLoadSuccess), Function.createDelegate(this, this.OnLoadFailed));

How do I add a new value to a Google Sheet from a text field in a Web App and then automatically update the associated dropdown?

WARNING: I'm not a programmer by trade.
Ok. Got the disclaimer out of the way. So this might not be the best way to do this but here is the scenario. I have a dropdown that gets populated via a Google Sheet. The user chooses a selection from the list but this dropdown does not have all of the possible values it could have. There will likely be a time when the user needs a new value added. While I could manually update the spreadsheet as new values are requested that introduces an element of human availability to get this done and I'm not always available.
What I would prefer is a self-serve model. I want to supply the user with a text field where they can enter the new value and submit it to the Google Sheet. Then I would like the dropdown to be updated with the new value for the user to choose.
Now, I realize that I could just submit the value in the new field to the Google Sheet but that will require building a condition to see whether it is the dropdown or text field that has a value in it. I'd also need some type of error handling in case both the dropdown and text field have values. That seems like a bigger headache to program then my ask.
I'm not sure what code you would need to see to help make this work but here is what I think might help.
doGet function
function doGet(e){
var ss = SpreadsheetApp.openById(ssId)
var ws = ss.getSheetByName("External");
var range = ws.getRange("A2:D2");
var valuesArray = [];
for (var i = 1; i <= range.getLastColumn(); i++){
var lastRowInColumn = range.getCell(1, i).getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
var list = ws.getRange(2,i,lastRowInColumn-1,1).getValues();
valuesArray.push(list);
}
var userEmail = Session.getActiveUser().getEmail();
var sourceListArray = valuesArray[2].map(function(r){ return '<option>' + r[0] + '</option>'; }).join('');
var productListArray = valuesArray[3].map(function(r){ return '<option>' + r[0] + '</option>'; }).join('');
var tmp = HtmlService.createTemplateFromFile("config");
tmp.productList = productListArray;
return tmp.evaluate();
}
Add to Google Sheet
function userClicked(tagInfo){
var ss = SpreadsheetApp.openById(ssId)
var ws = ss.getSheetByName("Data");
ws.appendRow([tagInfo.email, tagInfo.source, tagInfo.product, new Date()]);
}
Add record
function addRecord(){
var tagInfo = {};
tagInfo.product = document.getElementById("product").value;
google.script.run.userClicked(tagInfo);
var myApp = document.getElementById("source");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
var myApp = document.getElementById("brand");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
var myApp = document.getElementById("product");
myApp.selectedIndex = 0;
M.FormSelect.init(myApp);
}
How dropdowns are populated in the HTML.
<div class="input-field col s3">
<select id="product" onchange="buildURL()">
<option disabled selected value="">Choose a product</option>
<?!= productList; ?>
</select>
<label>Product</label>
</div>
Need to see anything else? I think it might be relatively easy to add the new value to the column but the tricky part seems to be the update of only that one dropdown and not the entire app. To me it seems like I want to trigger the doGet() function again but only for that specific dropdown. Thoughts?
UPDATE: current code to add new value to dropdown
function addProduct() {
let newProd = document.getElementById("newProduct").value;
google.script.run.withSuccessHandler(updateProductDropdown).addNewProduct(newProd);
document.getElementById("newProduct").value = "";
}
function updateProductDropdown(newProd){
var newOption = document.createElement('option');
newOption.value = newProd;
newOption.text = newProd;
document.getElementById('product').add(newOption);
}
UPDATE2: App Scripts function to add new value to column in spreadsheet
function addNewProduct(newProd){
var columnLetterToGet, columnNumberToGet, direction, lastRow, lastRowInThisColWithData, rng, rowToSet, startOfSearch, valuesToSet;
var ss = SpreadsheetApp.openById(ssId);
var ws = ss.getSheetByName("List Source - External");
lastRow = ws.getLastRow();
//Logger.log('lastRow: ' + lastRow)
columnNumberToGet = 9;//Edit this and enter the column number
columnLetterToGet = "I";//Edit this and enter the column letter to get
startOfSearch = columnLetterToGet + (lastRow).toString();//Edit and replace with column letter to get
//Logger.log('startOfSearch: ' + startOfSearch)
rng = ws.getRange(startOfSearch);
direction = rng.getNextDataCell(SpreadsheetApp.Direction.UP);//This starts
//the search at the bottom of the sheet and goes up until it finds the
//first cell with a value in it
//Logger.log('Last Cell: ' + direction.getA1Notation())
lastRowInThisColWithData = direction.getRow();
//Logger.log('lastRowInThisColWithData: ' + lastRowInThisColWithData)
rowToSet = lastRowInThisColWithData + 1;
valuesToSet = [newProd];
ws.getRange(rowToSet, 9).setValues([valuesToSet]);
return newProd;
}
SOLUTION to Update Materialize Dropdown
function updateProductDropdown(newProd){
newProdOption = document.getElementById('product');
newProdOption.innerHTML += '<option>' + newProd + '</option>';
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
}
You can specify a client side callback function if you use google.script.run withSuccessHandler(callback) where your callback could update the list only and not the whole site.
Example:
google.script.run.withSuccessHandler(updateDropdownWidget).updateDropdownList(text_from_input)
Where updateDrownList(text_from_input) is a function in your Apps Script that adds text to the sheet using SpreadsheetApp for example, and returns the "text" to the callback function: updateDropdownWidget(text) which adds a new list item to the HTML drop-down list in your front end.
index.html:
<form>
<label for="newOption">New option for the dropdown:</label>
<input type="text" id="nopt" name="newOption">
<input type="button" value="Submit"
onclick="google.script.run.withSuccessHandler(updateDropdownWidget)
.updateDropdownList(document.getElementById('nopt').value)">
</form>
<label for="cars">Choose a car:</label>
<select name="cars" id="cars">
<?!= values; ?>
</select>
<script>
function updateDropdownWidget(text){
var option = document.createElement('option');
option.value = text;
option.text = text;
document.getElementById('cars').add(option);
}
</script>
Code.gs:
function doGet(e){
var ss = SpreadsheetApp.getActiveSheet();
var lastRow = ss.getDataRange().getLastRow();
var values = ss.getRange(1,1,lastRow,1).getValues();
var valuesArray = [];
for (var i = 0; i < values.length; i++){
valuesArray.push('<option value="'+values[i]+'">' +values[i]+ '</option>');
}
var tmp = HtmlService.createTemplateFromFile("index");
tmp.values = valuesArray;
return tmp.evaluate();
}
function updateDropdownList(text_from_input){
// Log the user input to the console
console.log(text_from_input);
// Write it to the sheet below the rest of the options
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getDataRange().getLastRow();
sheet.getRange(lastRow+1,1).setValue(text_from_input);
// Return the value to the callback
return text_from_input;
}
Here's an example:
In my Stack Over Flow spreadsheet I four buttons which can be used to run any function in 3 script files and every time I load the sidebar it reads the functions in those script files and returns them to each of the select boxes next to each button so that I test functions that I write for SO with a single click and I can select any function for any button. Here's the Javascript:
$(function(){//JQuery readystate function
google.script.run
.withSuccessHandler(function(vA){
let idA=["func1","func2","func3","func4"];
idA.forEach(function(id){
updateSelect(vA,id);
});
})
.getProjectFunctionNames();
})
Here is GS:
function getProjectFunctionNames() {
const vfilesA=["ag1","ag2","ag3"];
const scriptId="script id";
const url = "https://script.googleapis.com/v1/projects/" + scriptId + "/content?fields=files(functionSet%2Cname)";
const options = {"method":"get","headers": {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}};
const res = UrlFetchApp.fetch(url, options);
let html=res.getContentText();
//SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), "Project Functions");
let data=JSON.parse(res.getContentText());
let funcList=[];
let files=data.files;
files.forEach(function(Obj){
if(vfilesA.indexOf(Obj.name)!=-1) {
if(Obj.functionSet.values) {
Obj.functionSet.values.forEach(function(fObj){
funcList.push(fObj.name);
});
}
}
});
//SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(funcList.join(', ')), "Project Functions");
return funcList;//returns to withSuccessHandler
}
Image:
Animation:

Get items, changed by current user, via JSOM

In SharePoint 2013 JavaScript, I want to load all items from a list, that have been modified by the current user. I tried this:
var ctx = SP.ClientContext.get_current();
var settings = ctx.get_web().get_lists().getByTitle('My Setting List');
var settingQuery = new SP.CamlQuery();
settingQuery.set_viewXml('<Query><Where><Eq><FieldRef Name="Editor" LookupId="TRUE" /><Value Type="Integer"><UserID /></Value></Eq></Where></Query>');
var settingItems = settings.getItems(settingQuery);
ctx.load(settingItems, 'Include(Id, Title)');
ctx.executeQueryAsync( /* ... */ );
But it gives me all the items from all users. What did I do wrong?
SP.CamlQuery.viewXml Property expects XML schema to be specified in the following format:
<View>
<Query>
...
</Query>
</View>
So, the solution is to enclose your query using View element.
Example
var ctx = SP.ClientContext.get_current();
var list = ctx.get_web().get_lists().getByTitle(listTitle);
var qry = new SP.CamlQuery();
qry.set_viewXml('<View><Query><Where><Eq><FieldRef Name="Editor" LookupId="TRUE" /><Value Type="Integer"><UserID /></Value></Eq></Where></Query></View>');
var items = list.getItems(qry);
ctx.load(items, 'Include(Id, Title)');
ctx.executeQueryAsync(
function() {
console.log(items.get_count());
},
function(sender,args){
console.log(args.get_message());
});

How do I get ID from an SPListItemCollection in javascript?

I have a Sharepoint 2010 list. Each item can have an "related item" in a second list ('extended').
I use the following code to determine if that related item exists or not (using list.getItems).
If it does exist I would like to read the ID of that item (from the "listCollection") and use that to open up the display form for that item. But how do I get the ID of the item from the object in my listCollection?
var listCollection;
function getExtended() {
try {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle('Extended');
var query = '<View Scope=\'RecursiveAll\'>'+
'<Query>'+
'<Where>'+
'<Contains>'+
'<FieldRef Name=\'MainId\'/>' +
'<Value Type=\'Integer\'>' + GetId() +'</Value>'+
'</Contains>'+
'</Where>'+
'</Query>'+
'</View>';
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml(query);
this.listCollection= list.getItems(camlQuery);
context.load(this.listCollection, 'Include(MainId, Status, ID)');
context.executeQueryAsync(Function.createDelegate(this, this.listReceived), Function.createDelegate(this, this.failed));
}
catch (e) {
alert(e);
}
}
function listReceived() {
var count=this.listCollection.get_count();
if (count==0){
$("#extendButton").html("<input type='button' onclick='NewExt()' value='Create new extended'/>");
} else {
$("#extendButton").html("<button>Show extended</button>");
}
}
It's interesting to re-read my question and not be entirely clear what I was asking myself. But the code I used in the end was simply:
var listItemEnumerator = this.listCollection.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
childId= oListItem.get_item('ID');
}
Which at least worked, even if I'm handling the (one-item) list in an overly-complex way.

Undefined function error for javascript function

Here is my code, I don't understand what's wrong.
<script type="text/jquery">
function gettotalAdult()
{
//Assume form with id="fsd-bucket-calc"
var theForm = document.forms["fsd-bucket-calc"];
//Get a reference to the # of Adults & Children
var quantity = theForm.elements["totalAdult"];
var caloriesAdult = theForm.elements["caloriesAdult"];
var adultcalTotal=0;
//If the totalAdult is not blank
if(totalAdult.value!="")
{
adultcalTotal = parseInt(totalAdult.value)*parseInt(caloriesAdult.value);
}
return adultcalTotal;
}
function gettotalChild()
{
//Assume form with id="fsd-bucket-calc"
var theForm = document.forms["fsd-bucket-calc"];
//Get a reference to the # of Children
var totalChild = theForm.elements["totalChild"];
var caloriesChild = theForm.elements["caloriesChild"];
var childcalTotal=0;
//If the totalChild is not blank
if(totalChild.value!="")
{
childcalTotal = parseInt(totalChild.value)*parseInt(caloriesChild.value);
}
return childcalTotal;
}
function gettotalCalories()
{
//Here we get the total calories by calling our function
//Each function returns a number so by calling them we add the values they return together
var totalCalories = gettotalAdult() + gettotalChild();
//display the result
document.getElementById('total-req-cal').innerHTML = "The total required calories are "+totalCalories;
}
</script>
This is my HTML:
<input type="text" name="totalAdult" id="totalAdult" onkeyup="gettotalCalories()" />
This is my error:
gettotalCalories is not defined
If it helps, the script is in the head of a WordPress page. Does anyone see what I'm doing wrong?
You have <script type="text/jquery"> you may need <script type="text/javascript"> instead.

Categories