CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: jQuery tmpl

Nested templates in jQuery.tmpl

I have used jQuery tmpl for a while and it is really awesome. Now I want to use some nested templates. And the thing is: it is very simple to do it:

Here is the code to achieve this:

<div onclick="doo()">test</div>
<div id="container"></div>
<script id="parent-template" type="text/html">
<li>
   {{tmpl t }}
</li>
</script>
<script id="red" type="text/html">
   <span style="color:red">{{= title}}</span>
</script>
<script id="green" type="text/html">
   <span style="color:green">{{= title}}</span>
</script>
<script type="text/javascript">
    var d = [];
    d.push({ title: "one", t: "red" });
    d.push({ title: "two", t: "green" });
    $.template("red", $("#red").template());
    $.template("green", $("#green").template());
    function doo() {
        $("#parent-template").tmpl(d).appendTo("#container");
    }
</script>

Simplifying jQuery tmpl interface

In one of my previous posts I showed a simple example how to retrieve data from a web service and render it with jQuery tmpl. To render this I used an id for a template and the container:

<script id="contactTemplate" type="text/html">
    <div>
        Name: {{= Name }} <br>
        Phone: {{= Phone }}
    </div>
</script>

<div id="contactContainer"></div>

To render we select the template and container with jQuery selectors:

function onSuccess(data) {
	$("#contactTemplate").tmpl(data.d.results).appendTo("#contactContainer");
}

On a page with multiple templates and containers it can be a djungle of different ids you have to track. Johan Leino in his great blog post provides a better and simpler way to organize containers and templates. The solution is to extend jQuery selectors (like :even, :odd and more) and introduce two new: :template and :container. This code comes from Johan Leino:

(function ($, undefined) {
    if ($ === undefined) {
        throw "Dependency: jQuery is not defined. Please check javascript imports.";
    }
    $.extend($.expr[':'],
    {
        // :template(name)
        template: function (current, index, metadata, elements) {
            var arg = metadata[3],
                d = $(current).data("template-for");
            if (d === undefined) {
                return false;
            }
            return arg ? arg === d : true;
        },
        // :container(name)
        container: function (current, index, metadata, elements) {
            var arg = metadata[3],
                d = $(current).data("container-for");
            if (d === undefined) {
                return false;
            }
            return arg ? arg === d : true;
        }
    });
} (jQuery));

Now we can forget the ids:

<script type="text/html" data-template-for="contacts">
    <div>
        Name: {{= Name }} <br>
        Phone: {{= Phone }}
    </div>
</script>

<div data-container-for="contacts"></div>

Our onSuccess method will look like:

function onSuccess(data) {
    var $container = $(":container(contacts)");
    var $template = $(":template(contacts)");
    $template.tmpl(data.d.results).appendTo($container);
}

Much simpler, isn’t it? More possibilities to write more generic js code, like extracting “contacts” into a variable. One thing I would like to know how performance is in older IE browsers for custom jQuery selectors.

See my post about nested templates where I implement these selectors.

String.format for javascript

sprintf is actually the best javascript implementation of sprintf (string.format). But wait, shouldn’t it be some more .NET-like stuff in SharePoint environment? Indeed there is! (Well, not only in SP, but ASP.NET)

String.format(“Hello {0}”, “world”) does exactly the same thing as on server side. Wow, it opens for many opportunities, e.g. in jQuery tmpl:

String.format validates arguments, and if all is OK, it invokes another function String._toFormattedString:

function String$_toFormattedString(useLocale, args) {
    var result = '';
    var format = args[0];
    for (var i=0;;) {
        var open = format.indexOf('{', i);
        var close = format.indexOf('}', i);
        if ((open < 0) && (close < 0)) {             
            result += format.slice(i);
            break;
        }
        if ((close > 0) && ((close < open) || (open < 0))) {
            if (format.charAt(close + 1) !== '}') {
                throw Error.argument('format', Sys.Res.stringFormatBraceMismatch);
            }
            result += format.slice(i, close + 1);
            i = close + 2;
            continue;
        }
        result += format.slice(i, open);
        i = open + 1;
        if (format.charAt(i) === '{') {
            result += '{';
            i++;
            continue;
        }
        if (close < 0) throw Error.argument('format', Sys.Res.stringFormatBraceMismatch);
        var brace = format.substring(i, close);
        var colonIndex = brace.indexOf(':');
        var argNumber = parseInt((colonIndex < 0)? brace : brace.substring(0, colonIndex), 10) + 1;
        if (isNaN(argNumber)) throw Error.argument('format', Sys.Res.stringFormatInvalid);
        var argFormat = (colonIndex < 0)? '' : brace.substring(colonIndex + 1);
        var arg = args[argNumber];
        if (typeof(arg) === "undefined" || arg === null) {
            arg = '';
        }
        if (arg.toFormattedString) {
            result += arg.toFormattedString(argFormat);
        }
        else if (useLocale && arg.localeFormat) {
            result += arg.localeFormat(argFormat);
        }
        else if (arg.format) {
            result += arg.format(argFormat);
        }
        else
            result += arg.toString();
        i = close + 1;
    }
    return result;
}

By the way, take a look at summary part of String.format:

/// <summary locid="M:J#String.format" />
/// <param name="format" type="String"></param>
/// <param name="args" parameterArray="true" mayBeNull="true"></param>
/// <returns type="String"></returns>

Great summary, how could we get intellisense on that in Visual Studio? Anyone know?

Another aspect of String.format I have discovered is that unfortunately you cannot format digitals like {0:00} like in C# (e.g. 8 gets 08). Then I recommend you zlib licensed javascript library called StringFormat from Daniel Mester Pirttijärvi.

this.data in jQuery tmpl

In jQuery tmpl we can render properties with {{= SomeProperty }}. Here is an example:

<script type="text/javascript">
    Writer = function (firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    };
    Writer.prototype = {
        getFullName: function () {
            return this.firstName + " " + this.lastName;
        }
    };

    $(document).ready(function () {
        var writers = [];
        writers.push(new Writer("Gennady", "Ajgi"));
        writers.push(new Writer("Mišši", "Şeşpĕl"));
        writers.push(new Writer("Ille", "Tuktaš"));
        writers.push(new Writer("Kĕştenttin", "Ivanov"));
        $("#tmpl").tmpl(writers).appendTo("#writers");
    });
</script>
<script id="tmpl" type="text/html">
<li>
    {{= firstName }} {{= lastName }}
</li>
</script>
<div id="writers"></div>

It will render like:

  • Gennady Ajgi
  • Mišši Şeşpĕl
  • Ille Tuktaš
  • Kĕştenttin Ivanov

But what if we want to access the object itself, not one of the properties. Say, you want to pass the object from the array into a js function as a parameter to decide how it will be rendered, or if you want show a “calculated” property. The key word is…: this.data. this.data has the current object. After it has been rendered, we can access this object with $(this).tmplItem().data.

<script type="text/javascript">
Writer = function (firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
};
Writer.prototype = {
  getFullName: function () {
    return this.firstName + " " + this.lastName;
  }
};
$(document).ready(function () {
 var writers = [];
 writers.push(new Writer("Gennady", "Ajgi"));
 writers.push(new Writer("Mišši", "Şeşpĕl"));
 writers.push(new Writer("Ille", "Tuktaš"));
 writers.push(new Writer("Kĕştenttin", "Ivanov"));
 $("#tmpl").tmpl(writers).appendTo("#writers");
});
</script>
<script id="tmpl" type="text/html">
<li>
 {{= this.data.getFullName() }}
</li>
</script>
<div id="writers"></div>

The cool thing is, you don’t even need to pass this.data as parameter to a function for processing, you can invoke your function without parameters. Inside this function you have access to this.data. So if you had created a normal function getFullName without a prototype:

function getFullName(person) {
  return person.firstName + " " + person.lastName;
}

So you could just invoke this from template like {{= getFullName }}. But it becames loose. So I wouldn’t recommend it. The prototype way is a better way to structure it.

jQuery tmplItem and no ids

tmplItem() works even without ids. To get the current data:

$(this).tmplItem().data;

If you want to remove, just invoke the ajax and remove with $.parents:

$(this).parents("li").remove();
Updating data inside tmplItems

If you want to achieve some fancy dependency tracking, consider knockout.js. But if you just want to update the data object inside a tmplItem, just change the object and call update:

var t = $(this).tmplItem();
var obj = t.data;
obj.Address = "hello avenue";
t.update();
Discovering SharePoint

And having fun 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