Knockout binding formatters for date and currency

 

Dependency

  • Requires Knockout
  • jQuery (for setting text())
  • ASP.NET (for the formatting functions).

 

ko.bindingHandlers.date = {
    update: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
       
        var d = "";
        if (valueUnwrapped) {
            var m = /Date\([\d+-]+\)/gi.exec(valueUnwrapped);
            if (m) {
                d = String.format("{0:dd/MM/yyyy}", eval("new " + m[0]));
            }
        }       
        $(element).text(d);   
    }
};
ko.bindingHandlers.money = {
    update: function(element, valueAccessor, allBindingsAccessor) {
        var value = valueAccessor(), allBindings = allBindingsAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(value);
       
        var m = "";
        if (valueUnwrapped) {       
            m = parseInt(valueUnwrapped);
            if (m) {
                m = String.format("{0:n0}", m);
            }
        }       
        $(element).text(m);   
    }
};

Usage:

 

  • data-bind="money: myMoney"
  • data-bind="date: myDate"

 

Note:

Dates are converted from ASP.NET's date format: \/Date(1000+1000)\/

InfoPath - creating sequential filenames without an extra column

Avid InfoPath form creators will no doubt know the trick to create sequential numbers for use in filenames.  The steps typically includes:

  1. Create a field FileName, create another field SeqNo.
  2. Publish the form to SharePoint Form library, and promote the column for SeqNo
  3. Create a view, use REST data connection or use owssrv.dll to get data from this Form library, in particular we want to know the SeqNo
  4. Prior to save, check that the FileName is not blank, query the data connection to find the latest SeqNo from the forms library.  Using max()
  5. Add one to this number, store it in SeqNo
  6. Create FileName by concatenating some prefix with SeqNo:  MyFile-004
  7. Submit through a data connection back to the Form library with the FileName

 

This blog post is NOT about using a second column

We will work out the next number completely without promoting any fields.

WHY, you may ask.  Well, because it's FUN!

And we get to play with a modified double-eval trick as a bonus!

 

Set up

  • Create a basic form, create a field filename
  • Publish to SharePoint Form library

image


image

 

Secondary data source for querying existing filenames

Create a SharePoint connection to the Form library.

Here I'm creating a SharePoint List data connection.  The old trick with owssrv.dll will work as well.

image

 

 

Secondary data source for submit (to save forms)

Another SharePoint connection to the Form library, this one is for submit.  Allow overwrite.  Also, use the filename field for saving.

image

image

Save button

Create a save button.  When the user clicks save, we're going to create a new filename with a sequential number, then call the submit data connection.

Our secondary data looks like this:

image

I drop this onto the form to show what is the data in this data connection.

 

image

 

What we want to do, is to take the names, strip out all the non-numeric characters, and then perform a max() operation to find the largest number.

 

Stripping characters with TRANSLATE

InfoPath has a useful function translate("abc", "ABC") it replaces the first set of characters with the second set.  If your second set is empty, like this: translate("abc", "") you can essentially perform a character removal.

And now, I can use my translate function like this:

image

image

Run the form in preview: we are now left with just the the numbers in the filename.  Good.

 

Double-eval

Back to our list of existing form names. 

image

The double-eval trick essentially gives us a way to do a for-each parse through a repeating section in InfoPath.

The basic form this is:

image

The inner-eval, runs "." (current), and the outer-eval, runs ".." (parent).   Combined, this gives us a concatenated string of all the Title

image

 

Combine both the translate strip, and the double-eval, we get:

image

 

Preview:

image

 

Finally, replace the outer-eval with a max function, and prefix a 0 (for filenames that don't have numbers).

image

max(eval(Title, 'concat("0", translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -+,_!.", ""))'))

 

Preview result:

image

 

So my filename function is this:

concat("form-", max(eval(Title, 'concat("0", translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -+,_!.", ""))')) + 1 )

image

 

Here's the form running in Form Server

image

 

Download

SSPUG retrospective: Creating Knockout user experiences in SharePoint with JavaScript

 

I had an absolute blast presenting Knockout, AJAX, jQuery, SP2010 REST services, and spservices tonight at the February 2012 Sydney SharePoint user group.

The turn out was awesome, and I want to thank you guys for the great questions and the awesome attention for listening me talk about this stuff, with great excitement, for 1.5 hours.

This is what we built, not bad, in 90 minutes ;-)

image

 

Great questions:

Why do you need to call ko.utils.unwrapObservable for the key function? 

This is actually pretty important, and I didn't explain it very well until I thought about it afterwards.

The reason is that I believe Knockout is actually building a dependency graph when you use knockout expressions and compute functions.  If you use data.Id() - you will actually set up a dependency chain between the knockout viewmodel and the key function.  I can't imagine it would be disastrously bad - since you don't bind the key function to the UI, but it is an unnecessary performance hit.

 

 

What do you do with the formatting?

The easiest way, I think, is to build a compute function and then return the value you want in the right format you wanted it.  Knockout itself doesn't contain formatting functions, and I think it will probably be implemented as an separate plugin.

ASP.NET's built in JavaScript, which is available in SharePoint, contains a lot of formatting functions for rendering both currency and dates. 

A separate, slightly prettier technique, is to add additional binding handlers (aka, the text:, html:, value: expressions), and create a new binding expression that also does formatting.  In my projects, I've used

  • money: MyCurrency
  • date: MyDate

These are one-way binding, because I'm lazy, but you can make them two-way as well if you want to handle the parsing.

 

Downloads

 

Next Presentations

No idea, but I plan to be presenting this for the rest of the year in the various SharePoint Saturdays, so bring your colleagues for a exciting session on a very cool, new technique.

Creating Knockout User Experiences in SharePoint with JavaScript and REST services

 

Sydney SharePoint user group is 21st of February.  Where I'll be presenting Knockout, AJAX and REST services.

 

To many of us web/SharePoint developers, discovering jQuery made us love JavaScript again. Finally, here was a JavaScript library that made sense. It made everything a thousand times easier. Within years, jQuery had become the ubiquitous hammer in everyone's tool belt.

On the server side, SharePoint shipped with a complex Client Object model, REST services, and it is incredibly easy and flexible to build your own web services and use them in your solutions.  Even for SharePoint 2007, SPServices has made huge improvements in bridging how you can talk to the server.

There is one final piece of the puzzle: how do we easily fit data that we've obtained from the server back into the web UI seamlessly? What if there's a way to do data binding, MVC/MVVM style, and leave both the object and the UI robust and free of spaghetti code?

Knockout solves one of the most difficult remaining problem in creating complex business solutions entirely using JavaScript.  If you thought jQuery alone is awesome.  Discovering Knockout is like finding another beautiful library like jQuery all over again!

In this session, John will demonstrate how to build a fairly complex system using Knockout and jQuery.  As well as show examples of some of the systems that he's been building and the flexibility you can easily achieve with Knockout.

So bring your developer hats and be prepared to enjoy an evening of new exciting techniques!  Don't be afraid to ask questions too!

Teaser Picture

image

Figure: this is your SharePoint task list, but supporting drag and drop!

 

See you at the Sydney SharePoint user group.

InfoPath how to copy a repeating section using rules

For years, we all thought this was impossible.  You had to use code.  I somehow woke up with an idea on how to do this, and set about testing and to my surprise, found a solution.  Here it is!

 

The form set up

image

  • Two repeating sections, Foo's and Bar's
  • One additional integer field i to control which row to copy

Put the elements on the form:

image

 

 

The copy rule

Create a rule on the integer field i

  1. We will use the normal action, then tweak it. 
    Give this rule the name "Copy"
    Start by defining a set field value rule.
    image
  2. Set /my:myFields/my:Foos/my:Foo/my:F1 to /my:myFields/my:Bars/my:Bar/my:B1
    image

    There are a few issues so far with the default Set Field Value action related to a repeating section.
    • For the Field (target), it will set ALL the matching nodes.
    • For the Value, it will get the First matching node.
  3. Let's fix the second value - we can do this in InfoPath designer.
    image

    The expression is:
    ../my:Bars/my:Bar[number(../../my:i)]/my:B1

    This expression lets us copy a different row.

    image

    So we can now copy value from any row - depending on what the number i is.
  4. To fix the Field Target is a bit more difficult.  InfoPath designer doesn't give us a way to modify the XPath of the field.

  5. Save the form.  We're about to do unsupported stuff. 
  6. Publish the form to Source Files. 
    image

    I publish to C:\Temp\CopyForm\
  7. Close InfoPath designer.  Open the file C:\Temp\CopyForm\manifest.xsf file using NotePad or your favourite XML editor.
  8. The "Copy" rule is hiding in this XML file, it looks like this:
  9. <xsf:rule caption="Copy">
        <xsf:assignmentAction targetField="../my:Foos/my:Foo/my:F1" expression="../my:Bars/my:Bar[number(../../my:i)]/my:B1"></xsf:assignmentAction>
    </xsf:rule>

  10. Change it to:
  11. <xsf:rule caption="Copy">
    <xsf:assignmentAction targetField="../my:Foos/my:Foo[number(../../my:i)]/my:F1" expression="../my:Bars/my:Bar[number(../../my:i)]/my:B1"></xsf:assignmentAction>
    </xsf:rule>
  12. Save, and close Notepad.  Re-open manifest.xsf file using InfoPath Designer
  13. Let's check our rule.
    image
  14. Are you thinking what I'm thinking?  We're nearly there.

The loop

  1. This rule is set on the number i, and runs once whenever the number i changes.
  2. Lets set it up to increment.
    image
  3. Add a condition to stop incrementing when we've run out of rows
    image

    image
  4. And to start the whole thing, remember we have a button.

    image

    To start the process, set i to 1.  XML index starts from 1 to n.  Does not start at 0.

 

Result - InfoPath Filler


image
Starting...

image

Press "Copy"

Result - Form Server:

image

Starting Browser Form

image

Copy.

 

Note - InfoPath "Infinite Loop" limitation:

InfoPath is hard coded to only execute 16 rules before throwing the "Infinite Loop" error.

image

An error occurred in the form's rules or code. The number of rule actions or the number of calls to the OnAfterChange event for a single update in the data exceeded the maximum limit.

The rules or code may be causing an infinite loop. To prevent this, ensure that the rule action or event handler does not update the data which causes the same rule action or event handler to execute.

 

There is no solution for hard coded 16 rules.  So your i can not go over 16.

Download