Quantcast
Channel: SharePoint Development Lab by @avishnyakov » js
Viewing all articles
Browse latest Browse all 13

Getting started with mQuery/m$ in SharePoint 2013 and SharePoint Online

$
0
0

getting-started-with-mQuery-in-sharepoint-2013

It turns out that SharePoint 2013 has a new library called mQuery which might be quite useful for DOM/array manipulations. Surely, you have the same library in SharePoint Online!

To make a long story short, I would say that mQuery repeats jQuery functions at some point. You may certainly ask why one more library has been introduced with the latest SharePoint release while jQuery has been in place for a quite long time. It makes no sense. I may make only assumptions around that, but I think it does make a lot of sense.

What’s the mQuery/m$?

What is the mQuery? Good question. To be honest, I have no idea either. For the past several months I have been working with client side object model, client side render templates and the rest shiny js stuff. One day I stumbled upon m$ variable in some of the SharePoint scripts as well as a file called “_layouts/15/mquery.debug.js”. Yes, curiosity killed the cat and now I’m here talking about mQuery.

Currently, I see only one post “mQuery for SharePoint 2013” by Niraj Tenany about mQuery. It seems to be unpopular topic yet.

Another one mystery I’m worried about is how “legal” to use mQuery at all. I don’t see intensive usage of mQuery inside SharePoint so it could be an internal API which is still being developed and potential might be changed in the future. Anyway, this seems suspicious, raw and in the air.

On the other hand, I suppose that the fact that we have something like mQuery in SharePoint 2013 is quite logical and predictable.

First of all, SharePoint has quite messy and inconsistent js code; legacy code, some code produced by #Script (ribbon/modal dialog framework and the rest), some other js code from Project server and the rest. Sure, at some point you just have to introduce some kind of reusable libraries/framework to be used across all the js code to avoid more mess. That’s life.

Secondly, I don’t remember any API for DOM/arrays manipulation in SharePoint. Obviously, I cannot imagine modern client side development without that “core” foundation. You may say hey-hey-hey, how about jQuery?! Well, I would not have moved to jQuery or any other 3rd part/open source framework either. In that case, I wouldn’t have full control over that 3rd part framework. Just remember that new jQuery doesn’t support some browsers which could be a major concern for Microsoft and SharePoint. In turn, that is a serious risk – SharePoint is the number one product from Microsoft and it’s said that there is millions installation of SharePoint platform.

Finally, what is mQuery? I have no idea. Seems to be a new API introduced in SharePoint 2013/Online to provide a better experience with DOM/array manipulation. Should I use it? – You may, on your own risk. Should you invest your time in mQuery? – You may, again on your own risk.

How do I use mQuery/m$?

Pretty much the same way as you leverage out of the box SharePoint API. Is has integration with SOD, so you might make sure it is on the page with the following code:

EnsureScriptFunc('mQuery.js', 'm$', function() {
    // DO STUFF
}

You may also add a reference to enable intellesence in the Visual studio with the following construction:

/// <reference path=”C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\mQuery.debug.js” />

What’s next? The next step is exploring either m$ object or _layouts/15/mquery.debug.js file to get more insights about methods and features available. I don’t want to repeat or copy paste mQuery’s methods here, but it might look like that:

mQuery-intellisence

Crafting simple application with mQuery/m$

To start with and learn more about mQuery, I decided to create a simple application with leveraging mQuery as much as I can.

Basically, it is going to be a “repeatable” table with “add a new row” and “delete row” features. Aren’t extremely smart, I know. But okay to get started and familiar with mQuery.

So, here is a mockup:

mQuery-table-sample

Here is how it might look like in at the final stage:

mQuery-table-sample-real

You may add new rows or you may remove already existing one. Also, there is a simple ‘templating’ inside the sample to allow create rows with different content inside.

Html markup could be added to a SharePoint page via “ScriptEditor” web part as well as the link to the javascript file. Here is the markup producing a few tables:

<script src="http://yourserver/Style Library/spdevlab/mQuery.samples.table.js"></script>

<style>
    .spdev-main-cnt td {
        vertical-align: top;
    }

    .spdev-rep-tb-cnt {
        border: 1px #dedede solid;
        padding: 5px;
    }

    .value-w, .value-h, .value-id {
        width: 50px;
    }
</style>

<script type="text/html" dynamic-table-template-id="name-value">
    <tr>
        <td>
            <input type='text' class='value-name' />
        </td>
        <td>
            <input type='text' class='value-value' />
        </td>
        <td><a href='#' class='spdev-rep-tb-del-override'>delete</a></td>
    </tr>
</script>

<script type="text/html" dynamic-table-template-id="whd-value">
    <tr>
        <td>
            <input type='text' class='value-id' />
        </td>
        <td>
            <input type='text' class='value-name' />
        </td>
        <td>
            <input type='text' class='value-w' />
        </td>
        <td>
            <input type='text' class='value-h' />
        </td>
        <td>
            <input type='text' class='value-d' />
        </td>
        <td><a href='#' class='spdev-rep-tb-del-override'>delete</a></td>
    </tr>
</script>

<table class='spdev-main-cnt'>
    <tr>
        <td>
            <div class='spdev-rep-tb-cnt' style='display: none'>

                <table class='spdev-rep-tb' template-id='name-value'>
                    <thead>
                        <td>Name</td>
                        <td>Value</td>
                        <td>Action</td>
                    </thead>
                </table>
                <div>
                    <a href='#' class='spdev-rep-tb-add'>add record</a>
                </div>
            </div>

        </td>
    </tr>
    <tr>
        <td>
            <div class='spdev-rep-tb-cnt' style='display: none'>
                <table class='spdev-rep-tb' template-id='whd-value'>
                    <thead>
                        <td>Id</td>
                        <td>Name</td>
                        <td>Width</td>
                        <td>Height</td>
                        <td>Description</td>
                        <td>Action</td>
                    </thead>
                </table>
                <div>
                    <a href='#' class='spdev-rep-tb-add'>add record</a>
                </div>
            </div>
        </td>
    </tr>
</table>

<script>

    EnsureScriptFunc('mQuery.js', 'm$', function () {
        spdevlab.mQuery.DynamicTable.initTables();
    });

</script>

Finally, here is a javascript source with some mQuery usage:

/// <reference path="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\mQuery.debug.js" />

Type.registerNamespace('spdevlab.mQuery');

spdevlab.mQuery.DynamicTable = function () {

    var self = this;

    // private fields
    spdevlab.mQuery.DynamicTable.prototype._domContainer = null;
    spdevlab.mQuery.DynamicTable.prototype._tableContainer = null;

    spdevlab.mQuery.DynamicTable.prototype._rowTemplateId = null;
    spdevlab.mQuery.DynamicTable.prototype._rowTemplateContent = null;

    spdevlab.mQuery.DynamicTable.prototype._options = {
        tableCnt: '.spdev-rep-tb',
        addCnt: '.spdev-rep-tb-add',
        removeCnt: '.spdev-rep-tb-del'
    };

    // public methods
    spdevlab.mQuery.DynamicTable.prototype.init = function (domContainer, options) {

        if (m$.isDefinedAndNotNull(options)) {
            m$.extend(self._options, options);
        }

        self._initContainers(domContainer);

        self._initRowTemplate();
        self._initEvents();
        self._showUI();
    };

    // private methods
    spdevlab.mQuery.DynamicTable.prototype._initContainers = function (domContainer) {

        self._domContainer = domContainer;
        self._tableContainer = m$(self._options.tableCnt, self._domContainer);
    };

    spdevlab.mQuery.DynamicTable.prototype._showUI = function () {
        m$(self._domContainer).css("display", "");
    };

    spdevlab.mQuery.DynamicTable.prototype._initEvents = function () {

        m$(self._options.addCnt, self._domContainer).click(function () {

            if (m$.isDefinedAndNotNull(self._rowTemplateContent)) {

                m$(self._tableContainer).append(self._rowTemplateContent);

                m$("tr:last-child " + self._options.removeCnt, self._tableContainer).click(function (e) {

                    var targetElement = e.currentTarget;
                    var parentRow = m$(targetElement).parents("tr").first();

                    m$(parentRow).remove();
                });
            }

            return false;
        });
    };

    spdevlab.mQuery.DynamicTable.prototype._initRowTemplate = function () {

        var templateId = m$(self._tableContainer).attr("template-id");

        if (m$.isDefinedAndNotNull(templateId)) {
            self._rowTemplateId = templateId;
            self._rowTemplateContent = spdevlab.mQuery.DynamicTable._templates[templateId];
        }
    };
};

spdevlab.mQuery.DynamicTable._templates = [];

spdevlab.mQuery.DynamicTable.initTables = function () {

    try {
        // init templates
        m$('script').forEach(function (scriptContainer) {

            var id = m$(scriptContainer).attr("dynamic-table-template-id");

            if (m$.isDefinedAndNotNull(id)) {
                spdevlab.mQuery.DynamicTable._templates[id] = scriptContainer.innerHTML;
            }
        });

        // init tables
        m$(".spdev-rep-tb-cnt").forEach(function (divContainer) {

            var dynamicTable = new spdevlab.mQuery.DynamicTable();

            dynamicTable.init(divContainer, {
                removeCnt: '.spdev-rep-tb-del-override'
            });
        });
    }
    catch (e) {
        ULS.enable = true;
        ULSOnError(e.message, document.location.href, 0);
    }
};

Look quite similar to jQuery, isn’t it?

Finally, you with the current files you will get a few beautiful tables on your page:

mQuery-table-sample-final

New rows could be added, templates for the rows could be configured. Also, you may remove a row with ‘delete’ link. Not bad for the beginning.

** It is a good practice to make sure that your code works well with multiple instances of the target component. In  our case we have two tables on the demo page to check that they could work independently without any issues.

Potential risks!

One more time I just want to make sure, is that you fully understand the biggest risk about using mQuery. A there is no information about it (or that’s just stupid me missed something), it is quite risky to use mQuery in your projects. On the other hand, mQuery just has to have backward capability. I believe that code written with mQuery should be able to work successfully in the future.

What would u do with mQuery? – It’s totally up to you.

What to improve?

So far I noticed a few things:

  • no method for ajax/async quesrits to the server
  • no shortcuts to ‘show()/hide()’ methods (only m$.css())
  • no methods like ‘text()/html()’
  • there is ‘m$.ready(callback)’ which is based on _spBodyOnLoadFunctions variable

Well, sure there more things to be hightlights, but these are the major I  have experienced so far.

Also, m$.ready and relation with _spBodyOnLoadFunctions proves that mQuery is fully about SharePoint. You can’t utilize mQuery outside of SharePoint pages. This is an important thing to keep in mind!

What’s next?

I am quite curious to know more about mQuery and to explore more limits with it. I am planning to continue posting about mQuery in the future.

Another one thing I would like to mention is “SharePoint 2013 TypeScript Definitions” project at codeplex. It provides TypeScript declarations for SharePoint 2013 JavaScript Object model. At this very moment, it does not have definitions for mQuery, which is a pity. I am looking forward to wrapping up mQuery to be used with TypeScript; separately without SPTypeScript or just send my definitions to be included later in SPTypeScript.

Files

Conclusion

SharePoint 2013 has a lot of enhancements related to JavaScript object model. It seems that SharePoint dev team is continuously improving internal js code. As a result, js code has become and will become more structured, clean and repeatable.

mQuery seems to be one of the result of the js code refactoring/improvements in SharePoint 2013. At some point, it mimics jQuery providing shortcuts and API for array/DOM manipulation. It also could be a nice asset for your project as well, but remember that you use it on your own risk!


Viewing all articles
Browse latest Browse all 13

Trending Articles