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>
Advertisements

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();
Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager - Coder, Speaker, Author

Office 365, SharePoint and Azure

SharePoint Dragons

Nikander & Margriet on SharePoint

Paul J. Swider - RealActivity

RealActivity is a specialized healthcare services and solution advisory firm.

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

Aryan Nava

| Blockchain | Serverless Architecture | Microservices Architecture | DevOps | AWS Lambda | Teraform |

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

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know about SharePoint - CommunicoCuspis