Introduction to Script Lab – A Simplified but powerful way to Office Extendibility

Script Lab is a Microsoft garage project which initiated with summer hackathon held back in 2016. Creator main focus is to build a platform where build add-ins simple and with less knowledge curve for web developers. It is simple but it does not mean it is not powerful. Let’s go through below slider where you could kick start on developing Office extended apps.

click here if slider does not work. 

More information
https://www.microsoft.com/en-us/garage/project-details.aspx?project=script-lab

Github Repository
http://aka.ms/scriptlab

Get Script Lab
https://aka.ms/getscriptlab – install

Office Add-ins UX design patterns
https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns

Office JS API reference
https://dev.office.com/reference/add-ins/javascript-api-for-office

Advertisements

REST and OData with Office365 APIs

When communicate with Office or SharePoint APIs, its important fact that knowledge on representational transfer protocol and OData protocols while moving with deep customization’s.

what is REST (Representational State Transfer)?

In simple terms REST is all about below;

  • Predefined set of stateless operation which identified by URL
  • Responses may contain HTML, JSON, XML or any other defined format which supported
  • GET, POST, PUT, DELETE are most common forms of HTTP verbs

rest_api

Eg.

GET:
http:///_api/web/lists/GetByTitle('Test')
GET:
https://outlook.office.com/api/v2.0/me/MailFolders/sentitems/messages/

what is OData (Open Data Protocol)?

  • Equipped with query and creational capabilities on REST APIs
  • Initiated by Microsoft in year 2007
  • Format [http or https]://<REST Endpoint URL>/<query>
http://<end point URI>?$select=value&$filter=condition$orderby=value

Open Standardization?
Standards which are developed with the involvement of community (mostly with developers). Open standards inherited to office 365 API development in following manners;
• Most of Office 365 APIs are exposed as a RESTful APIs
• Its implemented with OData 4.0 (as for year 2016)

OData queries?
OData queries is common standard which elaborated above also included in the SharePoint and Office365 end point data querying. Its ultra simple if you know the basics and played with this. Follow the following links and be expert on this.

www.odata.org : Official site for OData

graph.microsoft.io : Explore Microsoft Office365 API with queries

OData validator to validate your REST endpoints

Note : If you noticed there are versions associated with most of cloud based endpoints. Cloud services are continuously pushing changes to its services as sooner changes are ready, so then returned patterns may changed for same query. To avoid custom applications get break due to changed on endpoint, it classifies under version metadata. Simply you can pick any version which satisfies your requirement.

Querying SharePoint Endpoints as below;

SharePoint REST service query option syntax
Courtesy : msdn.microsoft.com

 

Further references 

Integrate SharePoint Documents with Office Web Apps in Custom Solutions

If you are finding way of integrating Office Web Apps(OWA)with your custom solution which built with SharePoint CSOM/ JSOM or with integration of any client site development. Specially in a scenario where you develop your own “SharePoint display template” following integration points will be useful;

View in office web apps

Following link will work; if your requirement is to open your document in OWA. This can be done with simply appending parameter as below;

<uri to your document>?Web=0

Eg:
http://mydomain.local/sites/OWASite/Documents/TechCentro.docx?Web=0

Edit SharePoint documents in OWA

Following way of integration with the Office Web apps which let you to pick your action is; means that whether your action may be read, edit or your default setting.

<Web absolute URi>_layouts/15/WopiFrame.aspx?sourcedoc=<Relative URi to document>&action=<Your action>

Summary of actions as below;

 

&action=default -> Gets default setting of the documents
&action=view    -> Open office app as a read only
&action=edit    -> Open office app as editable

Eg:

http://mydomain.local/sites/OWASite/_layouts/15/WopiFrame.aspx?sourcedoc=/sites/OWASite/Documents/BestPractices.docx&action=edit

You can be changed the default behavior with following approach
https://technet.microsoft.com/en-us/library/ee837425.aspx?f=255&MSPPError=-2147217396

Building URL to the Office Web Apps

If you thinking about how to build your URL; following illustration may be useful.

var owauri="_spPageContextInfo.webAbsoluteUrl" //absolute URL of the SharePoint site
+"/_layouts/15/WopiFrame.aspx?sourcedoc=" //static phrase
+"/sites/OWASite/Documents/TechCentro.docx" //Relative URL to the document
+"&action=edit //Action parameter

Useful resources

https://technet.microsoft.com/en-us/library/ff431685.aspx

[Improved Post] Update SharePoint Metadata (Taxonomy) column with Angular JS

After earlier post on the same topic which is updating taxonomy (managed metadata) column with Angular and with JSOM. Thought of optimize the code with more readable and with JavaScript promises. There may be areas further to be improved, for now sample code as below;

(function () {
 'use strict';

 // define controller
 var controllerId = "MMSDevCtrl";

 angular
 .module('app')
 .controller(controllerId, ['$q', mmsDevController]);

 // create controller
 function mmsDevController($q) {

 //global var
 var vm = this;

 //value definitions
 var siteUrl = 'http://win2012/sites/MSSDevTest';
 var listName = 'MyDocumentLibrary';
 var fieldName = 'MMSDepartments'; //MMS Column one
 var fieldName2 = 'MMSDevLanguages'; //MMS Column two
 var itemIdUpdating = 1; // Item to be udated
 var termLabel = 'IT'; //'';
 var termLabel2 = 'Java'; //'';
 //add metadata column to sharepoint
 vm.submitMetadata = function () {
 // function for update managed metadata column
 SetManagedMetaDataField();
 }

 // Setting managed metadata to SharePoint List or Library
 function SetManagedMetaDataField() {
 var context = new SP.ClientContext(siteUrl);
 //Get item form ID
 var list = context.get_web().get_lists().getByTitle(listName); //listName
 var item = list.getItemById(itemIdUpdating); //itemID
 //MMS columns
 var field = list.get_fields().getByInternalNameOrTitle(fieldName); //Tx field one
 var txField = context.castTo(field, SP.Taxonomy.TaxonomyField);
 var field2 = list.get_fields().getByInternalNameOrTitle(fieldName2); //Tx fieldName two
 var txField2 = context.castTo(field2, SP.Taxonomy.TaxonomyField);

 //loading context
 context.load(field);
 context.load(txField);
 context.load(field2);
 context.load(txField2);
 context.load(item);

 //excute async of context
 context.executeQueryAsync(
 //Success
 Function.createDelegate(this
 , function () {
 //Getting term set IDs of the fields
 var termSetId = txField.get_termSetId().toString();
 var termSetId2 = txField2.get_termSetId().toString();

 //Getting ID for term
 getTermIdForTerm(context, termLabel, termSetId)
 .then(function (termID) {
 console.log("Returned term Id", termID);
 //check for not multi valued taxonomy column
 if (!txField.get_allowMultipleValues()) {
 var termValue = new SP.Taxonomy.TaxonomyFieldValue();
 termValue.set_label(termLabel);
 termValue.set_termGuid(termID);
 termValue.set_wssId(-1);
 txField.setFieldValueByValue(item, termValue);
 }
 });

 getTermIdForTerm(context, termLabel2, termSetId2)
 .then(function (termID) {
 console.log("Returned term Id 2", termID);
 //check for not multi valued taxonomy column
 if (!txField2.get_allowMultipleValues()) {
 var termValue2 = new SP.Taxonomy.TaxonomyFieldValue();
 termValue2.set_label(termLabel2);
 termValue2.set_termGuid(termID);
 termValue2.set_wssId(-1);
 txField2.setFieldValueByValue(item, termValue2);
 }
 });

 // Define other columns to be updated
 item.set_item('Title', 'New Item 9102016 C');
 // Update item
 item.update();
 //Execute query for update
 context.executeQueryAsync(
 function () {
 console.log('field updated with MMS column #TechCentro');
 }, function (sender, args) {
 console.error(args.get_message() + '\n' + args.get_stackTrace());
 });
 }
 , function (sender, args) {
 console.log(args.get_message() + '\n' + args.get_stackTrace());
 })
 //Failed
 , Function.createDelegate(this, function (err) {
 console.error(err.get_message());
 })
 )
 }
 // Getting ID of the Term
 function getTermIdForTerm(clientContext, termValue, termSetId) {
 var deferred = $q.defer();
 var termId = "";
 var tSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(clientContext);
 var ts = tSession.getDefaultSiteCollectionTermStore();
 var tset = ts.getTermSet(termSetId);
 var lmi = new SP.Taxonomy.LabelMatchInformation(clientContext);
 lmi.set_lcid(1033);
 lmi.set_trimUnavailable(true);
 lmi.set_termLabel(termValue);
 var termMatches = tset.getTerms(lmi);
 //context loading with taxanomy values
 clientContext.load(tSession);
 clientContext.load(ts);
 clientContext.load(tset);
 clientContext.load(termMatches);
 clientContext.executeQueryAsync(
 function () {
 if (termMatches &amp;&amp; termMatches.get_count() &gt; 0) {
 termId = termMatches.get_item(0).get_id().toString();
 deferred.resolve(termId);
 console.log("Resolved Term Id for Term " + termValue, termId);
 }
 else
 deferred.resolve(null);
 }, function (sender, args) {
 console.log("Error on retrieving term GUID", args);
 deferred.reject(null);
 });
 return deferred.promise;
 }

 };

})();

Markup as below;


<script src="../../_layouts/15/SP.Runtime.js"></script>
<script src="../../_layouts/15/SP.js"></script>
<script src="../../_layouts/15/SP.Taxonomy.js"></script>
<script src="../Scripts/angular.js"></script>
<script src="../Scripts/App.js"></script>
<script src="../Scripts/mmsDev.controller.js"></script>
<div ng-app="app" ng-controller="MMSDevCtrl as vm">
{{}}
<input id="Text1" type="text" ng-model="vm.value"/>
<input id="Submit1" type="button" value="submit" ng-click="vm.submitMetadata()"/></div>

Click here to view old post.

Get | Resolve Term ID for Term Value in SharePoint Metadata Service

This may be generic function you can use when you play with managed metadata (taxonomy) columns or with Managed Managed Metadata Service.

Notes:

  • Used JSOM since no impletation in REST API to get done this task in SharePoint to date of post
  • Passing term set ID is must since there may may be many term values equivalent in the term store
  • For the example, I have retrieved the term set ID from the list field which glued with the managed metadata service.

Following code illustrate how to get term ID for term value provided.


// Resolve Term ID for the Term Value 
 function getTermIdForTermValue(siteUri, listName, fieldName, termValue) {
 //Define
 var deferred = $q.defer()
 , termId;
 var clientContext = new SP.ClientContext(siteUrl);
 var list = clientContext.get_web().get_lists().getByTitle(listName);
 //Tx field
 var field = list.get_fields().getByInternalNameOrTitle(fieldName);
 var txField = clientContext.castTo(field, SP.Taxonomy.TaxonomyField);
 //load context
 clientContext.load(field);
 clientContext.load(txField);
 // //excute async of context
 clientContext.executeQueryAsync(
 //Success on Async
 Function.createDelegate(this
 , function () {
 //Getting term set of the field
 var termSetId = txField.get_termSetId().toString();
 var tSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(clientContext);
 var ts = tSession.getDefaultSiteCollectionTermStore();
 var tset = ts.getTermSet(termSetId);
 //Define term label to match
 var lmi = new SP.Taxonomy.LabelMatchInformation(clientContext);
 lmi.set_lcid(1033);
 lmi.set_trimUnavailable(true);
 lmi.set_termLabel(termValue);
 var termMatches = tset.getTerms(lmi);
 //context loading with taxanomy values
 clientContext.load(tSession);
 clientContext.load(ts);
 clientContext.load(tset);
 clientContext.load(termMatches);
 clientContext.executeQueryAsync(
 function () {
 if (termMatches &amp;&amp; termMatches.get_count() &gt; 0) {
 termId = termMatches.get_item(0).get_id().toString();
 console.log("Resolved Term Id for Term " + termValue, termId);
 deferred.resolve(termId);
 }
 else {
 console.log("No IDs to resolved for Term " + termValue);
 deferred.resolve(null);
 }
 }
 , function (sender, args) {
 console.log("Error on resolving term ID", args);
 deferred.reject(null);
 });
 }
 , function (sender, args) {
 console.log(args.get_message() + '\n' + args.get_stackTrace());
 })
 //Failed on Async
 , Function.createDelegate(this, function (err) {
 console.error(err.get_message());
 })
 );
 return deferred.promise;
 }

Click here to view in gist.

For more details refer following links;

Managed Metadata Column Value Add with Angular | JavaScript & JSOM | CSOM

Following would be high-level program flow;MMS Column Update Program Flow

SP Taxonomy need to be imported.


var scriptbase = _spPageContextInfo.webServerRelativeUrl + "/_layouts/15/";
$.getScript(scriptbase + "SP.Taxonomy.js");

Create custom list item with metadata column in SharePoint with JSOM and Angular JS.

// Adding item to SharePoint custom list with Managed Metadata column (MMS column) with JSOM
(function () {
    'use strict'; 

    // define controller
    var controllerId = "mmsColumnUploadCtrl"; 

    angular
        .module('app')
        .controller(controllerId, ['$scope', mmsColumnUploadCtrl]); 

    // create controller
    function mmsColumnUploadCtrl($scope) {
        //global var
        var vm = this;

        //add metadata column to sharepoint
        vm.AddMetadataColumn = function () {
            var scriptbase = _spPageContextInfo.webServerRelativeUrl + "/_layouts/15/"; 

            // create list item with MMS column
            $.getScript(scriptbase + "SP.Taxonomy.js", createListItemWithMMSColumn); 

        } 

        //Create list item metadata with MMS column
        function createListItemWithMMSColumn() {
            //site URi
            var siteUrl = 'http://<site url>/sites/MMSPOC';
            // List name of updating
            var listName = 'TestList';// List name
            //Term GUID get from Service
            var termId = 'ed414e70-cc02-444b-ba78-8456e6495e45';//term GUID
            //For multi labled column may need to provice term lable also, else no
            //var termLabel = 'ABCTEST';//Term label

            // Client context
            var clientContext = new SP.ClientContext(siteUrl);
            var oList = clientContext.get_web().get_lists().getByTitle(listName);
            var itemCreateInfo = new SP.ListItemCreationInformation();
            var oListItem = oList.addItem(itemCreateInfo);
            // Define item
            oListItem.set_item('Title', 'New Item!'); // non MMS columns
            oListItem.set_item('MMSCol', termId); //MMS column
            // Update item
            oListItem.update(); 

            //client context..Async Req.
            clientContext.load(oListItem);
            clientContext.executeQueryAsync(
                Function.createDelegate(this, onQuerySucceeded),
                Function.createDelegate(this, onQueryFailed)
             );
        } 

        // On query success
        function onQuerySucceeded(oListItem) {
            console.info('Item created!');
        }
        // On query failed
        function onQueryFailed(sender, args) {
            console.error('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        } 

    }; 

})();

Update document library items’ managed metadata column in SharePoint with JSOM and Angular

// Adding item to SharePoint "Document Library" with Managed Metadata column (MMS column) with JSOM
(function () {
    'use strict'; 

    // define controller
    var controllerId = "mmsColumnUploadCtrl"; 

    angular
        .module('app')
        .controller(controllerId, ['$scope', mmsColumnUploadCtrl]); 

    // create controller
    function mmsColumnUploadCtrl($scope) {
        //global var
        var vm = this;

        //add metadata column to sharepoint
        vm.AddMetadataColumn = function () {
            var scriptbase = _spPageContextInfo.webServerRelativeUrl + "/_layouts/15/"; 

            // Create document item ith MSS column
            $.getScript(scriptbase + "SP.Taxonomy.js", updateDocumentItemWithMMSColumn); 

        } 

        // Create document metadata of document library item with MMS column
        function updateDocumentItemWithMMSColumn() {
            //site URi
            var siteUrl = 'http://<site>/sites/MMSPOC'; 

            // List name of updating
            var listName = 'MMSPOCDocLib';//document library name

            // GUID of the term
            var termId = 'ed414e70-cc02-444b-ba78-8456e6495e45';//term guid

            //For multi-valued terms following will be needed
            var termLabel = 'ABCTEST';//term label

            //Item Id for update in the document library
            //3 is item ID to be updated
			//You may dynamically change with the requirement
            var itemIdUpdating = 3; 

            // Client context
            var clientContext = new SP.ClientContext(siteUrl);
            var oList = clientContext.get_web().get_lists().getByTitle(listName);
            var itemCreateInfo = new SP.ListItemCreationInformation(); 

            var oListItem = oList.getItemById(itemIdUpdating);
            // Define item
            oListItem.set_item('Title', 'Item updated!');
            oListItem.set_item('MMSCol', termId);
            // Update item
            oListItem.update(); 

            //client context..Async Req.
            clientContext.load(oListItem);
            clientContext.executeQueryAsync(
                Function.createDelegate(this, onQuerySucceeded),
                Function.createDelegate(this, onQueryFailed)
             );
        }
        // On query success
        function onQuerySucceeded(oListItem) {
            console.info('Item created!');
        }
        // On query failed
        function onQueryFailed(sender, args) {
            console.error('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
        } 
    };

Await for more interesting coding samples and articles, keep following!!