Friday, October 31, 2014

ngEurope: what's new in Angular 1.3?


Angular 1.3 provides us with some improvements over an already very decent framework. At ngEurope, the sessions were fast and intensive, which was an interesting approach, but also didn't allow for very many details. That being said, here are the points I noted.

$compileProvider.debugInfoEnabled(false);

This allows you to disable all the debugging info for the code you will deploy in production. Read more about it in the docs.

$httpProvider.useApplyAsync(true)

Normally, returning from an HTTP call will trigger Angular's $apply function. If you are doing several HTTP calls in succession, it might be interesting to only call the $apply function when they have finished. The useApplyAsync function gives you that possibility. Setting this to true will make Angular wait for HTTP calls that finish close together to finish, before calling $apply.

one-time binding (with ::)

Finally! One-time bindings allow you to make Angular forget about the binding once it has rendered it. This can improve performance, especially when you have a lot of bindings that no longer change once the result of the binding was rendered. Doing so is easy: just prefix your binding with '::', like so:

<span>{{::user.name}}</span>


Now, Angular will no longer track changes to this property

ng-model-options="{debounce: 500}

This waits 500ms before updating the binding. This can be useful when the updating of your binding could take a while.

ng-model-options="{updateOn: 'blur'}

If you've used WPF, this is the equivalent of UpdateSourceTrigger. The updateOn option accepts any javascript event and does just that: it updates the model when the given event is raised.

allOrNothing

The allOrNothing feature prevents Angular from making an HTTP request when it doesn't make any sense. For example this:

ng-src="users/{user.id}/avatar.png"

will not make an HTTP request if user or user.id is undefined.

Finally, ngMessages allows for easier validation messages.

So that is what I learnt from the session about Angular 1.3. It's just a quick overview, but it's good to know what's possible. When you're facing a particular situation, and you know Angular has a solution for it, you won't feel the need to implement a solution yourself. You can just go check out the documentation.

Thursday, October 30, 2014

ngEurope: quick overview

Team4Talent, the company I work for, was kind enough to allow me to go to ngEurope in Paris. ngEurope is Europe's first Angular conference. In a few upcoming posts, I'll share what I've learnt, along with some personal thoughts of mine. I'll also (try to) answer some questions several people asked me. But if you can't wait, the conclusion is that I love Angular and plan to use it. Where I work at the moment, we've decided HTML5 and javascript in general, and Angular specifically, are to be considered for future projects. For personal projects, I've already used it once, am developing with it now (using Cordova), and plan to use it in the future.



First, a quick thanks to my company for sending me, and the ngEurope team for organizing ngEurope. The concept was a little different from other conferences I've attended in the past. Most have 45-60 minute talks. ngEurope had 15-30 minute talks. Also refreshing (for me) was the fact that it was totally not Microsoft or .NET centric.

Less positive was the lack of wifi. After someone obtained the password and tweeted it, the wifi was of course flooded and thus very slow. A conference for (mainly) web developers without wifi... A bit of a shame actually. Also a lack of vegetarian food (fish doesn't count), beamers in the back that only started working a few slides into the presentation,... A little rough around the edges, but I'm still happy I went.

That being said, let's get to the most important stuff: the tech and the code!

I will dedicate separate posts to the parts I found most interesting, so here are some subjects that didn't make it. This can be either because I didn't find them interesting enough (a personal opinion) or because they warrant a bigger post (or multiple posts) all by themselves (and I don't have the time right now).

New to AngularJS?

 

There's lots of places to start. I started with the free Angular course at codeshool.com by Gregg Pollack. If you're subscribed to Pluralsight or Egghead.io, they have good courses too. Also worth mentioning is Dan Wahlin's AngularJS in 60ish minutes. Give (one of) them a go and you'll see it's not hard to get started, but it's powerful when you're an expert. Something I'm totally not, by the way.

Ionic

 

Ionic is a very cool UI framework for building Angular apps on Cordova (the open source part of PhoneGap). It makes your app look and feel like native iOS or Android apps. No Windows Phone yet.


Cordova

 

Cordova is the open source part of PhoneGap. Provided you have npm installed, starting is as easy as doing:

    npm install -g cordova
    cordova create MyApp

This will scaffold a Cordova app, but it won't do anything Angular for you. That's a whole separate domain altogether. One which I'm only finding out about myself just now. But have a look at the ngCordova project for a set of Angular services that talk to Cordova. There are also Yeoman generators to get started.

i18n Internationalization

 

This is a good way of internationalizing your Angular app (though there is basic support for i18n already). It works with filters or directives. Filters are less performant but can update on the fly, while directives need a page refresh if the language is changed. There's also support for gender and plurals.

Angular UI Bootstrap

 

This is a set of Angular directives based on Bootstrap CSS. You can find it here.

Those are some short items worth checking out. Next up: a quick overview of what's new in Angular 1.3.

Also worth checking out

 


In subsequent posts, I'll dive a little deeper into sessions that I found interesting.

Wednesday, October 29, 2014

Collecting all errors of ValidationRules in WPF

Almost all articles on WPF and validation focus first on ValidationRules, and then continue telling you why IDataErrorInfo is better. A few go on and show you how to combine IDataErrorInfo with DataAnnotations.

While these last two are definitely good options, they're a little heavy for a very simple application. In my case: call a server, show the data (about 20 textboxes), send back to the server. Nothing fancy, I'm even databinding to my datacontract (gasp!), although I'm sending back a separate datacontract (with only the changeable properties).

This may go against best-practices, but I feel best-practices differ depending on the complexity of the problem you're trying to solve. In this case, in my opinion, it's okay to do what I'm doing.

I've added validation via ValidationRules. The problem lots of sources will tell you, is that there's no way of aggregating these errors. Collecting these errors can be handy for displaying them, disabling a save-button, etc.

However, there is a way. And a fairly easy one too. Whenever a validation changes (from fail to success or from success to fail), it raises a RoutedEvent: the Validation.Error attached event (if NotifyOnValidationError is set to true).

And what is a characteristic of RoutedEvents? They "bubble up". So you can handle them higher up in the UI tree.

In the control containing your validated controls, add a Validation.Error event handler and you will be able to catch the errors of containing controls. You could handle them like this:


private void Validation_OnError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
        _errors.Add(e.Error);
    else
        _errors.Remove(e.Error);

    SaveButton.IsEnabled = !_errors.Any();
}


Note: if you're using MVVM, you're probably better of using IDataErrorInfo (yes Stefaan, I'm saying you're right ;).

Monday, September 8, 2014

Serializing private fields with JSON.NET and GetSerializableMembers

JSON.NET can handle serializing and deserializing private fields, but you have to tell it to do so.

In the past, you had to set the DefaultMembersSearchFlags property of the ContractResolver of your settings. But this property is now marked obsolete. The documentation/Intellisense tells you to override GetSerializableMembers instead.

But I've found there's just one extra step involved.

First thing to do is to create your own class that inherits from DefaultContractResolver and override the GetSerializableMembers method:

protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
    var result = base.GetSerializableMembers(objectType);

    if (objectType == typeof(MyClass))
    {    
        var memberInfo = objectType.GetMember("_myField", 
                BindingFlags.NonPublic | BindingFlags.Instance).Single();
        result.Add(memberInfo);
    }

    return result;
}

This will make sure JSON.NET serializes the private field, but it didn't seem to deserialize it in my case. The solution is to also override the CreateProperties method and set the property as... Readeable.

Curiously enough, you have to set the property as Readable, not Writeable. If anyone knows why, feel free to let me know (I have no time now to check the source).

Anyway, this is more or less what my code looks like now:

protected override IList<jsonproperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
    var properties = base.CreateProperties(type, memberSerialization);

    if (type == typeof(MyClass))
    {
        var property = properties.Single(x => 
                 x.PropertyName == "_myField" 
                 && x.DeclaringType == member.DeclaringType);
        property.Readable = true;
    }
    
    return properties;
}

Thursday, September 4, 2014

Seeing more code in Visual Studio and adding a Command to a Menu in a Toolbar

I spend most of my time in Visual Studio. My work time, that is, although it probably takes up a big portion of my overall life too... ouch!

I like to have a clean Visual Studio, void of toolbars, icons, panels,.... I'll summon them when I need them, but most of them I rarely need. I keep a strip at the bottom (collapsed) with things like Output, Error List, Unit Tests, etc. This is the one on my work-PC (not my personal PC, I wouldn't choose to work with TFS :)


To the right, I have my Solution Explorer and Properties (and at work, Team Explorer). At the top, only the main menu, no toolbars:



This allows for a clean working space, maximizing your view on what you actually work on most: the code. It reduces noise, reduces the need for splitting lines of code over multiple lines, and it pushes you to learn keyboard shortcuts, by which you increase your productivity/speed.

There's one toolbar that I've added to the right, with some things I need now and then. It's a customized toolbar so it only has the commands I need. And it's to the right, because my screen is wider than it is high, and I want to be able to see as much code as possible. Putting it to the right is less "invasive" than if I were to put it at the top.

For the buttons, I've even declared my own shortcuts (i.e. Source Control Explorer maps to ctrl+alt+shift+S). You can do this via Tools > Customize > Keyboard... Search for "View.TfsSourceControlExplorer".

It's a little harder to add a command to a menu. You can see there's a Configuration item, where I can change the active Configuration of the solution:


(To my knowledge, there's no shortcut for this, and even if there was, you need some way of seeing the active configuration)

So, adding this to such a toolbar is not that intuitive. What's more, you want to add this Command ("Solution Configurations") to a Menu inside your Toolbar. Just adding it to the Toolbar will hide it when docked left or right.

To add a Command to a Menu inside a Toolbar, first create a new Toolbar. Go to Tools > Customize and click "New...". Give it a name and then go to the Commands tab.

In the Commands tab, select the "Toolbar" radio button and select your new Toolbar from the list. Add a new menu and click the "Modify Selection" button to give it a name. The Menu inside your new Toolbar actually is a new Toolbar in itself. So select that one:


Now click "Add Command" and select (in my case) Build > Solution Configurations:
Now, dock the Toolbar to the right, and you have the result:
It's not very intuitive that the Menu inside your Toolbar lists as a new Toolbar. But once you learn to customize your Visual Studio for your needs, and for maximizing screen real estate for code, you can begin working more efficiëntly.

Friday, July 18, 2014

Angular and ASP.NET MVC: when to use which golden hammer

In my previous post, I outlined how to use ASP.NET MVC and Angular together, making certain views pure MVC and others Angular.

When I first used Angular this way, I was so happy, I went the full Angular way making requests from Angular for my data. Essentially, something like this:
$http({
    method: 'GET',
    url: '/api/rest/'
}).success(function (data, status, headers, config) {
    vm.names = data;
}).error(function (data, status, headers, config) {
              
});

This is code inside my customers.js. It's just a call to my RestController.cs (a WebAPI controller). In my customers.html template, I have a simple:
<li ng-repeat="name in vm.names">{{name}}</li>

But now, we're making two requests for something that the server could have added to our HTML anyway. This would be different if we could add a customer on the overview page, but because adding is done on a separate page, this data is actually static (from the viewpoint of the browser).

So can we keep using Angular, but let the server dynamically add anything to the page that it can? Luckily yes, and this is where, to me, we hit the sweet spot of SPAs: making the web application feel responsive thanks to Angular, but making it performant and limiting request thanks to ASP.NET.

Here's how.

Add a new (MVC) controller and a view. Make the controller return the view with the necessary data, taking care to add Angular attributes where necessary. Something like this:
@model IEnumerable<string>

<section id="dashboard-view" class="mainbar" data-ng-controller="customersmvc as vm">
    <h1>{{vm.title}}</h1>

    <a href="/Angular/#/customers/create">Create new customer</a>

    <p>
        The title of this view is rendered via Angular, whereas the customer names are added to
        the HTML on the server.
    </p>

    <div>
        <ul>
            @foreach (var name in Model)
            {
                <li>@name</li>
            }
        </ul>
    </div>

</section>

This page now combines Angular and ASP.NET MVC. This can be handy for data that is "dynamic" in the sense that it comes from a database, differs per user, etc but won't change once it's rendered in the browser.

For data that will change in the browser, you can still leverage Angular.

One final thing to take a look at is that ASP.NET MVC will set the Layout of the view you are loading. This is done in the _ViewStart.cshtml file. Of course, you want to keep this for pages loaded normally via ASP.NET MVC, but not for the ones loaded by Angular.

If we would keep this for the pages loaded by Angular, we would get our navigation, footer, etc. twice. You can easily avoid this by adding the following to the view:

@{Layout = null;}

So that's basically how I've combined ASP.NET MVC and Angular. Let me know if you've found a better or different way, or if you have any comments or questions.

Wednesday, July 16, 2014

Angular and ASP.NET MVC: now I've got two golden hammers!

Angular is a great tool, but it took me some time to find a way to combine it elegantly with ASP.NET MVC. This is basically how I did it.

First, create a new ASP.NET MVC application. Next, install the Angular package via NuGet. Now for the customization.

The objective is to use the normal ASP.NET MVC navigation, unless for certain URLs, when we'll let Angular take over.

So http://www.example.com/Account/Login would be handled by ASP.NET ("ASP.NET-mode"), but http://www.example.com/#/Customers would be handled by Angular ("Angular-mode"). Of course, it's ASP.NET serving us the Customers page, but after that, we want to use Angular for data-binding, navigation, routing, the forms, etc.

Add a new Controller with one method, Index(), that returns View(). Standard ASP.NET up until now. I named mine AngularController.

Next, add a View in the corresponding folder (in my case: /Angular/Index.cshtml). In this view, set up your main Angular view. Something like:
@{
    ViewBag.Title = "Index";
}

<div ng-app="app">
    <div ng-controller="main as vm">
        <div ng-view class="shuffle-animation"></div>
    </div>
</div>

@section scripts {
    @Scripts.Render("~/bundles/angular")
}

So when we're in "Angular-mode", we want ASP.NET MVC to include our Angular scripts. The angular bundle looks something like this (in /App_Start/BundleConfig.cs):
bundles.Add(new Bundle("~/bundles/angular").Include(
                      "~/Scripts/angular.js",
                      "~/Scripts/angular-animate.js",
                      "~/Scripts/angular-route.js",
                      "~/Scripts/angular-sanitize.js",
                      "~/Scripts/app/app.js",
                      "~/Scripts/app/config.js",
                      "~/Scripts/app/main.js",
                      "~/Scripts/app/customers/customers.js"));

The reason I'm not using a ScriptBundle is because we don't want ASP.NET to minify the Angular scripts. This causes errors because Angular sometimes depends on function arguments to be specific strings. You can read more on that here.

For now, minification isn't important, but in a production-environment, you would want to use the minified Angular scripts.

In app.js, config.js and main.js, I've put the necessary code to get Angular running. The most important part is the getRoutes function in config.js:
function getRoutes() {
    return [
        {
            url: '/customers',
            templateUrl: '/Scripts/app/customers/customers.html'
        }
    ];
}

Finally, the customers.html and customers.js contain my Angular logic and HTML markup for this specific page. This now allows you to navigate to http://localhost:1748/Angular/#/ (your portnumber may vary of course).

There you have it. ASP.NET MVC is serving the HTML page that includes references to Angular scripts and templates, the browser downloads all that, and then Angular wires it all together!

(Of course, you might want to configure ASP.NET to use a different URL for the AngularController)

Adding this to your navigation is as simple as adding this tag to your _Layout.cshtml file:
<li><a href="https://www.blogger.com/Angular/#/customers">Customers</a></li>

Don't forget the hash.

Now lets add a second page. This will make the difference between what I've been calling "ASP.NET-mode" and "Angular-mode" more clear.

Add a new html file and a new javascript file to the /Scripts/app/customers/ folder, add the route to config.js and add the javascript file to the Angular bundle in BundleConfig.cs. The link in my case would now be:
<a href="https://www.blogger.com/Angular/#/customers/create">Create new customer</a>

Now, when you run the app, navigating from /Angular/#/customers to, say, /Account/Login will load the entire new page. But navigating from /Angular/#/customers to /Anguler/#/customers/create stays within Angular, and just loads the new template, "staying inside" your SPA. You can sort of notice it because loading a new page "inside" the SPA feels faster.

So we've effectively combined classic ASP.NET MVC with Angular, allowing us to choose where we want/need which.

You can check out the source code in my GitHub repository. I've taken care to make every commit a logical step in the process.