Tags

, , ,

Moving files inside a document library can be a requirements coming from the customer. Luckily, JavaScript is offering a simple solution, without going into server side development. I will describe below how this can be done and try to explain my code as much as possible.

First thing I did was to create a sort of reusable code and as always I created a namespace and add reference for Visual Studio auto-completion.

/// <Reference Name="MicrosoftAjax.js" />
/// <Reference Name="MicrosoftAjaxWebForms" /> 
Type.registerNamespace("Shp");

One of the limitations of JavaScript client object model is it cannot be synchronous. This means I need to create a lot of callback functions for complex operations. But my idea was to load main information on start-up and store it in a configuration class to be used later.

Shp.Info = function () {
    /// <summary>Static class which contains information about web and lists.</summary>
}

Shp.Info.context = null;
Shp.Info.web = null;
Shp.Info.lists = null;

Shp.Info.Initialize = function (callback, arguments) {
    /// <summary>Initialize Shp.Info class.</summary>
    var _cArgs = (typeof (arguments) === "undefined") ? ([]) : (arguments);
    Shp.Info.context = SP.ClientContext.get_current();
    Shp.Info.web = Shp.Info.context.get_web();
    var webLists = Shp.Info.web.get_lists();
    Shp.Info.context.load(webLists);

    var fail = function (args, message) {
        alert('Cannot get web information: ' + args.get_message() + '\n' + args.get_stackTrace());
    };

    var success = function () {
        Shp.Info.lists = webLists.$2_1;
        if ((typeof (callback) !== "undefined") && (callback !== null)) callback.apply(null, _cArgs);
    };

    Shp.Info.context.executeQueryAsync(success, fail);
}

Shp.Info._get_documentLibrary = function (docLibName) {
    /// <summary>Get document library from initalized web (internal use).</summary>

    for (var i = 0; i < Shp.Info.lists.length; i++) {
        if ((Shp.Info.lists[i].get_baseType() === 1) && (Shp.Info.lists[i].get_title() === docLibName)) {
            return Shp.Info.lists[i];
        }
    }
    return null;
}

Shp.Info.registerClass("Shp.Info");

What I am suggesting is to initialize configuration class on page load event, before making any other operation on SharePoint.

function pageLoad() {
    var loadNotification = SP.UI.Notify.addNotification("Please wait until system is fully loaded.", true);
    Shp.Info.Initialize(function () {
        SP.UI.Notify.removeNotification(loadNotification);
    });
}

For move files operation I have created a separate class:

Shp.ListItemsOps = function () {
    /// <summary>SharePoint ListItemsOps custom static class.</summary>
}


Shp.ListItemsOps.moveFileById = function (sourceDocLibName, fileid, destinationurl, callback) {
    /// <summary>Get file by id and copy to the destination URL</summary>
    /// <param name="sourceDocLibName" type="String" mayBeNull="false" optional="false"></param>
    /// <param name="fileid" type="Number" mayBeNull="false" optional="false"></param>
    /// <param name="destinationurl" type="String" mayBeNull="false" optional="false"></param>
    /// <param name="callback" type="Function" mayBeNull="true" optional="true"></param>
    var e = Function._validateParams(arguments, [{ name: 'sourceDocLibName', type: String, mayBeNull: false, optional: false },
    { name: 'fileid', type: Number, integer: true, mayBeNull: false, optional: false },
    { name: 'destinationurl', type: String, mayBeNull: false, optional: false },
    { name: 'callback', type: Function, mayBeNull: true, optional: true }], false);
    if (e) throw Error.create("Shp.ListItemsOps.copyFileById method was called with invalid arguments");

    var source = Shp.Info._get_documentLibrary(sourceDocLibName);
    if (source === null) {
        alert("Cannot find " + sourceDocLibName + " in web document libraries");
        return;
    }
    var spItem = source.getItemById(fileid);
    Shp.Info.context.load(spItem);

    var fail = function (source, args) {
        alert('Cannot move file: ' + args.get_message() + '\n' + args.get_stackTrace());
    }

    var copyItemSuccess = function (spFile) {
        if ((typeof (callback) !== "undefined") && (callback !== null)) {
            callback();
        }
    }

    var getItemSuccess = function () {
        if (spItem.get_fileSystemObjectType() !== 0) {
            alert("Items was found in the document library but is not a file type");
            return;
        }

        var spFile = spItem.get_file();
        Shp.Info.context.load(spFile);
        spFile.moveTo(destinationurl + '/' + spItem.get_item('FileLeafRef'), 1);
        Shp.Info.context.load(spFile);

        Shp.Info.context.executeQueryAsync(function () { copyItemSuccess(spFile); }, fail);
    }
    Shp.Info.context.executeQueryAsync(getItemSuccess, fail);
}

Shp.ListItemsOps.registerClass("Shp.ListItemsOps");

Shp.ListItemsOps.moveFileById is static function which should be called with 3 parameters: document library name (as string), file id (as integer) and destination url (as string).

If you have suggestions how to improve this code in any sense, please let me know. My intention is to create a reusable code easy to use for everyone.

Advertisements