Tuesday
Apr032012

InfoPath, custom WCF Service, Word and Open XML SDK (outline)

This upcoming series of articles promise to be far more exciting than the title.

Scenario

How do you use an InfoPath form document to populate a word document with content controls. 

 

Steps:

  1. Building a Word document template with Content Control place holders
  2. Use Content Control toolkit to bind values to place holders in the template to an embedded custom XML (hey, isn't an InfoPath document an XML file?)
  3. Creating a WCF service to take a Word template document, and replace the custom XML, by the power of Open XML SDK (2.0, of course).
  4. Invoking the WCF service from within an InfoPath document to generate a word template version of itself!
  5. Finally, a bit of discussion on where Word Automation services fits in the bigger picture, as well as thoughts on best practices.


Drop a comment below if you have any specific questions relating to these steps.  Specifically, if you can think of a far better title for this series.

Otherwise, stay tuned!  :-)

Tuesday
Mar272012

InfoPath - disabling backspace key in browser form

How to disable the backspace key using Javascript/jQuery for an InfoPath browser form in SharePoint 2010.

 

The problem

One really troubling problem with almost all web solutions is how the Backspace key works.  By default, it tells your browser to go back to the previous page in history.

If you are just browsing around on your Intranet, this is probably not a big deal - firstly, you wouldn't be pressing backspace unless you actually wanted to go back.  Secondly, if you did indeed made a mistake and pressed the backspace key, you'd just undo that action by clicking the forward button, or navigate to another link.  No problem.

 

When you are filling in a form on the browser though, such as through InfoPath, suddenly the backspace key is a big deal.  You users may be using the backspace key to delete text that they are in the middle of entering.  And if they didn't have a textbox focused, the backspace key is sent to the browser form, and suddenly you have a problem.  The form disappeared, and you have lost information.

 

InfoPath is quite smart - it remembers which view you are supposed to be on, and when you navigate to an outdated browser historical view of the form - Form Server will automatically redirect you forward to show you the correct form you are supposed to be viewing.  This is good, at least in the navigation sense.  So the only remaining problem is the lost data - your user may have had a whole page filled out and this mistake has just cleared their form.  Not good.

 

Enter Javascript

So, the plan is simple:

  1. Inject javascript to the existing browser form
  2. Listen to keydown event for a backspace key (keycode 8)
  3. Eat the event and stop it from propagation, so the browser don't see it

Using jQuery, you'll need this simple function.

 

function document_keydown(e) {
    if (e.keyCode == 8 && e.target.tagName != "INPUT") {

        // letting us know we've ate a backspace key
        SP.UI.Notify.addNotification('Ate a backspace key, hew!', false);

        // cancel backspace navigation
        e.preventDefault();
        e.stopImmediatePropagation();
        return false;
    }
};

$(document).keydown(document_keydown);

 

Injecting Javascript in modal dialog

 

If you are using SharePoint 2010's modal dialog to show InfoPath in a modal popup, it's slightly trickier.

 

// grab a reference to the modal window object in SharePoint
var w = SP.UI.ModalDialog.showModalDialog(options);

if (w) {
    // get the modal window's iFrame element
    var f = w.get_frameElement();

    // watch frame's readyState change - when page load is complete, re-attach keydown event
    // on the new document       
    f.onreadystatechange = function(e) {
        if (f.readyState == 'complete') {
            var fwin = f.contentWindow || f.contentDocument;
            $(fwin.document).keydown(document_keydown);
        }
    };
}

Result

 

nom-nom-nom backspace keys.

image

 

Note, because the Javascript catches the keypress event at the document level.  If your user still has focus on the input (textbox) level, the event will not be stopped - so your user still will be able to backspace when they are using a textbox.

Friday
Mar232012

Re: Sorry dad, you'll understand, someday

This is a quick blog post, in response to Zac Gorman's excellent Magical Game Time comic.

http://magicalgametime.com/post/19718347285/ill-stop-when-ive-saved-the-world-and-fallen-in

As you play through the game Earthbound as the kid protagonist Ness, your phone would ring every few hours, and your dad would ask you if you'd like to take a break.  If you say Yes, it'd save the game and switch it off.

The comic cleverly replies as Ness: I'll stop when I've saved the world and fallen in love.  (Sorry dad, you'll understand someday).

 

My boy is still three, he doesn't understand about saving the world, or falling in love, yet.  I'm sure he will soon.  And here'd be my response to him:

  • All dads were boys once.
    We already understood.
  • So off you go, save the world.
    Go and fall in love with your girl.
  • You do what you have to do.
    This is your time, we don't expect you to hold back, or stay at home.
  • When you are tired from saving the world, stop by and have some hot chocolate and ice cream.
    We will always be your biggest fan.

 

We will return to our regular SharePoint updates soon. 

Wednesday
Mar212012

AUSPC 2012 summary

I had an awesome time presenting Building your own custom REST Services and consuming them with jQuery AJAX in the Australian SharePoint Conference 2012.  A big thank you to the developers that came and geeked out with me for an hour on a Wednesday afternoon.

Notes

When you build a custom WCF Service using the CKS template, it is deployed to a subfolder the web front end's ISAPI folder, which, in turn, is mapped to the site's /_vti_bin/ folder.

image

 

It appears that in my earlier attempt to create an incomplete version of the REST service template item, I interfered with how CKS's templates worked - and correct features for deploying the WCF service is no longer being included in the package.  While existing items were updated and deployed, the new WCF service that I was creating wasn't being deployed to the ISAPI folder.

I've removed the REST template item from my Visual Studio .NET environment, and voila - the WCF services deployed nicely once again.

So that's one mystery resolved.  Now I scratch my head about how to fix my VS.NET REST template item.

 

Downloads

Tuesday
Mar202012

AUSPC 2012 quick update

I'm in the strange and calm interlude between day 1 and day 2 of awesomeness in the annual Australian SharePoint Conference (AUSPC) 2012.

Day 1 has been a lot of fun.  Manned the user group booth in the morning with Dan Brown.  Met many of the SharePoint guys in the community that I haven't seen for the last 6 month to a year.  Talked to a number of vendors, and attended a number of awesome sessions on the developer track.

I also got to sit on the panel answering developer questions amongst the legends like Nick Hadlee, Ishai Sagi, Brian Farnhill and Jeremy Thake

The oddest part is probably with MCA SharePoint Wayne Ewington sitting in the audience.  Every time we said something silly he'd start shaking his head and we'd all stop.  Hilarious.

 

Tomorrow morning, my session on Building your own custom REST Service and consuming them with jQuery AJAX is running in the developer track at 10:30am.  Hope to see everyone there.

All my related resources and presentations on this topic are summarized on http://johnliu.net/rest

Thursday
Mar012012

Dummy guide to install Win 8 on VHD for Boot to VHD

 

Summarized from:

You'll need:

 

Set up boot to VHD!

  1. Create a VHD

clip_image001

clip_image002

Note: I make this a dynamic disk, although I allocated up to 60GB, it only uses what it needs which was about 10 GB.

 

clip_image003

clip_image004

clip_image005

clip_image006

clip_image007

clip_image008

clip_image009

Created, and attached the VHD to Y:

 

Load the ISO into a virtual CD drive, mine is G:

I use virtualclonedrive to load ISO - this is a free utility.

clip_image001[5]

 

Next install the windows image into the VHD

Easiest way that worked for me is this wonderful powershell script.

 

clip_image001[7]

Remember to unblock this script

 

If you see:

File C:\Install-WindowsImage.ps1 cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.

You will need to allow remote script

PS C:\>set-executionpolicy remotesigned

 

PS C:\> .\Install-WindowsImage.ps1 -WIM G:\sources\install.wim

Index   Image Name

[1]     Windows Consumer Preview

Done.

PS C:\> .\Install-WindowsImage.ps1 -WIM G:\sources\install.wim -Apply -Index 1 -Destination Y:

PS C:\> .\Install-WindowsImage.ps1 -WIM G:\sources\install.wim -Apply -Index 1 -Destination Y:
Applying "Windows 8 Consumer Preview" to Y:...
WARNING: This may take up to 15 minutes...

Elapsed Time: 00:08:40.4870618

PS C:\>

 

Lastly, make the VM a boot record.

 

PS C:\> bcdboot Y:\Windows\
Boot files successfully created.

 

You can check it with bcdedit

PS C:\>bcdedit

Windows Boot Loader
-------------------
identifier              {default}
device                  partition=Y:
path                    \Windows\system32\winload.exe
description             Windows 8 Consumer Preview
locale                  en-us
inherit                 {bootloadersettings}
custom:17000077         352321653
osdevice                partition=Y:
systemroot              \Windows
resumeobject            {1abc7489-8e4b-11e0-877a-af036ca44d2f}
nx                      OptIn
custom:250000c2         1
detecthal               Yes

Windows Boot Loader
-------------------
identifier              {current}
device                  partition=C:
path                    \Windows\system32\winload.exe
description             Windows 7
locale                  en-US
inherit                 {bootloadersettings}
recoverysequence        {1abc7482-8e4b-11e0-877a-af036ca44d2f}
recoveryenabled         Yes
osdevice                partition=C:
systemroot              \Windows
resumeobject            {1abc7480-8e4b-11e0-877a-af036ca44d2f}
nx                      OptIn

 

Restart and you are off to go

 

Your PC will boot into Windows 8, which has a new happy looking boot loader.  If you feel the 30 second delay is too long, you can change the delay to 5 seconds from the boot loader options.

Thursday
Feb232012

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)\/

Wednesday
Feb222012

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

Tuesday
Feb212012

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.

Thursday
Feb162012

Curiosity drives creativity. The only limit for your kid are there because you put them there.

I watched this YouTube recently, Neil DeGrasse Tyson was being interviewed and was asked a question: what would you do as a nation to increase scientific literacy.

Neil's answer:  What do you do at home?  What do you do with your kids?  Kids needs to be able to explore freely.  The home, he argues, is not a great place for exploration.  Play in the toilet?  No.  Garage?  No.  Kitchen?  No, no, no.

The kid goes to the kitchen and starts to bang pots together, you tell him to stop.  The consequence of stopping a kid, is stopping a kid from exploring.  The seeds of curiosity are the foundations of science.  The parents need to get out of the way. 

If the kid pulls petals from a  $10 flower you bought from the florist, but discovers an interest in biology.  That's the cheapest $10 you've ever spent on his education!

 

iPad, and Technology

fernbedienung2.jpg (700×503)Many of us marvelled at our children being able to pick up an iPad and use it right away.  We say surely this is proof of Apple's solid design principles, even a three year old kid can master this technology at ease.

That may be the case, but I've beginning to really wonder.  When was the last time you let your kid explore your keyboard?  He's banging and breaking your keys?  If you don't let him experiment, how would he know what banging the keys together does? 

Mr 3 presses the back button on the iPad.  It quit his favourite game.  He knows for certain that is NOT the button he wants to press when he is playing his favourite game.

I got a new Samsung LCD TV, it comes with an extremely complicated remote control.  Mr 3 learned how to use it to get to his cartoons in the morning and switch to Simpsons in the evening before sleep.  He can even switch input sources between HDMI (XBox) and normal Digital TV channels!  Look at this thing: My kid can operate this, can you?

 

Dungeons and Dragons, and story telling

I was convinced that he will enjoy playing board game, and in particular, dungeons and dragons with me. 

Lots of parents are doing this.  A game that you can play with your kid, and helps them on mathematics, story telling, spelling, imagination.

Considering that he is still wet behind the ears, I opted for D&D-lite: HeroQuest.

WP_000443

He is three.  He is playing his dwarf hero here, trying to cheat the dice roll because he knows he needs to get "skulls" on the dice to hit the Ogre.  Along the way, he has already fought off:

A goblin, an orc, 3 chaos warriors - one whose helmet is now stuck in the fireplace, and 1 skeleton.  The goblin had a pretty nasty bump on the head - he says the goblin shouldn't sleep on the floor because it's dirty.  We put him on the table, and use the empty treasure chest as a pillow.

  • I asked him as he comes near a door - do you want to open the door?
  • He says: Yes, open the door, see what's inside.
  • I put down a skeleton
  • He says: Skeleton! 
  • I asked him, what are you going to do?
  • He says: Run away - and proceed to yank the dwarf all the way back to the beginning.  I had to stop him and tell him that he can fight by rolling the dice.

Dungeon Master tip for dads:

If your kid is running low on HP, make sure he "finds" a healing potion next time he searches a table, door, monster's dead body.  Don't make things too easy, but don't get them killed.

 

I'm realizing something

This is probably my take home message and something I'll try to remind myself my whole life.

Your kid knows no limits. 

All the limits in his life, are put there by adults

 

People tell him he can't try to do something.  He can't go somewhere.  He isn't tall enough to go on a ride. 

The box on HeroQuest says ages 7+.  Did that stop Mr 3?  Who puts these age limits on game boxes?

You know, I hope it's not yet too late.  I ask him to do something, and he tries, but he fails, and he tells me:

I can't do it

It breaks my heart.  No, it's OK, you can.  Try again, I'll help you, let's try again.

 

Let your kid paint their room

This is something I've read separately, and actually got Lina to agree:

We will leave the interior decoration of our kid's room to himself.  Within his room, he can paint his walls.

We're in a new house.  He is free to paint anywhere on the walls in his room.  Why limit him?  Re-painting his wall is easy.  But the memories and his creativity being cultivated - those are absolutely priceless.

 

Say less No.  Say more Try

This is so much easier to write than to live.  When your kid is being silly and driving you crazy, can you really hold back on the No?

John, let your kid try.  Say less NO, say more TRY.

Page 1 ... 3 4 5 6 7 ... 36 Next 10 Entries »