CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: github

SharePoint Utilities – a promising JavaScript Framework

My colleagues at Bool have developed a new JavaScript framework for SharePoint – sharepoint utilities. It started on our DevDay last year – a whole free day when we could learn new things, try out new techniques or build something that was not even requested from a customer. I was not working on sharepoint utilities, so I almost forgot it until…

I recently  re-discovered sharepoint utilities. It is on Github, it is MIT licensed and contributions are welcome. The core of sharepoint utilities (sputils) is a set of wrappers for Search, TermStore, REST that allow you be more productive as a developer.

What I find especially compelling with that it contains some other fundamental stuff that every SharePoint developer needs:

  • XHR, you only need to use sputils.rest.get or sputils.rest.post to make Ajax requests to SharePoint, no need for jQuery or sprequestexecutor.js
  • Promise, it contains a minimalist Promise framework – no need for jQuery.Deferred. All calls to SharePoint _api are wrapped in promises. So there is a better way of making calls to SharePoint.
  • DateTime, it contains some useful functions for working with dates and time.
  • Functional JavaScript. No need for underscore.js or lodash.js.

To me, XHR and Promises are two important parts that I need in every solution. So instead of linking jQuery and preparing reusable XHR functions for SharePoint, I’d recommend using sharepoint-utilities.

JSGrid Basics

JSGrid is the javascript framework in SharePoint used in Quick Edit View (previously Datasheet View). There are a few very good blog posts on this topic (See below in “Sources”). Nevertheless the fact is that jsgrid and working with quick edit from a developer’s perspective is a huge undiscovered area. Articles I have seen are intended for advanced developers. The goal with my post today is to outline the very basics of working with JSGrid. When you know the basics you will be more comfortable to discover and try out more.

The example I want to show is a jsgrid code for a “VerySimpleColumn”. The source code can be found on gist.github.com: https://gist.github.com/mirontoli/838d60df76107fac56a0 To focus on jsgrid, I assume you have knowledge and some experience of working with jslink, which is related to jsgrid.

A word of caution before we start

JSGrid is an undocumented part of SharePoint javascript “ecosystem”, neither it is a part of the official SharePoint javascript api. So actually we should not use it. On the other hand JSGrid indicates something that is more like a full-fledged javascript api because:

  1. It seems to be carefully prepared (all possible situations are covered)
  2. The api is human-readable. The events and properties are called OnBeginEdit, OnEndEdit, Focus, BindToCell and so on (opposed to the properties in the SP.Microfeed.js like $v_1, $v_2)
  3. It follows many best-practices for handling the UI in javascript, eventhough some constructs are clumsy, e.g. using absolute-positioned overlays on top of original table cells while editing a cell value.

So to me it seems quite okay to use it in real applications, but we have to live with the risk that the jsgrid api will be changed without any notice to us developers.

Set up a site column with a custom jslink

The first step is to set up everything so we can start discovering jsgrid. It is just a walkthrough, not a detailed explanation. If you are eager to look at jsgrid, jump directly to that section. In this example we’ll apply a jslink to a custom site column. The very same jslink will be used in jsgrid, too.

First of all add a new Site Column, call it VerySimpleColumn. The type is Multiple lines of text:

jsgrid-001

Let us put it in a new group: Tolle Columns (beautiful, huh?)

jsgrid-002

 

Three lines of plain text. Nothing extravagant.

jsgrid-003

After that we can verify that the column exists. Fine.

jsgrid-004

 

Now we have to update the jslink property for the new column. Make it in an app:

jsgrid-005

Now add a custom list, call it “TolleList”:

jsgrid-006

 

In the List Settings add the new site column, then you’ll see this:

jsgrid-007

 

Now upload an empty js file to the Style Library, call it field.jslink.verysimplecolumn.js:

jsgrid-008

 

It goes so fast 🙂 Now it is time to implement some jslink code

Writing jslink

I’ve been thinking a while. What example could I use for that jslink? I want it to be a very simple example, so we don’t need to concentrate on actual rendering logic. You can see sophisticated examples that I listed below in “Sources”. Here we will be using this example: We’ll append a text to the field value: “This field is fully controlled by jslink”. This text should be visible on all forms, but it is not a part of the actual field value. Well here it is:

jsgrid-009

The code should appear simple for us who have written at least some jslink code.

(function () {
    function verySimpleView(ctx, field) {
        var wrapper = 'This field is fully controlled by jslink<hr><span>{0}</span>';
        var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name] || "";
        return String.format(wrapper, value);
    }
    
    function verySimpleNewAndEdit(ctx) {
        var wrapper = 'This field is fully controlled by jslink<br><input type="text" id="{0}" value"{1}"/>';
        var id = 'tolle-' + new Date().getTime();
        var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
 
        formCtx.registerGetValueCallback(formCtx.fieldName, function () {
            var input = document.getElementById(id);
            return input.value;
        });
        var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name] || "";
        var html = String.format(wrapper, id, value);
        return html;
    }
    var overrideContext = {};
 
    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates.Fields = {
        'VerySimpleColumn': {
            'View': verySimpleView,
            'DisplayForm': verySimpleView,
            'EditForm': verySimpleNewAndEdit,
            'NewForm': verySimpleNewAndEdit
        }
    };
 
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();

This is how it looks like in the DispForm:

jsgrid-010

JSGrid. First Step: Disable the field in Quick Edit

Now we are ready to handle the Quick Edit. What we’ll do first is to disable editing our column. Why? Let’s say we have some complicated logic for rendering and editing of our field, we don’t the quick edit override it. So before we start implementing the QuickEdit part of the field, we want to disable it. Here, perhaps, ends the implementation of Quick Edit for some business cases.

jsgrid-011

To determine the Quick Edit we can use the propery of ther Render Context called inGridMode. The Quick Edit list uses the “View” template:

function handleGridMode(ctx, field) {
    field.AllowGridEditing = false;
}
function verySimpleView(ctx, field) {
    var wrapper = 'This field is fully controlled by jslink<hr><span>{0}</span>';
    var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name] || "";
    if (ctx.inGridMode) {
        handleGridMode(ctx, field);
    }
    return String.format(wrapper, value);
}

Wiring up a jsgrid EditControl

When our code works in all forms and the values are not “damaged” in the Quick Edit View, then the next step is to create an Edit Control that is used by the jsgrid “engine”. The very minimal Edit Control object is as follows. It contains a few event listeners and properties:

{
    SupportedWriteMode: SP.JsGrid.EditActorWriteType.LocalizedOnly,
    SupportedReadMode: SP.JsGrid.EditActorReadType.LocalizedOnly,
    BindToCell: function () { console.log("tolle BindToCell"); },
    OnCellMove: function () { console.log("tolle OnCellMove"); },
    Focus: function () { console.log("tolle Focus"); },
    OnBeginEdit: function () { console.log("tolle OnBeginEdit"); },
    OnEndEdit: function () { console.log("tolle OnEndEdit"); },
    Unbind: function () { console.log("tolle Unbind"); },
    Dispose: function () { console.log("tolle Dispose"); }
}

This edit control is created and returned in a function that is called: createVerySimpleColumnGridEditControl.

var createVerySimpleColumnGridEditControl = function (gridContext, cellControl) {
    return {
        SupportedWriteMode: SP.JsGrid.EditActorWriteType.LocalizedOnly,
        SupportedReadMode: SP.JsGrid.EditActorReadType.LocalizedOnly,
        BindToCell: function () { console.log("tolle BindToCell"); },
        OnCellMove: function () { console.log("tolle OnCellMove"); },
        Focus: function () { console.log("tolle Focus"); },
        OnBeginEdit: function () { console.log("tolle OnBeginEdit"); },
        OnEndEdit: function () { console.log("tolle OnEndEdit"); },
        Unbind: function () { console.log("tolle Unbind"); },
        Dispose: function () { console.log("tolle Dispose"); }
    }
};

Now we have to register our Edit Control when jsgrid is ready. We have to write a callback function and invoke SP.GanttControl.WaitForGanttCreation. Inside the callback function we register our Edit Control for our field: SP.JsGrid.PropertyType.Utils.RegisterEditControl

function handleGridMode(ctx, field) {
    window.SP.SOD.executeOrDelayUntilScriptLoaded(function () {
        window.SP.GanttControl.WaitForGanttCreation(function (ganttChart) {
            var verySimpleColumn = null;
            var editId = "EDIT_TOLLE_VERYSIMPLEFIELD";
            var columns = ganttChart.get_Columns();

            for (var i = 0; i < columns.length; i++) {
                if (columns[i].columnKey == "VerySimpleColumn") {
                    verySimpleColumn = columns[i];
                    break;
                }
            }
            if (verySimpleColumn) {
                verySimpleColumn.fnGetEditControlName = function (record, fieldKey) {
                    return editId;
                };

                window.SP.JsGrid.PropertyType.Utils.RegisterEditControl(editId, function (gridContext, cellControl) {
                    return createVerySimpleColumnGridEditControl(gridContext, cellControl);
                }, []);
            }

        });
    }, "spgantt.js");
}

In our first version of the Edit Control we only log the event names to the web browser console. It works.

jsgrid-012

Implementing the actual editing

When working on this I did small changes to these events and tried it out in the web browser. I’d recommend it to you, too. Trying out is the best way of learning. Here comes the functions that we need to have to implement:

  • createVerySimpleColumnGridEditControl (“constructor”). Here we initialize the edit control
  • bindToCell. Here we get the cellContext that we save as a “private” variable on that Edit Control object. The cell context is needed to get and set the field value.
  • focus. Here we define what element should be focused. In this case we forward the focus event to the actual input
  • onBeginEdit. Here we show the Edit Control and make it editable.
  • onEndEdit. Here we save the field value and hide the edit control.

jsgrid-013

Some notes on the Edit Control and Events

The Edit Control has a “container” – a html element that contains the representation of the field in edit mode. The Edit Control Container is an overlay – an absolutely-positioned element that exists outside the actual listview. We must set the position and we are responsible for hiding it when the field is not edited:

container.style.cssText = 'visibility:hidden;position:absolute;top:0;left:0;background:#ffffff;';

We also need to set the dimensions of the edit control container. It is quite easy using the information from cellContext:

var bindToCell = function(ctx) {
    cellContext = ctx;
    //An input is put as an overlay. 
    //We have to set the width and height so that it takes the whole cell place
    container.style.minWidth = cellContext.cellWidth + 'px';
    container.style.width = cellContext.cellWidth + 'px';
    container.style.height = cellContext.cellHeight + 'px';
    console.log("tolle BindToCell");
};

In OnBeginEdit we have to show the container, and in OnEndEdit we have to hide it

//OnBeginEdit
cellContext.Show(container);
//OnEndEdit
cellContext.Hide(container);

We have to save the value using the cellContext.

var value = input.value;
cellContext.SetCurrentValue({
    localized: value
});

Final code

(function () {
    var editWrapper = '<span>This field is fully controlled by jslink</span><br><input type="text" id="{0}" value"{1}"/>';
    var createVerySimpleColumnGridEditControl = function (gridContext, gridTextInputElement) {
        var cellContext, inEdit, html, container, input, id;
        id = "tolle-" + new Date().getTime();
        html = String.format(editWrapper, id, "");
        container = document.createElement("div");
        container.innerHTML = html;
        input = container.getElementsByTagName("input")[0];
        container.style.cssText = 'visibility:hidden;position:absolute;top:0;left:0;background:#ffffff;';
        gridContext.parentNode.appendChild(container);
        var bindToCell = function(ctx) {
            cellContext = ctx;
            //An input is put as an overlay. We have to set the width and height so that it takes the whole cell place
            container.style.minWidth = cellContext.cellWidth + 'px';
            container.style.width = cellContext.cellWidth + 'px';
            container.style.height = cellContext.cellHeight + 'px';
            console.log("tolle BindToCell");
        };
        var onCellMove = function () { console.log("tolle OnCellMove"); };
        var focus = function(eventInfo) {
            input.focus();
            console.log("tolle Focus", eventInfo);
        };
        var onBeginEdit = function (eventInfo) {
            inEdit = true;
            var currentValue = cellContext.originalValue.localized;
            if (currentValue) {
                input.value = currentValue;
            }
            cellContext.Show(container);
            console.log("tolle OnBeginEdit");
            this.Focus(eventInfo);
        };
        var onEndEdit = function() {
            cellContext.Hide(container);
            inEdit = false;
            var value = input.value;
            cellContext.SetCurrentValue({
                localized: value
            });
            console.log("tolle OnEndEdit");
        };

        var unbind = function() { console.log("tolle Unbind"); };
        var dispose = function () { console.log("tolle Dispose"); }

        return {
            SupportedWriteMode: window.SP.JsGrid.EditActorWriteType.LocalizedOnly,
            SupportedReadMode: window.SP.JsGrid.EditActorReadType.LocalizedOnly,
            BindToCell: bindToCell,
            OnCellMove: onCellMove,
            Focus: focus,
            OnBeginEdit: onBeginEdit,
            OnEndEdit: onEndEdit,
            Unbind: unbind,
            Dispose: dispose
        }
    };

    function handleGridMode(ctx, field) {
        window.SP.SOD.executeOrDelayUntilScriptLoaded(function () {
            window.SP.GanttControl.WaitForGanttCreation(function (ganttChart) {
                var verySimpleColumn = null;
                var editId = "EDIT_TOLLE_VERYSIMPLEFIELD";
                var columns = ganttChart.get_Columns();

                for (var i = 0; i < columns.length; i++) {
                    if (columns[i].columnKey == "VerySimpleColumn") {
                        verySimpleColumn = columns[i];
                        break;
                    }
                }
                if (verySimpleColumn) {
                    verySimpleColumn.fnGetEditControlName = function (record, fieldKey) {
                        return editId;
                    };

                    window.SP.JsGrid.PropertyType.Utils.RegisterEditControl(editId, function (gridContext, cellControl) {
                        return createVerySimpleColumnGridEditControl(gridContext, cellControl);
                    }, []);
                }

            });
        }, "spgantt.js");
    }


    function verySimpleView(ctx, field) {
        var wrapper = 'This field is fully controlled by jslink<hr><span>{0}</span>';
        var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name] || "";
        if (ctx.inGridMode) {
            handleGridMode(ctx, field);
        }
        return String.format(wrapper, value);
    }
    
    function verySimpleNewAndEdit(ctx) {
        var id = 'tolle-' + new Date().getTime();
        var formCtx = window.SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);

        formCtx.registerGetValueCallback(formCtx.fieldName, function () {
            var input = document.getElementById(id);
            return input.value;
        });
        var value = ctx.CurrentItem[ctx.CurrentFieldSchema.Name] || "";
        var html = String.format(editWrapper, id, value);
        return html;
    }
    var overrideContext = {};

    overrideContext.Templates = overrideContext.Templates || {};
    overrideContext.Templates.Fields = {
        'VerySimpleColumn': {
            'View': verySimpleView,
            'DisplayForm': verySimpleView,
            'EditForm': verySimpleNewAndEdit,
            'NewForm': verySimpleNewAndEdit
        }
    };

    window.SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
})();


Summary

Well, jsgrid is quite complicated. I have tried to keep it as simple and minimalistic as possible. When we can these basics, we can move on and master advanced examples where we can deliver high value to business that loves Quick Edit 🙂

Sources

Interesting, Anton, Andrey and me are born in Sovyet and are interested in JSGrid. Coincidence? 🙂

Load git into PowerShell

Just a little productivity tip. If you use git on Windows, you probably already have the Github for Windows application. This application adds the Git Shell:

006-gitshell

The Git Shell will open a PowerShell window and execute shell.ps1 from the Github directory:

007-gitshell

What it won’t do is to load your personal PowerShell profile. I want to use my PowerShell profile that creates some links and adjust the look-and-feel and the promt of the shell. By the way I have published my profile.ps1 as a gist:

I also want to have git in PowerShell available directly. The answer is in the shell.ps1 in the Github folder:

008-gitshell

So add this line to your profile.ps1 as I did:

. (Resolve-Path "$env:LOCALAPPDATA\GitHub\shell.ps1")

That’s it. If you haven’t seen the “DOT” in PowerShell scripts, it is called dot sourcing, it will execute the script and keep all the variables and references within the script.

An alternative

If you do not have Github for Windows, there is another way to load git functionality into PowerShell:

Toastr.js and SharePoint

Have you used SharePoint javascript Notifications (SP.UI.Notify)? Are you looking for something new and fresh? Well then check out the Toastr.js – a simple, beautiful, fully responsive and light-weight javascript lib for notifications, developed by John Papa and Hans Fjällemark and released under the MIT License.

By the way, toastr was one of many things I discovered and learned on John Papa’s online course by pluralsight: Single Page Apps with HTML5, Web API, Knockout and jQuery. It is a really awesome course, where you learn how to create an amazing SPA.

Well, how’s about SharePoint. While whatching the course videos about toastr, I thought: Can we use it in SharePoint? Yes we can!

Just load the toastr css and js and start using it:

toastr.success("Data has been saved successfully!", "Looks very nice")

 

The easiest way to get the toastr in your project is to install the toastr nuget package:

Install-Package toastr

css3 transform

See Richards Bradshaw’s page with explanations and examples of css3 transform and transitions. His code is also available for forking on Github.

Sharepoint repos on github

githubYou may think all interesting open source Sharepoint projects on codeplex. Well it is true, but there are some interesting projects on github as well. There are 17 projects for now. From a matrix to RichControls.

richcontrols for sharepoint

cloud9 web ide

Skapa javascript-appar i din webbläsare. Mycket smidigt. Direkt kontakt till github.

Improvement ideas

Now, to organize it a little bit, all improvement ideas will be placed in project issues on the github and tagged as “improvement ideas“.

It is much better to collaborate this way. You can track the status of a improvement idea, comment it. Every time it is changed, all the involved developers will be announced.

Good beginners’ tutorial on android, eclipse and git

Smashing magazine has a pretty good tutorial how to start programming for android using git, github, eclipse and datastorage. I recommend:

Get Started Developing For Android With Eclipse, Reloaded

New files in Eclipse

If there are new classes or files in the project (say you have got the latest version from github into existing workspace in Eclipse). In order for Eclipse to see them, right click on the package and press “Refresh”.

Discovering SharePoint

And going crazy doing it

Bram de Jager talking Office 365, SharePoint and Azure

My view and thoughts on Productivity and more.

My programming life

and everything in between

SharePoint Development Lab by @avishnyakov

It is a good place to share some SharePoint stories and development practices.

SharePoint Dragons

Nikander & Margriet on SharePoint

RealActivity - Real-time and trustworthy

Blog site of founder, RealActivty - Paul J. Swider

Mai Omar Desouki - Avid SharePointer

Egyptian & Vodafoner - Senior SharePoint Consultant

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points!!

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode, ya mama

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know about SharePoint - CommunicoCuspis