0

I have an Angular 2+ application that happily execute calls via REST API to a SharePoint 2013 hosted in a different server. It works quite good but unfortunately for a very specific need (discussion boards) it's not enough. Here what I am doing:

async addMessageREST(callback, siteUrl, discussionBoardName, parentItemId, newMessageBody) {

    const requestOptions = {
      withCredentials: true,
      crossDomain: true
    };

    var messagePayload = {
      // '__metadata': { "type": "SP.Data.DiscussionsListItem" },
      'Body': newMessageBody,  
      'ParentItemID': parentItemId, //unfortunately will be ignored
      'FileSystemObjectType': 0,
      'ContentTypeId': '0x0107008822E9328717EB48B3B665EE2266388E'
    };

    // retrieve the contextinfo
    let contextinfo = await this._http
    .post(
          siteUrl + '/_api/contextinfo',
          null,
          requestOptions
    )
    .toPromise();

    // finally post the request
    const requestOptionsAddMessage = {
    withCredentials: true,
    crossDomain: true,
    headers: new HttpHeaders().set('X-RequestDigest', contextinfo["FormDigestValue"]).set("Accept", "application/json;odata=verbose")
    };

    let request = "/_api/web/Lists/GetByTitle('" + discussionBoardName + "')/items";


    let discussionItem = await this._http
    .post(
    siteUrl + request,
    messagePayload,
    requestOptionsAllMessages
  )
  .toPromise();

callback(discussionItem);
}

Technically this works fine, but unfortunately it's not enough because as you may know REST API doesn't offer specific functionalities to manage discussions items. For this JSOM provide quite good methods, but unfortunately I am not able to establish a connection with it (I get a 401 error). Here what I am doing:

addMessageJSOM(callback, siteUrl, discussionBoardName, parentTopicId, newMessageBody) {

    let clientContext = new SP.ClientContext(siteUrl);

    let list = clientContext.get_web().get_lists().getByTitle(discussionBoardName);
    
    let discussionItem = list.getItemById(parentTopicId);

    let properties = {
       'Body': newMessageBody
    };

    let messageItem = SP.Utilities.Utility.createNewDiscussionReply(clientContext, discussionItem);

    for (var propName in properties) {
      messageItem.set_item(propName, properties[propName])
    }
    messageItem.update();

    clientContext.executeQueryAsync(() => {
      callback(messageItem);
    }, (error: any) => {
        console.log('Request failed', error);
    });

}

All works good, until it comes to the executeQueryAsync, and I get the said 401 error. I suppose it's because somehow I am not passing the digest/the options that I am passing via HTTP in the REST Call. Any idea how I could pass these options via JSOM? Alternatively, there is a way to call the JSOM endpoint via HTTP without relying on the SP libraries?

Thanks in advance for your reading until here!

Dan
  • 1

2 Answers2

0

can you change this below line so that parent item id wont be ignored

let request = "/_api/web/Lists/GetByTitle('" + discussionBoardName + "')/items(" + parentItemId + ")" ;
  • The problem is that I want to set the parentId, but apparently specifically for discussion lists that's a read-only field that can't be set in any way through REST calls – Dan Feb 01 '21 at 11:11
0

JSOM must rely on SP libraries. If you want to create discussion item via Rest API, you may take a reference of below demo:

function executeJson(options) {
    var headers = options.headers || {};
    var method = options.method || "GET";
    headers["Accept"] = "application/json;odata=verbose";
    if (options.method == "POST") {
        headers["X-RequestDigest"] = $("#__REQUESTDIGEST").val();
    }

    var ajaxOptions =
    {
        url: options.url,
        type: method,
        contentType: "application/json;odata=verbose",
        headers: headers
    };
    if ("data" in options) {
        ajaxOptions.data = JSON.stringify(options.data);
    }

    return $.ajax(ajaxOptions);
}


function createListItem(webUrl, listTitle, payload) {
    var url = webUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/items";
    return executeJson({
        "url": url,
        "method": 'POST',
        "data": payload
    });
}

function moveListItem(webUrl, listTitle, itemId, folderUrl) {
    var url = webUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/getItemById(" + itemId + ")?$select=FileDirRef,FileRef";
    return executeJson({
        "url": url
    })
        .then(function (result) {
            var fileUrl = result.d.FileRef;
            var fileDirRef = result.d.FileDirRef;
            var moveFileUrl = fileUrl.replace(fileDirRef, folderUrl);
            var url = webUrl + "/_api/web/getfilebyserverrelativeurl('" + fileUrl + "')/moveto(newurl='" + moveFileUrl + "',flags=1)";
            return executeJson({
                "url": url,
                "method": 'POST'
            });
        });
}


function getParentTopic(webUrl, listTitle, itemId) {
    var url = webUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/getItemById(" + itemId + ")/Folder";
    return executeJson({
        "url": url,
    });
}


function createNewDiscussionReply(webUrl, listTitle, messagePayload) {
    var topicUrl = null;
    return getParentTopic(webUrl, listTitle, messagePayload.ParentItemID)
        .then(function (result) {
            topicUrl = result.d.ServerRelativeUrl;
            return createListItem(webUrl, listTitle, messagePayload);
        })
        .then(function (result) {
            var itemId = result.d.Id;
            return moveListItem(webUrl, listTitle, itemId, topicUrl);
        });
}

$(function () {
    // Handler for .ready() called.

    var listTitle = "discuss";
    var webUrl = _spPageContextInfo.webAbsoluteUrl;
    var messagePayload = {
        '__metadata': { "type": "SP.Data.DiscussListItem" },  //set DiscussionBoard entity type name
        'Body': "Thanks for the information",  //message Body
        'FileSystemObjectType': 0, //setto 0 to make sure Mesage Item
        'ContentTypeId': '0x0107008822E9328717EB48B3B665EE2266388E', //set Message content type
        'ParentItemID': 1  //set Discussion (topic) Id
    };

    createNewDiscussionReply(webUrl, listTitle, messagePayload)
        .done(function (item) {
            console.log('Message(reply) has been sent');
        })
        .fail(function (error) {
            console.log(JSON.stringify(error));
        });

});

More references:

BR

Baker_Kong
  • 1,739
  • 1
  • 4
  • 9
  • Thanks for your comment, I will give a try to it. I actually already saw the link you proposed, but it has a comment that comes often out when one try to create a discussion via REST API: "While this appears to work (the reply shows up in the discussion thread of the parent post) it does not set the ParentItemID property on the reply, it remains null which breaks some of the features of discussions. See this article for why: REST api support for discussion list". Still your solution looks slightly different (in particular for how the payload is managed). I will check if it works. – Dan Feb 01 '21 at 07:48
  • unfortunately for me is the same outcome, ParentId is not set in this way, and even if you are able to change the folder of the item, without ParentId the threading funcionality is lost. – Dan Feb 01 '21 at 11:10