6

Do you have any tips how can I create a new folder in a document library using listdata.svc (OData REST interface of SharePoint 2010) from JavaScript? SP creates a new file instead of a folder. I can create list items over OData without any problems, but this folder thing isn't documented at all. Thank you for your advices in advance.

I have an image gallery with folder creation enabled.

I tried to set the Path, ContentType (0x01010200B9CF3E8350E8024CB9921FDE096B5ACF), ContentTypeID fields of the new entity and added the slug request header, but it creates a file every time.

I can add list items in custom lists, but not a folder to document library.

1
  • If you are able to get files uploaded, could you please respond to the question I posted on my answer? Jun 19, 2013 at 16:25

6 Answers 6

11

This took forever to figure out, but of course it is simple once you got it.

Instead of pasting a bunch of code, here is the context and then the raw HTTP POST request that I ended up with.

The documentation is actually right here: http://msdn.microsoft.com/en-us/library/dd962796(v=office.12).aspx

Syntax for the slug header is as following:

/<LIST_PATH>/<FOLDERS>|<FOLDER_CONTENT_TYPE_ID>

So here is my SharePoint setup.

Document Library = "My Docs" (the Library Title)

  • Short Form: "MyDocs" (used by ListData.svc)

  • Path: "Docs" (used for slug and Path)

    The folder I want to create is "Folder 2" inside "Folder 1" (i.e. /Folder 1/Folder 2)

    URL:

    http://www.somewhere.com/_vti_bin/listdata.svc/MyDocs
    

    Method:

    POST
    

    header:

    slug: /Docs/Folder 1/Folder 2|0x01200093331D3790C54144AC10D65D164227C0
    

    body:

    {
      "ContentTypeID" : "0x01200093331D3790C54144AC10D65D164227C0",
      "ContentType" : "Folder",
      "Title" : "Folder 2",
      "Path" : "/Docs/Folder 1"
    }
    
  • 3
    • I wish I had more upvotes to give! Awesome work! Mar 20, 2014 at 1:05
    • 1
      This should be the accepted answer--even though a while later it would be useful for later on; just saved me some SOAP headaches, thanks!
      – Jeff
      Mar 26, 2014 at 19:00
    • Thank you for the post. Really helped me out with a PowerShell script. Aug 26, 2016 at 22:40
    1

    Have you tried this approach:

    //Create Folder name MyFolder inside a doc library MyLib
    //Reference to Lists.asmx proxy
    ListsWebService.Lists listWebService = new ListsWebService.Lists();
    string xmlCommand;
    XmlDocument doc = new XmlDocument();
    xmlCommand = "<Method ID='1' Cmd='New'><Field Name='FSObjType'>1</Field><Field Name='BaseName'>MyFolder</Field> 
    <Field Name='ID'>New</Field>
    </Method>";
    XmlElement ele = doc.CreateElement("Batch");
    ele.SetAttribute("OnError", "Continue");
    ele.InnerXml = xmlCommand;
    listWebService.Credentials = System.Net.CredentialCache.DefaultCredentials;
    XmlNode node1 = listWebService.UpdateListItems("MyLib", ele);
    

    from here

    1
    • Thank you Robert! Unfortunately this isn't the OData-capable listdata.svc, but the soap interface of SP.
      – Robesz
      Jun 20, 2013 at 6:57
    1

    I have never been able to get this to work with the ListData.svc. I always get errors regarding slug headers or something else. For example sending a post to the Shared Documents URL with the following payload:

    {
       "ContentTypeID":"0x012000BBD736485259BF4582A1FE518D692108",
       "Name":"TestFolder2",
       "Title":"TestFolder2",
       "ContentType":"Folder"
    }
    

    Returns this error:

    {
       "error":{
          "code":"",
          "message":{
             "lang":"en-US",
             "value":"Invalid slug header for BLOBs. Slug headers must be server- or web-relative URL of the file. Server-relative URLs begins with a forward slash (\"/\")."
          }
       }
    }
    

    But since you are working in JavaScript you can do this easily using the Client Object Model:

    clientcontext = new SP.ClientContext.get_current();
    web = clientcontext.get_web();
    this.list = web.get_lists().getByTitle("LibraryName");
    var listItemCreationInfo = new SP.ListItemCreationInformation();
    listItemCreationInfo.set_underlyingObjectType(SP.FileSystemObjectType.folder);
    

    Code snip stolen from SharePointKings.

    If you can workout the slug headers and get this working, please post your findings. I gave up when trying to figure out how to add an attachment via ListData.svc.

    StackOverflow: https://stackoverflow.com/questions/17005819/how-to-use-the-html5-js-file-upload-api-to-upload-a-file-to-odata-service

    SP StackExchange: ListData.svc: How to upload attachment?

    Any project I do that uses ListData I always end up doing in a hybrid approach with JSOM. Some things are simpler using ListData others are easier using JSOM...

    6
    • I used the same payload before, had the same slug header issue, but I added it to the request header. Which caused an other error message, but I added "slug" to the list of iis allowed headers and the content was created...but as a file, just like I told in the question.
      – Robesz
      Jun 20, 2013 at 7:01
    • About your client object model snippet - I've never tried COM... I'm running my JavaScript file from mobile and external website from different domain. Is this available in this scenario or only for SharePoint-hosted pages?
      – Robesz
      Jun 20, 2013 at 7:11
    • No, you would need to have access to SP.js and some other files as well as access to a hidden input called __REQUESTDIGEST used by the JSOM... I will be looking at this again this weekend, though, since you have provided me with some important details. Jun 21, 2013 at 16:20
    • Great, thanks! I left the office, but I check your solution on Monday, I'm very excited!
      – Robesz
      Jun 21, 2013 at 17:11
    • I didn't succeed with JavaScript Object Model in a cross-domain setup, although I made a workaround that would be useful for others, too. We upload the files with metadata including the desired parent path and move the file from the temp directory to the folder passed as a metadata. Thanks for all your efforts, I really appreciate!
      – Robesz
      Jun 27, 2013 at 12:29
    0

    I choosed to upload a document with metadata containing the parent folder and create the containing folder with a workflow. I have total control over the IIS of the SP 2010 foundation, so I was able to allow all the necessary request headers and domains to work in a cross-domain environment with basic auth (over https). I have a HTML5 client app with JayData library to consume the OData endpoint of SP (listdata.svc)

    <script src="scripts/jquery-1.9.1.min.js"></script>
    <script src="scripts/datajs-1.0.3.js"></script>
    <script src="scripts/jaydata.js"></script>
    
    
    var ctx = new MyPreGeneratedContext({
        name: 'oData',
        oDataServiceHost: 'https://mysharepoint.com/_vti_bin/listdata.svc',
        user: 'user',
        password: 'pass'
    });
    
    ctx.onReady(function () {
    
    var uploadFile = function (path, data, callback) {
        var request = {
            requestUri: ctx.storageProvider.providerConfiguration.oDataServiceHost + '/MyDestinationDocLibrary',
            method: 'POST',
            headers: {
                slug: path
            },
            body: data
        }
        ctx.storageProvider.appendBasicAuth(request, ctx.storageProvider.providerConfiguration.user, ctx.storageProvider.providerConfiguration.password);
    
        OData.request(request, function (resdata, response) {
    
            var entity = new ctx.MyDestinationDocLibrary.elementType(resdata, {
                converters: $data.oDataConverter.fromDb
            });
    
            callback(entity);
    
        },
        function () { alert(JSON.stringify(arguments)) });
    }
    
    uploadFile('/MyDestinationDocLibrary/testdoc.txt', 'filecontent', function (newFile) {
            console.log(newFolder.Owshiddenversion);
            ctx.MyDestinationDocLibrary.attach(newFile);
            newFile.ParentPath = 'Custom folder processed by the workflow";
            ctx.saveChanges({success: $data.debug, error: $data.debug});
        });
    
    });
    

    I guess this isn't the most elegant solution but this was the only one working in my scenario.

    0

    As Tommy pointed out in his answer and according to 3.1.4.3 Document:

    Inserting new documents to a document library involve sending a POST request containing the contents of the document to the EntitySet representing the document library. The protocol client MUST include the SLUG header (as specified in RFC5023 section 9.7) whose value is the name of the file that is being created in their POST requests.

    How to create Folder via REST in SharePoint 2010 using JavaScript

    function createFolder(webUrl,listName,folderName,folderPath, success, failure) {
    
        var folderPayload = {
          'ContentType': 'Folder',
          'Title' : folderName,
          'Path' : folderPath
        };
    
        $.ajax({
            url: webUrl + "/_vti_bin/listdata.svc/" + listName,
            type: "POST",
            contentType: "application/json;odata=verbose",
            data: JSON.stringify(folderPayload),
            headers: {
                "Accept": "application/json;odata=verbose",
                "Slug": folderPath + "/" + folderName + "|0x0120" 
            },
            success: function (data) {
                success(data.d);
            },
            error: function (data) {
                failure(data.responseJSON.error);
            }
        });
    }
    

    Examples:

    1 Create root folder named Orders in the Documents library

    createFolder('https://intranet.contoso.com','Documents','Orders', '/Shared Documents',function(folder){
        console.log('Folder ' + folder.Name + ' has been created succesfully'); 
      },
      function(error){
        console.log(JSON.stringify(error));
      }
    ); 
    

    2 Create sub folder named 2014 under the folder Orders in the Documents library

    createFolder('https://intranet.contoso.com','Documents','2014', '/Shared Documents/Orders',function(folder){
        console.log('Folder ' + folder.Name + ' has been created succesfully'); 
      },
      function(error){
        console.log(JSON.stringify(error));
      }
    ); 
    
    0

    to get the content ID and the path , do first a Get request to 'http://XXXXX/_vti_bin/listdata.svc/xxxDoclibarynamexxxx'

    when i used values there it worked with me , i am using angular/typescript.

     Createfolder (folder: any) {
          const httpOptions2 = {
            headers: new HttpHeaders({
              'Accept':  'application/json',
              'Content-Type':  'application/json',
              'slug': '/' + folder + '|0x012000D2279CFA950BFF4BAC86C1005F1B40FC'
            })
          };
          const body = {
           'ContentTypeID' : '0x012000D2279CFA950BFF4BAC86C1005F1B40FC',
           'ContentType' : 'Folder',
            'Title' : folder,
            'Path' : '/',
             'Name' : folder
          };
          const url = 'http://XXXXX/_vti_bin/listdata.svc/xxxDoclibarynamexxxx';
    
          return this.http.post(url , body, httpOptions2 );
          }
    

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

    Not the answer you're looking for? Browse other questions tagged or ask your own question.