10
votes

We're using the Sharepoint 2013 REST API to get all news items from the Sharepoint. We made a custom ContentType 'Newsitem' with several properties including a Publishing Image Field.

  var contentTypeId = "0x01100018B03AC7E8312648AEA00851DEDBCAF802";
  var standardUri = "https://examplesite.com/blog/_api/lists/getbytitle('Messages')/items?$top=7&$filter=startswith(ContentTypeId,'" + contentTypeId + "')";
  var selectiveUri = "https://examplesite.com/blog/_api/lists/getbytitle('Messages')/items?$top=7&$filter=startswith(ContentTypeId,'" + contentTypeId + "')&$Select=Title,Teaser,Body,ShowAt,TeaserImg";

Using standardUri for my REST call, I retrieve all properties but no TeaserImg. Explicitly selecting TeaserImg makes the call fail of course.

Why can't I find the TeaserImg, isn't this possible with Sharepoint 2013 REST Api and should I use CSOM instead?

4
Has anyone thought of a way to add a calculated field that calculates the string URL of the Publishing Image? Then expose that calculated field to the REST API?jmbmage

4 Answers

14
votes

It does not seem possible to retrieve Publishing Image fields using List Item Collection endpoint.

There is a workaround, publishing fields could be retrieved using ListItem.FieldValuesAsHtml property via SharePoint REST endpoint as demonstrated below

Limitation: it requires to perform two requests.

How to retrieve Publishing fields using SharePoint 2013 REST

function getJson(endpointUri, success, error) 
{    
    $.ajax({       
       url: endpointUri,   
       type: "GET",   
       processData: false,  
       contentType: "application/json;odata=verbose",
       headers: {   
          "Accept": "application/json;odata=verbose"
       }, 
       success: success,
       error: error
    });
}


function getPublishingPage(webUrl,listName,listItemId,publishingProperties, success, failure) 
{
    var itemUri =  webUrl + "/_api/web/lists/getbytitle('" + listName + "')/items(" + listItemId + ")";  
    getJson(itemUri,
       function(data){
           var pageItem = data.d;

           var selectProperties = [];  
           for(var idx in publishingProperties){
               if(!pageItem.hasOwnProperty(publishingProperties[idx])){
                   selectProperties.push(publishingProperties[idx]);
               }
           }
           if(selectProperties.length > 0) {
              //construct an additional query 
              var query = '/FieldValuesAsHtml?$select=' + selectProperties.join(',');
              var endpointUri = pageItem['__metadata'].uri + query;
              getJson(endpointUri,
                 function(data){
                    for(var property in data.d){
                       if(property == "__metadata") continue; 
                       pageItem[property] = data.d[property];   
                    }
                    success(pageItem);  
                 },
                 failure);
           } 
           else {
              success(pageItem);
           }   
        },
       failure);
}

Usage

The following example demonstrates how to retrieve page fields including publishing fields, such as PublishingRollupImage:

getPublishingPage(_spPageContextInfo.webAbsoluteUrl,'Pages',3,['PublishingRollupImage','PublishingPageImage'],printPageDetails,logError);

function printPageDetails(pageItem)
{
    console.log('Page Content: ' + pageItem.PublishingPageContent);
    console.log('Page Title: ' + pageItem.Title);
    console.log('Page Rollup Image ' + pageItem.PublishingRollupImage);
}

function logError(error){
    console.log(JSON.stringify(error));
}

Probably the best solution here would be to utilize CSOM

function getListItems(listTitle,success,error)
{
   var ctx = SP.ClientContext.get_current();
   var list = ctx.get_web().get_lists().getByTitle(listTitle);
   var items = list.getItems(SP.CamlQuery.createAllItemsQuery());
   ctx.load(items);
   ctx.executeQueryAsync(function() {
       success(items);
   },error);
}



getListItems('Pages',printPageItemsDetails,logError);

function printPageItemsDetails(pageItems)
{
    for(var i = 0; i < pageItems.get_count();i++) {
        var pageItem = pageItems.getItemAtIndex(i);
        console.log(pageItem.get_fieldValues()['PublishingPageContent']);
        console.log(pageItem.get_fieldValues()['PublishingRollupImage']);
    }
}
6
votes

Unfortunately, the Publishing Image field is not technically returnable via REST (at least, according to this article).

However I found (using the Advanced REST client) that you can actually retrieve the html for the Publishing Image field by making two requests. One to retrieve the list item for which you are attempting to get the Publishing Image, and another to retrieve the Publishing Image html via the FieldValuesAsHtml property of the returned results.

getPublishingImage(listname, id){
    var publishingImage = '';

    $.ajax({
        url:        _spPageContextInfowebroot.webAbsoluteUrl + '/_api/web/lists/getbytitle(\'' + listname + '\')/items(' + id + ')',
        method:     'GET',
        headers:    {
            Accept:     'application/json; odata=verbose'
        },
        success:    function(data, request){
            // List item retrieved. Fetch the Publishing Image.
            var publishingImageUri = data.d.0.FieldValuesAsHtml.__deferred.uri;

            // Query SharePoint
            $.ajax({
                url:        publishingImageUri,
                method:     'GET',
                headers:    {
                    Accept:     'application/json; odata=verbose'
                },
                success:    function(data, request){
                    publishingImage = data.d.Image;
                }
            });
        }
    });

    // Return the Publishing Image html
    return publishingImage;
};

While not ideal, at least with the html you can use jQuery or another method to extract the image uri from the html element. Or you can simply insert the element as is into the DOM.

Hope this helps!

0
votes
function LoadArticle(item) {
  return GetPublishingPageImage(item, ["DCCAIContentImage"]).then(function(
    pub
  ) {
    for (var property in pub.d) {
      if (property == "__metadata") continue;
      item.DCCAIContentImage(pub.d[property]);
    }
  });
}

function GetPublishingPageImage(curItem, publishingProperties) {
  var query = "/FieldValuesAsHtml?$select=" + publishingProperties;

  //debugger;
  var endpointUri = curItem["__metadata"].uri + query;
  //      var endpointUri = curItem.__metadata().uri + query;

  return $.ajax({
    url: endpointUri,
    type: "GET",
    processData: false,
    contentType: "application/json;odata=verbose",
    headers: {
      Accept: "application/json;odata=verbose"
    }
  }).then(function(response) {
    return response;
  });
}
0
votes

I found a way to get all data in a single call: use the RenderListDataAsStream POST REST call:

this._webAbsoluteUrl +
"/_api/web/GetList(@listUrl)/RenderListDataAsStream?
@listUrl=%27%2Fsites%2F<scName>%2Flists%2F<listUrlName>%27";

It gives all simple text field data, can be used for more complex fields such as managed metadata & lookup fields, but more importantly in this case, it gives you the url of the image that was used for the Publishing Image column.

You do need to parse it from this structure:

"<div dir="" class="ms-rtestate-field"><img alt="" src="/sites/<scName>/SiteAssets/<myImageOnSharepoint>.jpg" style="BORDER&#58;0px solid;" /></div>"

Code sample (SPFx with TypeScript):

const requestHeaders: Headers = new Headers();
requestHeaders.append("Content-type", "application/json");
requestHeaders.append("Accept", "application/json");

var body =
{ parameters:
  {
    DatesInUtc: "true"
  }
};

const httpClientOptions: IHttpClientOptions = {
  body: JSON.stringify(body),
  headers: requestHeaders
};
const queryUrlGetAllItems: string =
  this._webAbsoluteUrl +
  `/_api/web/GetList(@listUrl)/RenderListDataAsStream?@listUrl=%27%2Fsites%2F<scName>%2Flists%2F<listUrlName>%27`;

return this._webPartContext.spHttpClient
  .post(queryUrlGetAllItems, SPHttpClient.configurations.v1, httpClientOptions)
  .then((response: any) => {
    if (response.status >= 200 && response.status < 300) {
      return response.json();
    } else {
      return Promise.reject(new Error(JSON.stringify(response)));
    }
  })
  .then((data: any) => {
    if (data) {
      for (let i = 0; i < data.Row.length; i++) {
        let item = data.Row[i];
        // ... process data
      }
    }
    // ... return value
  });