Site Meter
 
 

Knockout.js 1.2.0 released

Earlier today I published the final 1.2.0 build of knockout.js. This is a big release with stacks of new goodness since 1.1.2:

  • Changed the license to MIT (more permissive than the previous license, MS-PL)
  • Added useful new bindings: event, attr, html
  • Enhanced some existing bindings: options, checked
  • Enhanced templating features (now supports jquery.tmpl 1.0.0pre as well as previous versions, template polymorphism, passing additional data via options)
  • Various performance improvements (e.g., now precompiles and caches templates, and ensures all data/subscriptions associated with DOM elements are cleaned immediately when those elements are removed) plus bugfixes
  • Better compilation style (ensures Closure Compiler no longer adds any extra variables to global namespace)
  • Various new extensibility points requested by plugin authors
  • Minor syntactical improvements (e.g., added zero-arg constructor for observable arrays)
  • All documentation updated to match 1.2.0

Thanks very much to the many people who have contributed ideas, pull requests, bug reports, and support to make this release possible! I’m really enjoying the community that’s growing around this.

Hang on, what’s Knockout.js?

In case you’ve never heard of it, here’s tekmaven’s explaination: Smile

image

(By the way, for Visual Studio developers: Install-Package knockoutjs)

More specifically, Knockout is a JavaScript library for building rich, responsive user interfaces. It uses automatic dependency tracking and declarative bindings to update your UI whenever your data model changes, letting you cleanly structure your code around the MVVM pattern.

No, that’s just marketing blather… show me something real

OK then, to learn more:

MvcScaffolding: Scaffolding custom collections of files

This blog post is part of a series about the MvcScaffolding NuGet package:

  1. Introduction: Scaffold your ASP.NET MVC 3 project with the MvcScaffolding package
  2. Standard usage: Typical use cases and options
  3. One-to-Many Relationships
  4. Scaffolding Actions and Unit Tests
  5. Overriding the T4 templates
  6. Creating custom scaffolders
  7. This post: Scaffolding custom collections of files

Previously you’ve seen how to modify the output from existing scaffolders (by overriding their T4 templates) and how to create custom scaffolders that take arbitrary parameters and render new templates of their own.

But what if, instead of generating just a single file, you want to generate multiple files that all work together? Well, it’s not surprising that you can do so.

  • You can put multiple Add-ProjectItemViaTemplate commands in your PowerShell file. You can generate as many different files, using as many different templates, as you want.
  • You can invoke one scaffolder from another. For example your custom scaffolder logic can contain “Scaffold Controller” or “Scaffold View” instructions to generate controllers and views using the built-in logic.

In this final post in the current MvcScaffolding series, I’ll show how some of these ideas can be tied together to build something useful.

Example: An Ajax-powered Controller

I showed an example of doing this in my MvcConf talk (video here) a couple of months ago, when I built a custom ControllerWithAjaxGrid scaffolder. This custom scaffolder produces a controller (obviously), but instead of having the usual index/edit/details/delete views, it just has a single view that contains an Ajax-powered grid from which the user can view, add, edit, and delete records. Videos are hard to reuse code from, so for your convenience I’ll reproduce the code in this blog post.

To see it in action, download the demo project, and then scaffold an Ajax-grid controller for the included StockItem model by executing “Scaffold ControllerWithAjaxGrid StockItem” in the console:

SNAGHTML2e143ef5

Run the controller by launching the application and navigating to /StockItems:

image

It uses jqGrid to do all the client-side stuff. By the way, if you’re wondering how to make jqGrid do different things like sorting or filtering, don’t ask me, I have no idea – talk to the experts! Let’s keep this post focused on the scaffolding side of things.

How ControllerWithAjaxGrid Works

I won’t list all the code for ControllerWithAjaxGrid and its template – you can download the runnable demo project for that. As an outline of how it works, ControllerWithAjaxGrid.ps1 contains the following instruction to create the controller itself:

Scaffold MvcScaffolding.Controller $ModelType -Project $Project `
    -CodeLanguage $CodeLanguage -OverrideTemplateFolders $TemplateFolders `
    -NoChildItems -Force:$Force

This inherits all the normal controller-scaffolding logic (e.g., knowing which folder to output the class file into) from MvcScaffolding.Controller, and merely overrides location where the T4 template is found (using –OverrideTemplateFolder). I was then able to put a ControllerWithContext.cs.t4 file in my custom scaffolder’s folder and hence override the code that gets generated. My custom controller template returns JsonResult data to support the Ajax grid. For example, here’s the template for its GetData action:

public JsonResult GridData(int rows, int page)
{
    var count = _context.<#= modelNamePlural #>.Count();
    var pageData = _context.<#= modelNamePlural #>.OrderBy(x => x.<#= Model.PrimaryKey #>).Skip((page - 1) * rows).Take(rows);
    return Json(new {
        page = page,
        records = count,
        rows = pageData,
        total = Math.Ceiling((decimal)count / rows)
    }, JsonRequestBehavior.AllowGet);
}

Similarly, my custom controller doesn’t need all the usual views – it only needs one that contains the JavaScript code to display the grid. I generate that view using a “Scaffold View” command in ControllerWithAjaxGrid.ps1, again using the –OverrideTemplateFolders parameter to make the View scaffolder load the T4 template from ControllerWithAjaxGrid’s folder.

One interesting thing about the view template is that it gets a list of all the properties on your model class:

<# var properties = viewDataType.VisibleMembers().OfType<codeProperty>(); #>

… then later uses this to generate some JavaScript code relating to each property:

<script type="text/javascript">
    jQuery("#ajaxGrid").jqGrid({
        ...
        colNames: [<#= string.Join(", ", properties.Select(prop => "'" + prop.Name + "'")) #>],
        ...
    });
</script>

Finally, my custom controller needs to be sure that there is actually a data context class that it can use for data access. This is easy to arrange: I just put the following command in ControllerWithAjaxGrid.ps1:

Scaffold DbContext $ModelType -DbContextType ((Get-Project $Project).Name + "Context")

You can see I’m using the convention that the data context class should be called ProjectNameContext, but you could change that if you wanted.

For the full code including the T4 templates, download the demo project.

Conclusion

You could use the same techniques to create other custom controller types with different combinations of views, data access classes, and so on.

If you’re unfamiliar with PowerShell then it might take a bit of learning, but once you’ve got a custom scaffolder to suit your project’s requirements, you can commit your /CodeTemplates folder into source control, and then everyone on your team can quickly generate controllers in the style you’ve defined, supplying whatever custom parameters you’ve declared.

For more information about creating custom controllers, see the tutorial in my previous blog post and the list of useful cmdlets for custom scaffolder scripts.

MvcScaffolding: Creating custom scaffolders

This blog post is part of a series about the MvcScaffolding NuGet package:

  1. Introduction: Scaffold your ASP.NET MVC 3 project with the MvcScaffolding package
  2. Standard usage: Typical use cases and options
  3. One-to-Many Relationships
  4. Scaffolding Actions and Unit Tests
  5. Overriding the T4 templates
  6. This post: Creating custom scaffolders
  7. Scaffolding custom collections of files

Intro

If you only ever want to generate controllers, actions, repositories, and the other item types built into MvcScaffolding, it’s enough just to customise the T4 templates for them. But what if you want to generate something different, for example configuration files, build scripts, CSS files, JavaScript files, or something else? Or what if you want to generate combinations of multiple interrelated items?

You can create a custom scaffolder that uses arbitrary PowerShell logic. It can render T4 templates (multiple ones if you want), with the result being output:

  • As a new file in your project
  • Or, as a new code block inserted into an existing class

Or, your PowerShell logic can use Visual Studio’s “code model” API to manipulate files and code elements in other arbitrary ways.

Example: Scaffolding jQuery Plugins

Note: The rest of this post assumes you’ve already got MvcScaffolding installed. If not, see the earlier posts in this series for an introduction.

Let’s say your team uses jQuery plugins all the time. Every separate bit of client-side functionality is implemented as a separate jQuery plugin. So, to speed this up and to gain better consistency, you want to make a scaffolder that generates the outline of a jQuery plugin. To get started, run the CustomScaffolder scaffolder, giving the name jQueryPlugin for your new scaffolder:

SNAGHTML2dbba9a7_thumb1

Yes, CustomScaffolder is a scaffolder that generates other scaffolders. I find this pleasing in a recursive kind of way.

This adds a CodeTemplates folder to your project, containing files for the new scaffolder:

image_thumb5

As you can see, we’ve got two files:

  • A PowerShell script (.ps1), where we can put arbitrary logic to decide what templates get rendered and where the output goes. By default, it renders a T4 template and uses the output to create a new file called ExampleOutput in the root of your project.
  • A T4 template (.t4), i.e., the thing that the default .ps1 file renders. By default this generates a simple C#/VB class (depending on your project type).

If you want to see this working, you can run the custom scaffolder right away:

Scaffold jQueryPlugin

This will generate a new class file, ExampleOutput.cs, in the root folder of your project. That’s really just to show you how it works. We don’t really want that, so don’t run the new scaffolder yet, or if you already have done, delete ExampleOutput.cs.

Making it do something useful

Here’s the design for our jQueryPlugin scaffolder:

  • It will take two parameters: PluginName (mandatory), and HasOptions (an optional switch that modifies the JavaScript code we generate).
  • It will render a T4 template, passing those parameter values to it. The template will produce the outline of a jQuery Plugin JavaScript file.
  • The output will create a new file, /Scripts/jQuery/jQuery.pluginname.js

To actually implement this, you either need a passing familiarity with PowerShell, or at least the willingness to play around with the default script and try to modify it to suit your requirements. It’s a bit out of scope for me to try to teach PowerShell in this blog post, so let’s skip to the completed implementation. Here’s my finished jQueryPlugin.ps1 file:

[T4Scaffolding.Scaffolder(Description = "Creates a jQuery Plugin code file")][CmdletBinding()]
param(
    [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$PluginName,
    [switch]$HasOptions,
    [string]$Project,
    [string]$CodeLanguage,
    [string[]]$TemplateFolders,
    [switch]$Force = $false
)
 
$outputPath = "Scripts\jQueryPlugins\jQuery.$PluginName.js"
 
Add-ProjectItemViaTemplate $outputPath -Template jQueryPluginTemplate `
    -Model @{ PluginName = $PluginName; HasOptions = $HasOptions.IsPresent } `
    -SuccessMessage "Added jQuery plugin at {0}" `
    -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage -Force:$Force
 
Write-Host "---"
Write-Host "To reference your new jQuery plugin, copy the following script reference into your layout:"
Write-Host "<script src=`"`@Url.Content(`"~/$($outputPath.Replace("\", "/"))`")`" type=`"text/javascript`"></script>" -ForegroundColor DarkRed -BackgroundColor Gray
Write-Host "---"

I appreciate this may be a bit alien if you’ve never seen PowerShell before, but it’s not actually so bad:

  • The first few lines define metadata about the scaffolder itself – its description, and a definition of the parameters it takes (including saying which are mandatory/optional).
  • Add-ProjectItemViaTemplate is a cmdlet built into T4Scaffolding. It renders a T4 template (in this example, one called “jQueryPluginTemplate”) and creates a new file in your project containing the output (in this case, in the folder “Scripts\jQueryPlugins\”). You can pass whatever data you want from the PS1 script to the T4 template (in this example, we just pass the PluginName and HasOptions parameter values). See the end of this blog post for more info about T4Scaffolding’s built-in cmdlets.
  • Write-Host emits text into the console itself. In this example, we’re using it to supply useful information to the developer – an example <script> tag they can paste into their layout to reference the JavaScript file they just generated.

Next, we need the T4 template that defines the JavaScript code we want to generate. Here’s my finished jQueryPluginTemplate.t4 file. If you’ve written jQuery plugins before, this will probably look very familiar:

<#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #>
// ----
// <#= Model.PluginName #> jQuery plugin
// ----
(function ($) {
    $.fn.<#= Model.PluginName #> = function (<# if(Model.HasOptions) { #>options<# } #>) {
<# if(Model.HasOptions) { #>
        var allOptions = $.extend({
            // TODO: Put default option values here
        }, options);
 
<# } #>
        return this.each(function () {
 
            var $this = $(this);
            // TODO: Add code here to operate on $this
 
        });
    };
})(jQuery);
Running the custom scaffolder

Now, you can invoke your custom scaffolder to generate jQuery plugins from the console. There’s full tab-completion support, so developers can auto-complete not just the name of your scaffolder (jQueryPlugin), but also the names of the custom parameters it takes.

SNAGHTML2dd907cd_thumb1[3]

This will generate a JavaScript source file at Scripts\jQueryPlugins\jQuery.reverseText.js, containing:

// ----
// reverseText jQuery plugin
// ----
(function ($) {
    $.fn.reverseText = function (options) {
        var allOptions = $.extend({
            // TODO: Put default option values here
        }, options);
 
        return this.each(function () {
 
            var $this = $(this);
            // TODO: Add code here to operate on $this
 
        });
    };
})(jQuery);

Once you’ve referenced this script file (e.g., by copy & pasting the example <script> tag emitted to the console), you can use your new plugin to operate on the HTML elements that match a jQuery selector, e.g.:

$(".someClass").reverseText();
A runnable example

Download the demo project, which contains the jQueryPlugin custom scaffolder. You can run it from the Package Manager console as follows:

Scaffold jQueryPlugin somePluginName             # Like this...
Scaffold jQueryPlugin somePluginName –HasOptions # ... or like this

Useful Scaffolding Cmdlets

In the preceding example, I demonstrated the use of Add-ProjectItemViaTemplate, a PowerShell cmdlet included in the core T4Scaffolding package (installed automatically when you install MvcScaffolding).

There are many other useful cmdlets included in T4Scaffolding that you can use from your custom scaffolders, for example to:

  • Render T4 templates
  • Inspect and modify files in your solution’s projects
  • Inspect and modify code elements in your classes
  • Detect primary keys and 1:many relations on entity classes
  • Interact with source control bindings
  • … or merely to pluralise words.

For a list of examples, see this wiki page on CodePlex.

Conclusion

With a bit of PowerShell-fu (or a bit of copy-paste-existing-examples-fu), you can make your own scaffolder that:

  • Takes a custom set of parameters
  • Renders a custom set of T4 templates
  • Sends the output to a custom set of locations in your project or in existing classes

Once you’ve made it, it’s easy to share with colleagues: just commit your /CodeTemplates folder into source control, and then anyone working on your project will be able to run your scaffolder

In the next post, I’ll present a slightly bigger example that does output multiple files, and produces a different type of controller with an Ajax-powered grid in its view.