Quantcast
Channel: SharePoint Development Lab by @avishnyakov » GanttControl
Viewing all articles
Browse latest Browse all 2

Custom Field Type for SharePoint 2013 – Custom “Quick Edit” mode implementation

$
0
0

Custom Quick Edit mode for SharePoint 2013

A few month ago I wrote a nice post “Custom Field Type for SharePoint 2013 – VISA card field sample” which shows the way to create a custom field for SharePoint 2013. Basically, we just need to use JavaScript to craft callbacks and specify rendering functions for edit/view/new and other field rendering modes.

This is just a half of the story as SharePoint 2013 introduced a new “Quick Edit” grid for the batch record editing in the list/libraries. The good news that this grid is written with pure JavaScript, but the terrible news is that we don’t have any documentation on that grid – how to extend or handle your custom field logic in that “Quick Edit” grid.

To fill the gap, you may check “Custom Field Type for SharePoint 2013 – Custom “Quick Edit” mode rendering” post where I described some rendering options related to the “Quick Edit” mode in SharePoint. I ended up with some geeky stuff explaining hardcore insights about how JSGrid and “Quick Edit” mode works in SharePoint 2013. Quite weird and deep stuff, really.

However, today I am quite excited to share a working prototype and guide/documentation which would help you implement your own “Quick Edit” mode support for the custom field. Yea, you read correctly, “Quick Edit” support! – How awesome is that?

Prerequisites

To start with, consider checking the following post to get more context and insights:

I use VISA field sample from “SharePoint 2013 custom field samples” project a codeplex which was fully migrated to TypeScript and SPTypeScript.

If it still sounds reasonable to you, let’s make something cool for the “Quick Edit” support, then.

High level flow for the custom Edit Control in Quick Mode

Well, at this point you should already be familiar with custom field rendering and some dirty details regarding JSGrid/Gantt control. Okay, let’s go deeper, then.

Internally, JSGrid has a quite large object model related to the fields, rows, table, data processing and the rest neat stuff. However, we would need to know just a few small things from all JSGrid/GanttControl mess.

First of all, every time you edit a cell within “Quick Edit” mode, a particular JS function gets called. SharePoint field types have different handlers to render simple text inside “Quick Edit“, or combo box, or date value and other types.

That stuff is called “EditControl“, and the high level definition might look like that:

 export class EditControl {

     public SupportedWriteMode: SP.JsGrid.EditActorWriteType;
     public SupportedReadMode: SP.JsGrid.EditActorReadType;

     public BindToCell(cellContext: any);
     public OnCellMove();

     public Focus(eventInfo: any);

     public OnBeginEdit(eventInfo: any);
     public OnEndEdit(eventInfo: any);

     public Unbind();
     public Dispose();
 }

Pretty much, we have set of the methods/events to be able to interact with the JSGrid; understand whether the cell is being edited or not, read the current value and pull it back to the JSGrid, handle focus events as well as track keyboard and mouse.

The general flow for the custom edit control looks like that:

  • You are given the current cell context
  • You create UI you may need and attach it to the current cell context
  • You subscribe/handle OnBeginEdit/OnEndEdit methods
  • You use current cell context to read/write field value

Really, not that hard. More details with the implementation will be covered later in this post.

Next, let’s focus on the entry point for the edit control registration. Well, there is an entry point to understand if a new JSGrid/Gantt control gets created on the page. This event might be used to attach our custom edit control for the particular fields on the page.

We may use static callback SP.GanttControl.WaitForGanttCreation() which is called per every Gantt control on the page. The general idea looks like that:

  • Handle new Gantt control creation via SP.GanttControl.WaitForGanttCreation
  • Find target field in the current Gantt control field set
  • If we have target field, register custom JSGrid edit control for that field

Again, not tricky and might be done, right?

Finally, let’s see the potential implementation with TypeScript.

Some implementation

Let’s assume we have implemented “VisaFieldGridEditControl” to support VISA field “Quick Edit” mode. The initial registration might look like this:

SP.SOD.executeOrDelayUntilScriptLoaded(function () {

    SP.GanttControl.WaitForGanttCreation(function (ganttChart) {

        var visaColumn = null;

        var visaFieldQuickEditId = "EDIT_SPDLAB_VISAFIELD";
        var columns = ganttChart.get_Columns();

        for (var i = 0; i < columns.length; i++) {
            if (columns[i].columnKey == "VisaField") {
                visaColumn = columns[i];
                break;
            }
        }
        visaColumn.fnGetEditControlName = (record, fieldKey) = > {
            return visaFieldQuickEditId;
        };

        SP.JsGrid.PropertyType.Utils.RegisterEditControl(visaFieldQuickEditId, function (gridContext, cellControl) {
            var editorInstance = new spdevlab.fields.VisaFieldGridEditControl();
            editorInstance.Init(gridContext, cellControl);

            return editorInstance;
        }, []);
    });

}, "spgantt.js");

Again, just handling Gant control creating, finding the target field, updating “fnGetEditControlName” function to point to unique custom edit control ID and, finally, registration with SP.JsGrid.PropertyType.Utils.RegisterEditControl method.

In turn, VisaFieldGridEditControl looks much complicated. The start method is “Init()” where we consume the current cell context as “gridContext” variable, creating 4 text boxes within “<div>” and putting it inside cell context with the pure _gridContext.parentNode.appendChild() method call.

export class VisaFieldGridEditControl implements SP.JsGrid.EditControl {

    public Init(gridContext: any, gridTextInputElement: any) {

        var self = this;

        this._onActivateActor = () = > {
            self._gridContext.OnActivateActor();
        };
        this._onKeyDown = (e) = > {
            self.onKeyDown(e);
        };
        this._onKeyUp = (e) = > {
            self.onKeyUp(e);
        };
        this._onMouseDown = (e) = > {
            self.onMouseDown(e);
        };

        this._gridContext = gridContext;
        this._gridTextInputElement = gridTextInputElement;

        this._cnt = document.createElement('div');
        this._cnt.style.cssText = 'visibility:hidden;position:absolute;top:0px;left:0px;background:#ffffff;border:1px #dedede solid;';

        for (var i = 0; i < 4; i++) {
            var newTb = document.createElement('input');

            newTb.id = "spdevlab-visafield-quickedit-" + i.toString();
            newTb.value = i.toString();
            newTb.style.cssText = 'position:;top:0px;left:0px;';
            newTb.maxLength = 4;
            newTb.size = 4;

            this._cnt.appendChild(newTb);
            this._tbs[i] = newTb;
        }

        this._gridContext.parentNode.appendChild(this._cnt);
    }
}

OnBeginEdit/OnEndEdit methods are called per every cell editing session. The key point is to show/hide the UI via _cellContext.Show()/_cellContext.Hide() methods. You don’t need to change actual control visibility, JSGrid API covers you up.

public OnBeginEdit(eventInfo: any) {

    this._inEdit = true;

    var currentValue = this._cellContext.originalValue.localized;

    if (currentValue) {
        VisaFieldHelper.UpdateValues(this._tbs, currentValue);
    }

    this._cellContext.Show(this._cnt);

    this._setupHandlers(true);
    this.Focus(eventInfo);
}

public OnEndEdit(eventInfo: any) {

    this._cellContext.Hide(this._cnt);

    this._inEdit = false;
    this._setupHandlers(false);

    var value = this._tbs[0].value + "" +
        this._tbs[1].value + "" +
        this._tbs[2].value + "" +
        this._tbs[3].value;

    this._cellContext
        .SetCurrentValue({
            localized: value
        });
}

Finally, mouse/keyboard tracking. This is quite a pain, as TypeScript has some struggling with “this/() =>” scope so it might be tricky to use $addHandler/$removeHander methods. Anyway, as we have 4 text boxes per every VISA string part, we need to register the same set of events for every text box. In general, I just “skip” tab key to allow tabbing between VISA part textboxes within onKeyDown() method. We may either stop event propagation for a particular key/event or push it back to the JSGrid via _gridContext.OnKeyDown(eventInfo) method call.

private _setupHandlers(attachActions: boolean) {

    var self = this;

    for (var i = 0; i < this._tbs.length; i++) {

        var tb = this._tbs[i];

        if (attachActions) {

            $addHandler(tb, 'focus', self._onActivateActor);
            $addHandler(tb, 'keydown', self._onKeyDown);
            $addHandler(tb, 'keyup', self._onKeyUp);
            $addHandler(tb, 'mousedown', self._onMouseDown);
        } else {
            $removeHandler(tb, 'focus', self._onActivateActor);
            $removeHandler(tb, 'keydown', self._onKeyDown);
            $removeHandler(tb, 'keyup', self._onKeyUp);
            $removeHandler(tb, 'mousedown', self._onMouseDown);
        }
    }
}

private onKeyDown(eventInfo: any) {

    if (eventInfo.keyCode == Sys.UI.Key.tab) {
        eventInfo.stopPropagation();
    } else {
        this._gridContext.OnKeyDown(eventInfo);
    }
}

Pretty much, these are the only thing you may need to know to implement custom field rendering support for “Quick Edit” mode. JSGrid/Gantt controls aren’t documented at all, so they are is quite challenging things to deal with. However, custom “Quick Edit” mode can be implemented; the VISA field is a convincing proof of concept.

Finally, at the end you may get a neat eiting experience for the VISA field in “Quick Edit” more. Saving/editing value works fine, “ESC” pushes you back to the normal grid state as well as “Tab” swich the current VISA part text box. A-s-w-e-s-o-m-e!

Custom Quick Edit mode for SharePoint 2013

Well, this is quite complicated technical post, I know. So you may check out the source code of the VISA field at SharePoint 2013 custom field samples, consider other links to get started, and I wish you all the best with exploring JSGrid/Gantt controls JavaScript API in SharePoint 2013.

Also, there are some new TypeScript definitions within SP.GanttControl.d.ts and SP.JsGrid.d.ts files. They aren’t full, there is no covering of the JSGrid/Gantt control for SPTypeScript/TypeScript yet. You may use the current definitions or add more, or wait for the new definitions by SharePoint 2013 TypeScript Definitions project.

Links

Conclusion

SharePoint 2013 introduced new JSGrid/Gantt controls written in pure JavaScript. This is quite fantastic as there is an opportunity to provide custom rendering or even new feature for JSGrid/Gantt control.

On the other hand, there is no documentation regarding JSGrid/Gantt control. Any kind of custom/new functionality is hard to developer, debug and introduce so this post is supposed to prove high level overview of the “Quick Edit” support for the custom field rendering in SharePoint 2013.


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images