How can I determine if a Sharepoint ListItem exists based on a couple of known values?

I have this Sharepoint (2010) Javascript (adapted from here) to insert or Update various "fields" in the ListItem:

var listId;

. . .

function upsertPostTravelListItemTravelerInfo1() {
  var clientContext = new SP.ClientContext(siteUrl);
  var oList = clientContext.get_web().get_lists().getByTitle('PostTravelFormFields');

  var itemCreateInfo = new SP.ListItemCreationInformation();
  this.oListItem = oList.addItem(itemCreateInfo);

  listId = this.oListItem.ID;
  oListItem.set_item('ptli_formFilledOut', new Date());
  oListItem.set_item('ptli_TravelersName', $('travelername').val());
    . . .

  oListItem.update();

  clientContext.load(oListItem);

  clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
}

In the code above, the first "upsert" stores the "listId"; subsequent writes into the list (it is to be written piece-by-piece, in case the user stops or something stops them, and they come back to it later) get that previously begin ListItem using the getItemById() method:

function upsertPostTravelListItemTravelerInfo2() {
  var clientContext = new SP.ClientContext(siteUrl);
  var oList = clientContext.get_web().get_lists().getByTitle('PostTravelFormFields');
  this.oListItem = oList.getItemById(listId);

  oListItem.set_item('ptli_tripNumber', $('tripnumber').val());
    . . .

My challenge is in a case where the user wants to update the first bits of data (they insert those, then come back later and decide to change something) in the first of the two methods shown above (upsertPostTravelListItemTravelerInfo1()).

I will need the use getItemById() here, too. When this is the first entry, it doesn't exist yet, and I use:

listId = this.oListItem.ID;

...but when this portion is being updated, will need the listId so I can:

this.oListItem = oList.getItemById(listId);

To do so - to assign the correct value to listId - I will need to interrogate the list to see if the "record" for certain values already exists, and thus there already is a listId; pseudocode:

listId = //a "record" with a username value of "<userName>" and a payeeName of "<payeeName>" with a "Completed" value of "false")
if (listId == null) {
      var itemCreateInfo = new SP.ListItemCreationInformation();
      this.oListItem = oList.addItem(itemCreateInfo);
      listId = this.oListItem.ID;

} else {
      this.oListItem = oList.getItemById(listId);
}

My question is: what do I need to replace that pseudocode with? How is a Sharepoint 2010 ListItem interrogated, query-like, to find a matching "record" for specific ListItem member values?

UPDATE

Based on crclayton's first idea, I'm thinking this:

function upsertPostTravelListItemTravelerInfo1() {
  var clientContext = new SP.ClientContext(siteUrl);
  var oList = clientContext.get_web().get_lists().getByTitle('PostTravelFormFields');

  this.website = context.get_web();
  this.currentUser = website.get_currentUser();

  var itemCreateInfo = new SP.ListItemCreationInformation();
  this.oListItem = oList.addItem(itemCreateInfo);

  var travelersEmail = $('traveleremail').val());

  /* If this is an update, the call to getListItemID() will return a val; otherwise (an insert), get from newly instantiated ListItem.  */
  listId = getListItemID(currentUser, travelersEmail);
  if (listId === '') {
    listId = this.oListItem.ID; 
  }

  oListItem.set_item('ptli_formFilledOut', new Date());
  oListItem.set_item('ptli_TravelersName', $('travelername').val());
  oListItem.set_item('ptli_TravelersEmail', travelersEmail);
  . . .
}

function getListItemID(username, payeename) {
  var arrayListEnum = oList.getEnumerator();

  while (arrayListEnum.moveNext()) {
     var listItem = arrayListEnum.get_current();

     if(listItem.get_item("ptli_formPreparedBy") === username &&
        listItem.get_item("ptli_TravelersEmail") === payeename &&
        listItem.get_item("ptli_formCompleted") == false) {

         return listItem.get_id();    
     }
   }
   return '';
}

...might be the ticket.

UPDATE 2

From the answer, I'm getting an err msg on this line:

var arrayListEnum = oList.getEnumerator();

Namely, "Uncaught TypeError: oList.getEnumerator is not a function"

Is is the case that there's no such function named getEnumerator(), or...???

UPDATE 3

I still get, "Uncaught TypeError: oList.getEnumerator is not a function" with this (modified) code:

function getListItemID(username, payeename, oList) {
    var clientContext = new SP.ClientContext.get_current();
    var listItems = oList.getItems("");
    clientContext.load(listItems);
    clientContext.executeQueryAsync(function () {

        var arrayListEnum = oList.getEnumerator();

        while (arrayListEnum.moveNext()) {
            var listItem = arrayListEnum.get_current();

            if (listItem.get_item("userName") === "<userName>" &&
        listItem.get_item("payeeName") === "<payeeName>" &&
        listItem.get_item("Completed") == false) {

                return listItem.get_id();
            }
        }
        return '';
    });
}

I'm calling it this way:

function upsertPostTravelListItemTravelerInfo1() {
    var clientContext = SP.ClientContext.get_current();
    var oList = clientContext.get_web().get_lists().getByTitle('PostTravelFormFields');

    this.website = clientContext.get_web();
    currentUser = website.get_currentUser();

    var itemCreateInfo = new SP.ListItemCreationInformation();
    this.oListItem = oList.addItem(itemCreateInfo);

    var travelersEmail = $('traveleremail').val();

    /* If this is an update, the call to getListItemID() will return a val; otherwise (an insert), get from newly instantiated ListItem.  */
    listId = getListItemID(currentUser, travelersEmail, oList);
    if (listId === '') {
        listId = this.oListItem.ID;
    }

So is getEnumerator() a valid function or not? If yes, what am I doing wrong? If not, what can I use in its stead?

Upvotes: 3

Views: 7334

Answers (2)

Charles Clayton
Charles Clayton

Reputation: 17946

It might not be a query-like as you'd like, but what about something like:

 var clientContext = new SP.ClientContext.get_current();
 var listItems = oList.getItems("");
 clientContext.load(listItems);
 clientContext.executeQueryAsync(function(){

     var arrayListEnum = listItems.getEnumerator();

     while (arrayListEnum.moveNext()) {
         var listItem = arrayListEnum.get_current();

         if(listItem.get_item("userName") === "<userName>" &&
            listItem.get_item("payeeName") === "<payeeName>" &&
            listItem.get_item("Completed") == false) {

                return listItem.get_id();    
         }
     }
 });

Or you can use CAML query like so:

 var query = new SP.CamlQuery();
 query.set_viewXml("<View><Query><Where><Contains><FieldRef Name='userName'/>" +
                    "<Value Type='Text'>userName</Value></Contains></Where></Query>" + 
                    "</View>");
 listItems = oList.getItems(query);

 clientContext.load(listItems);
 clientContext.executeQueryAsync(onQuerySucceeded, function(){Alert("not found");});

 ...

 function onQuerySucceeded() {
    var listEnumerator = listItems.getEnumerator();
    while (listEnumerator.moveNext()) {
        console.log(listEnumerator.get_current().get_id());
    }  
 }

Upvotes: 3

WhiteHat
WhiteHat

Reputation: 61222

CRUD example using REST
as requested using SharePoint 2010

The beauty of a RESTful service --> everything happens over HTTP

Thus, you can use pure JavaScript via XMLHttpRequest

or JQuery via $.ajax

or MicrosoftAjax.js via Sys.Net.WebRequest
as this example demonstrates, since it is already available in a SharePoint 2010 web part

// test rest on SharePoint 2010
testREST();

function testREST() {
  /*
  **  List name: Test List (collapse spaces)
  **  Find list item - Set query in url --> ListName?$filter=
  **  Or access by list item id --> ListName(id)
  */
  invokeRequest({
    // make GET request with url query
    // REST also allows expansion of lookup fields
    //  --  here, i check `ModifiedBy` for `[Me]`
    'url': "TestList?$filter=" +
           "TextColumn eq 'row 1' and " +
           "NumberColumn lt 3 and " +
           "ModifiedById eq " + _spPageContextInfo.userId,

    // GET request
    'verb': "GET",

    // not needed for GET requests
    'body': null,
    'match': null,
    'method': null,

    // on complete
    'success': function (jsonObj) {
      // check the results of our query, returned in array: jsonObj.d.results
      // fyi -- if id used -- ListName(id) -- no array, one object: jsonObj.d
      if (jsonObj.d.results.length === 0) {
        // nothing found, insert new item
        insertItem();
      } else {
        // check field for _first_ item returned -- NumberColumn
        if (jsonObj.d.results[0].NumberColumn < 2) {
          // update if less than 2
          updateItem(jsonObj.d.results[0]);
        } else {
          // delete if greater than or equal to 2
          deleteItem(jsonObj.d.results[0]);
        }
      }
    },
    'fail': function (errCode, errMessage) {
      console.log(errCode + ' = ' + errMessage);
    },
  });
}

function insertItem() {
  /*
  **  List name: Test List
  **  Insert list item
  */
  invokeRequest({
    // make POST request for insert
    'url': "TestList",
    'verb': "POST",

    // use MicrosoftAjax.js to serialize our new list item
    'body': Sys.Serialization.JavaScriptSerializer.serialize({
      // set a key: value according to the column names in the list
      Title: "TEST",
      TextColumn: "row 1",
      EmployeeId: _spPageContextInfo.userId,
      NumberColumn: 1,
      DateColumn: new Date()
    }),

    // new item -- match & method not needed
    'match': null,
    'method': null,

    // on complete
    'success': function (jsonObj) {
      // print new list item to console
      var s = '';
      for (var key in jsonObj.d) {
        if (jsonObj.d.hasOwnProperty(key)) {
          s += key + ' = ' + jsonObj.d[key] + '\n';
        }
      }
      console.log('new list item\n' + s);
    },
    'fail': function (errCode, errMessage) {
      console.log(errCode + ' = ' + errMessage);
    },
  });
}

function updateItem(listItem) {
  /*
  **  List name: Test List
  **  Update list item
  */
  invokeRequest({
    // make POST request for insert -- set ID on url
    'url': "TestList(" + listItem.Id + ")",
    'verb': "POST",

    // serialize our updates -- literal w/ field name keys
    'body': Sys.Serialization.JavaScriptSerializer.serialize({
      Title: listItem.TextColumn + " test",
      NumberColumn: Number(listItem.NumberColumn) + 1
    }),

    // send the -- etag match -- for our update
    'match': listItem.__metadata.etag,

    // MERGE allows updates to one or more fields
    'method': "MERGE",

    // on complete
    'success': function (jsonObj) {
      // print request body -- _updated fields_ -- to console
      var newFields = Sys.Serialization.JavaScriptSerializer.deserialize(jsonObj.body);
      var s = '';
      for (var key in newFields) {
        if (newFields.hasOwnProperty(key)) {
          s += key + ' = ' + newFields[key] + '\n';
        }
      }
      console.log('updated list item\n' + s);
    },
    'fail': function (errCode, errMessage) {
      console.log(errCode + ' = ' + errMessage);
    },
  });
}

function deleteItem(listItem) {
  /*
  **  List name: Test List
  **  Delete list item
  */
  invokeRequest({
    // make POST request for delete -- set ID on url
    'url': "TestList(" + listItem.Id + ")",
    'verb': "POST",

    // no body needed for delete
    'body': null,

    // send the match for delete method
    'match': listItem.__metadata.etag,
    'method': "DELETE",

    // on complete
    'success': function (jsonObj) {
      // print request url for delete request
      console.log('deleted list item request\n' + jsonObj.url);
    },
    'fail': function (errCode, errMessage) {
      console.log(errCode + ' = ' + errMessage);
    },
  });
}

// invoke web request using [MicrosoftAjax.js](https://msdn.microsoft.com/en-us/library/vstudio/bb397536(v=vs.100).aspx)
function invokeRequest(requestObj) {
  // new web request
  var webRequest = new Sys.Net.WebRequest();

  // set request headers
  webRequest.get_headers()['Cache-Control'] = 'no-cache';
  webRequest.get_headers()['Accept'] = 'application/json';
  webRequest.get_headers()['Content-Type'] = 'application/json';

  // set etag match
  if (requestObj.match !== null) {
    webRequest.get_headers()['If-Match'] = requestObj.match;
  }

  // set method
  if (requestObj.method !== null) {
    webRequest.get_headers()['X-HTTP-Method'] = requestObj.method;
  }

  // set request verb
  webRequest.set_httpVerb(requestObj.verb);

  // set request body
  if (requestObj.body !== null) {
    webRequest.set_body(requestObj.body);
  }

  // set request url
  webRequest.set_url(
    _spPageContextInfo.webServerRelativeUrl + '/_vti_bin/ListData.svc/' + requestObj.url
  );

  // set user context
  webRequest.set_userContext(requestObj);

  // set completed callback and invoke request
  webRequest.add_completed(serviceComplete);
  webRequest.invoke();
}

// process web request
function serviceComplete(executor, args) {
  // check response
  if (executor.get_responseAvailable()) {
    // check status
    switch (executor.get_statusCode()) {
      case 200:   // OK
      case 201:   // Created
        // raise success callback - pass list item
        executor.get_webRequest().get_userContext().success(
          executor.get_object()
        );
        break;

      case 202:   // Accepted
      case 203:   // Non auth info
      case 204:   // No content
      case 205:   // Reset
      case 206:   // Partial
      case 1223:  // No content (SP)
        // raise success callback - pass original request object
        executor.get_webRequest().get_userContext().success(
          executor.get_webRequest().get_userContext()
        );
        break;

      // Error
      default:
        // raise fail callback - pass status
        executor.get_webRequest().get_userContext().fail(
          executor.get_statusCode(),
          executor.get_statusText()
        );
    }
  } else {
    // check timeout
    if (executor.get_timedOut()) {
      executor.get_webRequest().get_userContext().fail(408,'Request Timeout');
    } else {
      // check abort
      if (executor.get_aborted()) {
        executor.get_webRequest().get_userContext().fail(800,'Request Aborted');
      } else {
        executor.get_webRequest().get_userContext().fail(801,'Unknown Error');
      }
    }
  }
}

more on naming conventions in SharePoint 2010
more on spPageContextInfo

Upvotes: 1

Related Questions