Download as pdf or txt
Download as pdf or txt
You are on page 1of 76

SQL Reporting Services, ASP.

NET MVC, AngularJS, F#, Life after Parse

MAY
JUN
2016
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95

Create Mobile UIs with


Xamarin.Forms

Explore and Embrace AngularJS 2


Implement Lean Controllers in iOS Apps
Tame the HTML5 Audio Control
TABLE OF CONTENTS

Features
8 Parse is Set to Shut Down. Now What? 60 Implementing Lean Controllers in iOS Applications
It seems like only yesterday that Facebook acquired Parse so that Have you been struggling with sluggish apps? Perhaps all that’s needed
developers could focus more on the frontend than the backend of their is a little tightening of the code. Mohammad makes your apps lean and
apps. In January 2017, they’re shutting Parse down. mean again with a simple ToDo example.
What’s a developer to do? Jason tells us what our options are. Mohammad Azam
Jason Bender
64 SQL Server Reporting Services: Eight Power Tips
12 The Journey to Angular: Part 1
SQL Server’s Reporting Services is still the best workhorse for getting
When you wrap your JavaScript code into a closure, you won’t have data to your users. Kevin tells you how to take advantage of some of
bugs caused by unnecessary variables. Paul shows you how to do this its more subtle points.
using a templating tool called Mustache, which will help you get closer Kevin S. Goff
to coding in Angular.
Paul D. Sheriff

18 AngularJS 2
Sahil shows us a few nifty aspects of AngularJS 2 that help experienced
and novice developers alike. AngularJS 2 is still in beta, but he says
Columns
that you’ll love it even so. 74 Managed Coder: On Responsibility
Sahil Malik Ted Neward

22 Taming the HTML5 Audio Control

Departments
If you want your Web page to hold audio recordings that play when users
want them to, you’ll want to read John’s article. He shows you that it’s
not only quick, but it’s easy!
John V. Petersen
6 Editorial
28 Why F# Code
Functional programming is all the rage and Microsoft’s foray into the functional 10 Advertisers Index
world is called F#. Rachel introduces you to this first-class functional language
with the ability to harness the rich .NET ecosystem.
Rachel Reese 73 Code Compilers
34 Arranging Views with Xamarin.Forms Layout
There’s no longer a simple answer to what sort of device your page will
be viewed upon. Walt examines the options and shows you how to
make sure that yours will look great on anything, old or new.
Walt Ritscher

44 Integrating ASP.NET MVC and AngularJS


Miguel looks at organizing styles and integrating technologies to make
one spiffy new kind of app with multi-SPA layers, and you don’t have to
throw away your Microsoft experience to do it.
Miguel Castro

US subscriptions are US $29.99 for one year. Subscriptions outside the US pay US $44.99. Payments should be made in US dollars drawn on a US bank. American Express,
MasterCard, Visa, and Discover credit cards are accepted. Bill me option is available only for US subscriptions. Back issues are available. For subscription information, send
e-mail to subscriptions@codemag.com or contact customer service at 832-717-4445 ext 028.
Subscribe online at codemag.com
CODE Component Developer Magazine (ISSN # 1547-5166) is published bimonthly by EPS Software Corporation, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
POSTMASTER: Send address changes to CODE Component Developer Magazine, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
Canadian Subscriptions: Canada Post Agreement Number 7178957. Send change address information and blocks of undeliverable copies to IBC, 7485 Bath Road, Mississauga,
ON L4T 4C1, Canada.

4 Table of Contents codemag.com


ONLINE QUICK ID 00
EDITORIAL

Creative Fear
The SXSW Interactive conference has a section of the conference dedicated to the concept of
mentorships. It works like this: As a mentor, you meet with attendees who sign up for seven-minute
meetings. These meetings are free form and the attendees can ask whatever they want of their mentor.

My mentorship sessions tend to revolve around I had a great conversation with Melanie Spiller The point is to find people who’ll give you honest
three tent-pole areas of my career: writing, being (the person who makes our authors, including me, and constructive criticism. You don’t necessarily
a software developer, and being an independent sound so good) about the aspect of fear in cre- have to be told how to fix it, but knowing that
consultant/business owner. It’s an honor and ative endeavors. Melanie and I both have inter- something doesn’t work puts you closer to the
privilege to be a mentor. In my 20+ years as an ests outside of the software development/tech- right path.
independent software developer I‘ve been a men- nology realm. Melanie’s an accomplished singer
tor to many of my colleagues and friends and I as well as a great writer, and I have a passion for
take the job seriously. film, especially the creative process surrounding Just Do It
film’s creation. There’s another trait that we both Sometimes you just need to put one foot in front
I’ve been a mentor at SXSW for a few years now share as well: The fear of turning artistic fantasy of the other and go for it. Write that script, get
and for the first few years, no-one showed up for into reality. In my case, I’m kind of scared witless that camera and shoot that photo, break out the
their scheduled session. Admittedly, this was a bit to create my own film. Numerous cautionary tales journal and start that book—just go for it. What
of a disappointment. Some of my friends asked and random trepidations creep into my mind: do you have to lose?
why I continued to participate in the program. My What if I don’t like creating my own movie? What
answer was simple: If someone shows up, the sev- if I can’t find people to help me? What if I make
en minutes I give him or her could be life-chang- a movie and it sucks? And Melanie tells me that Rod Paddock
ing. Not to be egotistical, but I firmly believe that she’s revised her book 11 times (that’s right, the
seven minutes of good advice, or encouragement, whole shebang, rewritten from start to finish 11
can make all the difference in a person’s life. times!) over numerous years and with the help/
advice of various writing groups and agents, and
This year, I might have had that affect. My last despite more than one agent saying “yes,” she’s
appointment of the day was a software developer expressed similar fears to me and describes her
from Boston, who, with some other software devel- current status as “blocked.”
opers, was about to quit the world of W2 employ-
ment and “hang a shingle.” This software team is How do you get over these creative fears? Here
putting together a set of tools for building custom- are a few ideas.
ized chat bots. It was an interesting concept and
looked to be well-architected. I gave him the same
advice I’ve given other colleagues over the years: Ask for Help
get a CPA, set up an LLC or corporation with the This is exactly like the software developer in my
help of a lawyer, make sure the ownership of the mentorship story. Seek out the advice of other
intellectual property is properly documented, etc. people who’ve done it before. Consider their ad-
vice and leverage their knowledge as you pursue
After having a rich conversation about his busi- your endeavors. It’s not a sign of weakness—it’s a
ness and architecture, we chit chatted for a while sign of strength to know what you need and how
and I told him something that set him back a bit. to get it.
I told him that he’s way ahead of so many other
people. The simple act of showing up for our men-
tor session set him apart from 75% of the other Form a Circle of Trust
people who failed to show up. That commitment In any creative endeavor, you need to have peo-
to making himself better, accompanied by the ple that you can send your work to who will set
leap it takes to start a new endeavor said much you straight when something works and, better
more about the person than the business idea. It yet, when something doesn’t work. One of my
takes guts to set out on your own and it takes friends in Austin is a professional screenwriter/
smarts to ask for advice about starting out. He author and I’m part of his “Circle of Trust.” He
had both of these elements, guts and smarts. I relies on me to give honest advice and I’m al-
hope he succeeds in his endeavors. ways happy to do that. For one of his scripts, my
advice was something like this: “These sections
This leads me to the subject I want to really talk sound like bad episodes of Law and Order and
about: Getting over fear in the creative process. you should drop or trim them as they do nothing
Being creative can be exhilarating and scary at for the story.” If all he wanted was praise for his
the same time. lovely prose, I bet I’d be out of the circle quickly.

6 Editorial codemag.com
ONLINE QUICK ID 1605021

Parse is Set to Shut Down. Now What?


Parse, a Backend-as-a-Service (BaaS) platform, allows developers to focus their efforts on building a robust front-end experience
without having to worry about constructing a complex backend infrastructure. Its cost and resource-effective options alleviate many
projects’ need to create a database, code API endpoints, handle a push-notification infrastructure, figure out how to scale properly, etc.

Facebook acquired Parse in 2013. In 2014, Parse released the dependency on a third party. As made evident by Parse
a report detailing their support of over 500,000 applica- shutting down, relying on a third party to support your
tions. On January 28, 2016 Facebook announced that it business’s infrastructure can negatively impact you in the
would shut Parse down with all services ceasing operation long term should the service get discontinued or its prod-
on January 28, 2017. uct undergo a radical change.

This announcement left many developers, including


me, needing to figure out where to go next. Essentially,
anyone using the service has one year to migrate their Building your own backend grants
Jason Bender backend elsewhere or their application will stop working the highest level of flexibility,
Jason.bender@rocksaucestudios.com when the plug is pulled. If you’re like most, you haven’t customization, and control.
www.controlappdelete.com planned or budgeted for migrating your backend to an-
www.twitter.com/TheCodeBender other service. Fortunately, several options exist and mi-
grating isn’t as hard as you might think.
Jason Bender is the Director
of Development for Rocksauce Although this approach does give you control of your own
destiny, it also comes with several negatives, depending on
Studios, an Austin, Texas-based
Mobile Design and Development
What are My Options? your team’s expertise and the monetary resources at your
Company. He has 11 years cod- Parse shutting down inconveniences many developers, disposal. Many developers originally went with Parse to save
ing experience in multiple lan- and many alternative options do exist. From building your costs and get to market faster. A custom backend not only
guages including Objective-C, own backend, finding a substitute service, or spinning up costs significantly more to develop, it takes longer and comes
Java, PHP, HTML, CSS, and Ja- your own self-hosted instance of Parse, there are a variety with a higher probability for error. Because you assemble the
vaScript. With a primary focus of options to choose from. infrastructure and architect the approach yourself, not only
on iOS, Jason has developed do you introduce the human error element, but also mainte-
dozens of applications includ- Building Your Own Backend nance needs. It requires an ongoing effort to keep it running
ing a #1 ranking reference app Out of the options covered in this article, creating your at maximum potential. For instance, you have to make sure
in the US. Jason was also called own backend will likely consume the most time and re- that it has the latest security updates, scales properly, man-
upon by Rainn Wilson to build sources, both short-term and long-term. However, this ages the hardware, and monitors error logs, just to name a
an iOS application for his wildly approach also grants the highest level of flexibility, cus- few new chores to add to your team’s ToDo list.
popular book and Youtube tomization, and control.
channel: SoulPancake. Building a custom backend, however, doesn’t need to be
When building a custom backend, you’re free to choose an all-or-nothing endeavor. There are several proven tech-
the technologies and frameworks that make the most nologies and services to simplify and expedite that process.
sense to support your business. You don’t have to deal Again, you open yourself up to reliance on third parties but,
with the traditional limiting factors that you may encoun- as is the case with much of software development, you’ve
ter when using a BaaS platform. Furthermore, you remove got to run a cost-benefit analysis. Services like Heroku (more

Figure 1: Amazon Mobile Hub dashboard

8 Parse is Set to Shut Down. Now What? codemag.com


details in the sidebar) can at least alleviate some of the pres-
sures of maintaining your own infrastructure. You still build
and architect your solutions from scratch but technologies
like this help solve many hardware headaches and make it
significantly easier to scale up with your business.

Amazon Mobile Hub


Amazon Mobile Hub is Amazon’s BaaS platform that uses
existing Amazon Web Services (AWS) technologies, like
AWS Cognito, AWS Simple Notification Service, and AWS
DynamoDB, to help developers create robust mobile experi-
ences. Under a single dashboard, developers can enable and
configure the corresponding services that they need to pow-
er their application. Figure 1 demonstrates the dashboard
that allows a developer to use an array of features, like:

• User management and authorization using AWS Figure 2: Client-to-backend relationship after the first phase of Parse’s migration strategy
Cognito
• NoSQL and SQL databases using AWS RDS and AWS
DynamoDB
• Push Notifications using AWS Simple Notification
Service
• App Analytics using Amazon Mobile Analytics
• Cloud-based logic using AWS Lambda
• QA against real devices in the cloud using AWS De-
vice Farm

If you’ve used Parse in the past, the feature offerings should


appear very familiar. Additionally, many of the Amazon ser-
vices, like DynamoDB for one, have drop-in client-side iOS
and Android SDKs just as Parse did. However, they’re not
drop-in replacements. If you want to transition to Amazon,
you need to reconfigure your backend architecture through
the Amazon Mobile Hub dashboard and then, using the
various Amazon SDKs, replace any use of the embedded
Parse SDK with the Amazon counterpart. Although the
functionality is similar, it differs in syntax, so this requires
a sizeable amount of rework on each client-side platform,
depending on the overall scope of the project. Figure 3: Client-to-backend pre-deployment relationship after completed migration
As a result, Amazon Mobile Hub makes a lot of sense when
starting a new project and looking for a Parse alterna- the sidebar for links to some of the services you can take Parse Substitutes
tive. However, when looking at the most cost-effective advantage of.
migration options, other approaches exist that can get https://github.com/relatedcode/
you back up and running quicker. Similarly, on Github (links in sidebar), Parse details tutorials ParseAlternatives contains a very
to incrementally configure your own version of the Parse serv- detailed list of Parse alternatives
as well as smaller services that
Your Own Parse Server er using Heroku and either mLab or ObjectRocket. You start
cover specific functionality that
When Parse announced that it was closing up shop, it also by migrating only your data to a self-hosted MongoDB. From
Parse offers, like push notifications
open-sourced the Parse server, which runs on Node.js and there, you can tell your existing application to start writing to
and analytics.
MongoDB. If building your own custom backend or switch- your hosted DB instead of the Parse-hosted DB. Figure 2 dem-
ing to a Parse substitute on short notice seems unfeasible, onstrates what the relationship looks like after phase 1, with
self-hosting your own version of Parse, at the very least, blue elements controlled by Parse and orange self-hosted. Parse’s Migration Plan
gives you time to figure out your long-term plan.
Eventually, after following the entirety of Parse’s instructions https://github.com/
Amazon details tutorials on their website for how to mi- on migrating your dependencies from their platform to your ParsePlatform/parse-server/
grate your existing Parse setup to Amazon AWS using AWS own self-hosted version, the client-to-backend relationship wiki/Migrating-an-Existing-
Elastic Beanstalk. Not only do you get the dependability resembles Figure 3. In Figure 3, you have a development Parse-App contains official Parse
of Amazon’s infrastructure, but also the development ef- build running on a completely Parse-independent version of documentation for migrating
fort on your existing platforms is minimal. For instance, it the Parse API using your own deployed Parse server and a your existing Parse application to
allows you to continue to use the Parse client-side SDKs self-hosted MongoDB instance. At the same time, your pro- a self-hosted instance.
that you already have in place, meaning that (as long as duction application, still using Parse’s API, has transitioned
you’re on the latest SDK versions) you only need minimal to the new MongoDB instance as well, because changing
changes to the client-side application to continue using your production application’s data source can be done with-
basic data services. If you use push notifications, analyt- out client-side updates. Then, the only thing left to do is
ics, or some of a few of the other offerings that Parse had, push a version of the development build into production and
you’ll have to find substitutes to fill in the gaps. Check have your users update to this build. If you’ve given yourself

codemag.com Parse is Set to Shut Down. Now What? 9


enough time, your user base will migrate to the new build synching. Additionally, it supports user authentica-
and when Parse goes offline, your users will be free-and- tion, cloud code, and push notifications.
clear of the version that previously relied on Parse.

Although this option likely gives you the shortest path to Sooner Rather than Later
migrate off of Parse’s services, you should also consider Whichever approach you decide to take, it benefits you
the downside to this approach. Mainly, the open source to move quickly. Parse announced that if you haven’t
server doesn’t come with all the bells and whistles that at least migrated your data source by April 28, 2016, it
largely made Parse desirable to begin with; items such would de-prioritize the traffic to your application in favor
as the dashboard (Parse mentions that they’re working of applications that have already made that transition.
on an open-source version), push notifications, analytics, They also formally suggest that you try to complete your
webhooks, general application configuration, cloud code, migration off of their services by July 28, 2016.
and scheduled jobs will all need to be substituted if your
application is dependent on them.
If you haven’t at least migrated
Additional Parse Substitutes
Lastly, the BaaS ecosystem has a number of players that you your data source by April 28,
could consider if you’ve determined that you want a substi- 2016 Parse will de-prioritize
tute and would rather re-engineer your client-side applica- the traffic to your application
Amazon Migration Plan tions instead of taking up backend development. The follow- in favor of applications
ing list details some of the more popular options. The sidebar that have already made
https://aws.amazon.com/mobile/ contains additional links to a more comprehensive list.
getting-started/ details Amazon’s that transition.
official strategy for moving an • Kinvey: A BaaS platform very similar to Parse and
existing Parse application to
offering cloud storage, push notifications, and cus-
AWS using Elastic Beanstalk.
tom business logic. Unlike Parse, the free tier is The options listed in this article represent a small sample
development-only. of the choices that you have to consider. If you want to
Heroku • Firebase: NoSQL cloud database that specializes in check out more options, look at the sidebar for several
real-time communication. Data is stored in JSON additional resources. Additionally, when considering one
https://www.heroku.com/
objects and is then synced to all connected clients of the Parse alternatives, keep an eye out, as most have
Heroku is a cloud platform based in real-time. tutorials specifically created to help developers transition
on a managed container system, • CloudKit: An iOS- and OSX-specific public and pri- from Parse to their respective platform.
with integrated data services vate cloud database that has a point-click dash-
and a powerful ecosystem, board similar to Parse. Jason Bender
for deploying and running • Microsoft Azure Mobile App Service: Similar to
modern apps. Parse in that it also does both offline/online data

ADVERTISERS INDEX
Advertisers Index
SQL Reporting Services, ASP.NET MVC, AngularJS, F#, Life after Parse 1&1 Internet, Inc. dtSearch
www.1and1.com 7 www.dtSearch.com 55
MAY
JUN
2016
AnDevCon Hibernating Rhinos Ltd.
www.andevcon.com 43 http://ravendb.net 5
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95

Create Mobile UIs with


Xamarin.Forms
Aspose LEAD Technologies
www.aspose.com 2 www.leadtools.com 38
CODE Divisions Real Time Web Solutions Conference
www.codemag.com 76 www.webrtcexpo.com/east/Default.aspx 67
CODE Framework SPTechCon
www.codemag.com/framework 11 www.sptechcon.com 47
Explore and Embrace AngularJS 2
Implement Lean Controllers in iOS Apps
Tame the HTML5 Audio Control
DevCon5
www.devconfive.com 29
Advertising Sales: DevTeach Developers Conference
Tammy Ferguson www.devteach.com 75
832-717-4445 ext 026
tammy@codemag.com

This listing is provided as a courtesy to


our readers and advertisers.
The publisher assumes no responsibility
for errors or omissions.

10 Parse is Set to Shut Down. Now What? codemag.com


ONLINE QUICK ID 1605031

The Journey to Angular: Part 1


In the eighteen years that I’ve been doing Web development, a lot has changed. We started out creating HTML pages to
present static information to our users. We then used classic ASP to get database data and incorporate that into our pages.
To use both of these technologies, we had to know a lot about HTML, CSS, and JavaScript. Along came .NET and we started

rendering everything on the server-side. We forgot a lot table-condensed table-striped">


about HTML, CSS, and JavaScript as Web Forms wrapped <thead>
up a lot of that for us. Web Forms’ architecture closely <tr>
mimicked the way developers created desktop applica- <th>Product Name</th>
tions. This was great for helping developers move to the <th>Introduction Date</th>
Web, but unfortunately hid a lot of the power of the Web, <th>URL</th>
and also tended to be a little slow. </tr>
</thead>
Web developers were demanding that Microsoft get back <tbody></tbody>
Paul D. Sheriff to the roots of HTTP and HTML, and thus MVC was invent- </table>
www.PDSAServices.com ed. This technology was very different from Web Forms,
but was more closely aligned with how the Web worked. In Listing 1, there are three main components. There’s
Paul D. Sheriff is the President In order to use MVC, you had to get back to your roots of a variable called products that holds the collection of
of PDSA, Inc. PDSA develops HTML, CSS, JavaScript, and jQuery. Most developers using product data and there’s a function called productTable-
custom business applications MVC were still doing a lot of server-side rendering and Build() and a function called productList(). Of these
specializing in Web and mobile
this meant a lot of post backs, which also still slowed three things, only productList() needs to be public. The
technologies. PDSA, founded
down the user experience. other items should be hidden from the global scope of
in 1991, has successfully
the page. This is where a closure works well. To create a
delivered advanced custom
application software to a wide In my last three articles for CODE Magazine, I introduced closure, wrap all your variables and functions contained
range of customers and diverse you to a pure HTML page that allowed you to list, add, within the <script> tags into another function, as shown
industries. With a team of edit, and delete data using the Web API, jQuery, and Ja- in the code snippet below.
dedicated experts, PDSA deliv- vaScript. As you have seen from these articles, this page
ers cost-effective solutions, is very fast, much faster than either Web Forms or MVC’s var controller = (function () {
on-time and on-budget, using server-side rendering. Unfortunately, the code we’ve writ- // Add your private functions & variables
innovative tools and processes ten leaves a little bit to be desired. There are a couple of
to better manage today’s com- things we can do to make our code better; namely, JavaS- })();
plex and competitive environ- cript closures and HTML templating. These two technolo-
ment. Paul is also a Pluralsight gies are used extensively in AngularJS, which is a client- The wrapper that you’re creating is called an Immedi-
author. Check out his videos at side framework that is very popular for Web development ately-Invoked Function Expression, commonly known as
http://www.pluralsight.com/ today. an IIFE. An IIFE is a design pattern that creates a scope
author/paul-sheriff. where you can create private variables and functions and
In this article, you’ll learn to wrap your JavaScript func- expose public functions. It does all of this while not pol-
tions and variables into a JavaScript closure. In addition, luting the global environment. If you take the code from
you’ll learn to use mustache.js to create HTML templates Listing 1 and wrap it into a closure, all three components
and eliminate the coding of HTML in JavaScript. By learn- become private. This means that you can’t reference any
ing these techniques, you will be that much closer to of them from the new controller variable. The variable
moving to Angular. When you begin to use Angular you products and the productBuildTable() function are fine,
will see a performance gain in your Web pages. This is due but you need to make productList() a public function. To
to less post-backs and less bytes transferred across the do this, add a return statement around productList() and
network. There are many other benefits as well, and I will move the name of the function in front of the function
explore these in the next articles. statement. The code below shows the complete closure
without the all of the code in the functions.
Introduction to JavaScript Closures var controller = (function () {
The first step in getting to Angular is to learn about Ja- var products = [];
vaScript closures. Think of a JavaScript closure like a class
in an OOP language. Within this closure, you can have function productTableBuild() {
private variables, private functions and public functions. }
To illustrate, let’s take the HTML page shown in Figure 1
and the JavaScript to load the HTML table shown in List- return {
ing 1 and wrap that up into a closure. productList: function () {
}
The portion of this page you’ll be interacting with is the };
<table> element. This element is shown below. })();

<table id="productTable" When the HTML document is loaded, the $(document).


class="table table-bordered ready function is called, which, in turn, calls the pro-

12 The Journey to Angular: Part 1 codemag.com


ductList() function in your closure. Because this function The complete JavaScript code in your page should now
now only has scope within the closure, you need to add look like Listing 2.
the variable name controller in front of the call to pro-
ductList(), as shown below. JavaScript Closure for Product Add, Edit, Delete Page
If you’ve been reading my last few articles, you’ll remem-
$(document).ready(function () { ber that you wrote a lot of functions. If you’re not famil-
controller.productList(); iar with the last article, that’s not a problem, as you can
}); probably get a good idea from the code in Listing 3 of

Listing 1: A normal JavaScript function to load a table


<script> {
$(document).ready(function () { ProductId: 1,
productList(); ProductName: 'Extending Bootstrap with
}); CSS, JavaScript and jQuery',
IntroductionDate: "6/11/2015",
var products = []; Url: 'http://bit.ly/1SNzc0i'
},
function productTableBuild() { {
for (var i = 0; i < products.length; i++) { ProductId: 2,
$("#productTable tbody").append( ProductName: 'Build your own Bootstrap
"<tr>" + Business Application Template in MVC',
"<td>" + IntroductionDate: "1/29/2015",
products[i].ProductName + Url: 'http://bit.ly/1I8ZqZg'
"</td>" + },
"<td>" + {
products[i].IntroductionDate + ProductId: 3,
"</td>" + ProductName: 'Building Mobile Web Sites
"<td>" + Using Web Forms, Bootstrap, and HTML5',
products[i].Url + IntroductionDate: "8/24/2014",
"</td>" + Url: 'http://bit.ly/1J2dcrj'
"</tr>"); }
} ];
}
productTableBuild();
function productList() { }
// Add data to products variable </script>
products = [

Figure 1: A list of products

codemag.com The Journey to Angular: Part 1 13


Listing 2: A JavaScript closure eliminates functions and variables from the global namespace
$(document).ready(function () { {
controller.productList(); ProductId: 1,
}); ProductName: 'Extending Bootstrap with
CSS, JavaScript and jQuery',
var controller = (function () { IntroductionDate: "6/11/2015",
var products = []; Url: 'http://bit.ly/1SNzc0i'
},
function productTableBuild() { {
for (var i = 0; i < products.length; i++) { ProductId: 2,
$("#productTable tbody").append( ProductName: 'Build your own Bootstrap
"<tr>" + Business Application Template in MVC',
"<td>" + IntroductionDate: "1/29/2015",
products[i].ProductName + Url: 'http://bit.ly/1I8ZqZg'
"</td>" + },
"<td>" + {
products[i].IntroductionDate + ProductId: 3,
"</td>" + ProductName: 'Building Mobile Web Sites
"<td>" + Using Web Forms, Bootstrap, and HTML5',
products[i].Url + IntroductionDate: "8/24/2014",
"</td>" + Url: 'http://bit.ly/1J2dcrj'
"</tr>"); }
} ];
}
productTableBuild();
return { }
productList: function () { };
// Add data to products variable })();
products = [

Sample Code what it does. You’re not interested in creating the whole page and just change the format of those to match what’s
project in this article, just how to wrap up the different presented in this article.
You can download the sample functions into the closure.
code for this article by visiting my
website at http://www.pdsa.com/ The HTML page from the last articles lists, adds, edits, Templating with Mustache
downloads. Select PDSA Articles, and deletes product data. This page contains 19 functions Concatenating strings in JavaScript as I did in the pro-
and then select “Code Magazine within the <script> tags. Of these 19 functions, only five ductTableBuild() function is a horrible way to generate
- The Journey to Angular - Part 1”
need to be made public. There’s also one global variable HTML. It’s very difficult to read, hard to debug, and leads
from the drop-down list.
called Product. This variable becomes a private variable to runtime errors. Instead, let’s employ a technique
within the closure, as that’s the only place it needs to be called templating by bringing an open-source library
referenced. Listing 3 is what your closure looks like for called Mustache into the project. You can download this
all 19 functions. I removed all of the code from within the very small library at https://github.com/mustache/mus-
functions so you can just see how everything is enclosed tache.github.com. Once you download it, add the mus-
within the IIFE. tache.min.js file to your project and reference the library
in your HTML page using the following tag:
Remember that after wrapping your functions into a clo-
sure, you need to reference the closure variable in front <script src="/Scripts/mustache.min.js"></script>
of your functions. This includes your event handlers. If
you added your event handlers into your closure, you In Listing 2, the function productTableBuild() is used to
need to make sure they are made public. You also need to build HTML table rows in JavaScript. You’re now going to
change the HTML that calls these event handlers. Add the eliminate the code in that function and replace it with
name of your closure variable in front of the calls to the code to process a template. To do this, you need to do
event handlers, as shown in the next code snippet. Notice three things. First, add a public function in the closure to
the controller. that was added prior to the updateClick() expose the collection of product objects contained in the
function name. products variable.

<button type="button" id="updateButton" productCollection: function () {


class="btn btn-primary" return productList;
onclick="controller.updateClick();"> }
Add
</button> Second, add a <script> tag with an ID attribute and a type
of “text/html”. Within this tag, you create template data
Creating closures is not that hard and really, just requires binding code using curly braces. Anything you see within
a little bit of refactoring of your code. Think about what two open curly braces and two closing curly braces refers
functions need to be exposed as public functions on your to a function or property name of a JSON object.

14 The Journey to Angular: Part 1 codemag.com


<script id="productTableTmpl" type="text/html"> The third thing you need to do is to write the code to
{{#productCollection}} process this template using the Mustache library. In the
<tr> productTableBuild() function, replace the old code with
<td>{{ProductName}}</td> the code shown here:
<td>{{IntroductionDate}}</td>
<td>{{Url}}</td> function productTableBuild() {
</tr> var template = $("#productTableTmpl").html();
{{/productCollection}}
</script> var html = Mustache.to_html(template,
controller);
In the template code, you see {{#productCollection}}.
This refers to the function name productCollection in the $('#productTable tbody’).html(html);
closure that returns the array of JSON product objects. }
Think of this token as a “for” loop. At the end of this
template code is {{/productCollection}}. This signifies The first line of code returns the HTML for the template code
the end of the “for” loop. in the <script> tag. The second line of code passes that HTML
and the variable named controller (the JavaScript closure)
Within these two tokens are the <tr> and <td> elements to the to_html() function of the Mustache library. The
and within each <td> elements are more data binding Mustache library now accesses the productCollection()
tokens with the names of each property in the product function in the closure, iterates over the collection of
object that you wish to display in each column of the product objects, and renders each <tr> element between
table. the {{#productCollection}} and the {{/productCollec-

Listing 3: Wrapping all your functions into a closure


$(document).ready(function () { // Delete product from <table>
// Get all product data function productDelete(ctl) {
controller.productList(); }
}); // Call Web API to update a product
function productUpdate(product) {
// **************************** }
// Closure for page // Update Web API call was successful
// **************************** function productUpdateSuccess(product) {
var controller = (function () { }
// **************************** // Update product in <table>
// Private variables function productUpdateInTable(product) {
// **************************** }
var Product = { // Get a product from Web API
ProductId: 0, function productGet(ctl) {
ProductName: "", }
IntroductionDate: "", // Move product data to input fields
Url: "" function productToFields(product) {
} }
// Handle exceptions from AJAX calls
// Constants function handleException(request,
const BASE_URL = "/api/Product/"; message, error) {
}
// **************************** // Get error messages from ModelState
// Private Functions function getModelStateErrors(errorText) {
// **************************** }
// Call Web API to add a product
function productAdd(product) { // ****************************
} // Public Functions
// Add Web API call was successful // ****************************
function productAddSuccess(product) { return {
} deleteClick: function (ctl) {
// Display all Products },
function productListSuccess(products) { editClick: function (ctl) {
} },
// Add Product row to <table> addClick: function () {
function productAddRow(product) { },
} updateClick: function () {
// Build a <tr> for a row of table data },
function productBuildTableRow(product) { // Get all Products to display
} productList: function () {
// Clear form fields }
function formClear() { };
} })();

codemag.com The Journey to Angular: Part 1 15


tion}} tokens. The to_html() function returns the raw public function that returns the data formatted the way
HTML to which you pass that HTML to the html() function you want. For example, if you want to display the date in
of the selector, which returns the DOM object <tbody> in your locale’s format, you can add a public function named
the “productTable” <table>. In this way, the table now toLocalDate() in your closure, as shown here:
has rows and columns and can display the product data.
Listing 4 contains the complete JavaScript code to gen- toLocalDate: function () {
erate the page that looks like Figure 2. return this.IntroductionDate
.toLocaleDateString();
Formatting Data in a Template },
Displaying a UTC date in your HTML table is probably not
what you want for your users. Mustache has some limited Modify your template to use this new function instead of
formatting capabilities, but it’s often easier to create a the IntroductionDate property.

Figure 2: A list of products from a template

Listing 4: Wrapping all your functions into a closure


var controller = (function () { // ************************************
// ************************************ return {
// Private Variables productList: function () {
// ************************************ // Add data to productList variable
var productList = []; productList = [
{
// ************************************ ProductId: 1,
// Private Functions ProductName: 'Extending Bootstrap with
// ************************************ CSS, JavaScript and jQuery',
function productTableBuild() { IntroductionDate: new Date(2015, 5, 11),
// Get template from script Url: 'http://bit.ly/1SNzc0i'
var template = },
$("#productTableTmpl").html(); ...
// Pass Mustache the template and the object ];
// with the collection of product data
var html = productTableBuild();
Mustache.to_html(template, controller); },
// Insert the rendered HTML into the DOM productCollection: function () {
$('#productTable tbody').html(html); return productList;
} }
};
// ************************************ })();
// Public Functions

16 The Journey to Angular: Part 1 codemag.com


<script id="productTableTmpl" type="text/html"> type: 'GET',
{{#productCollection}} contentType: "application/json;
<tr> charset=utf-8",
<td>{{ProductName}}</td> dataType: 'json'
<td>{{toLocalDate}}</td> }).done(function (data) {
<td>{{Url}}</td> products = data;
</tr> productTableBuild();
{{/productCollection}} }).fail(function (error, textStatus) {
</script> handleException(error,textStatus,null)
});
When you run the page now, you should see the date dis- },
played in your local format.
If you have a date property being returned from the Web
Get Data from Web API API like IntroductionDate, you need to remember that
So far in this article, you used hard-coded data for the prod- this value comes across as a string. You need to convert
uct list. A more realistic use is to retrieve data from a Web API it into a valid JavaScript date prior to attempting to use
call. Add a Web API controller to return a collection of prod- the toLocaleDateString() function on it. Modify your to-
uct objects with the same property names as the ones used in LocalDate() function to do the conversion, as shown in
this article. Add a new private function to your closure called the following code snippet:
getProducts(). This function makes an Ajax call to your Web
API and upon successful return of the data, assigns the col- toLocalDate: function () {
lection returned to the productList variable in your closure. return new Date(this.IntroductionDate)
SPONSORED SIDEBAR:
.toLocaleDateString();
function getProducts() { }, Does Your Cloud App
return $.ajax({ Leave You Feeling Under
url: BASE_URL, the Weather?
type: 'GET', Summary
contentType: "application/json; In this article, you learned how to wrap your JavaScript The developers at CODE have
charset=utf-8", code into a closure. A closure ensures that your JavaScript worked on everything from
dataType: 'json', doesn’t pollute the global environment with unneces- cloud applications to mobile
success: function (products) { sary variables that can cause hard-to-find bugs. You also projects. If you’re having
productList = products; learned how to use templating with the open source library problems with your and need
}, called Mustache. Templating is used extensively in Angular, guidance, the developers at
CODE Consulting can help.
error: function(request,message,error) { so starting to get familiar with this technique will help you
For more information
handleException(request,message,error); to move to Angular. In the next article, I’ll introduce you
visit www.codemag.com/
} to Angular and you will see how to apply what you learned
consulting or email us at
}); in this article. info@codemag.com
} to set up your time with
Paul D. Sheriff a developer today.
In the getProducts() function notice, this function returns
the call to the $.ajax() function. A “Promise” is returned
from the jQuery $.ajax() call. This allows us to call the
getProducts() function from the productList() function
and chain to the Promise’s done() function. This allows
the $.ajax() call to be processed asynchronously, and
when it’s done, call the productTableBuild() function in
order to process the Mustache template.

productList: function () {
getProducts().done(function () {
productTableBuild();
});
},

The alternative to creating a new function and returning the


$.ajax() promise is to use the newer syntax for $.ajax(). For
this syntax (valid after jQuery 1.5), you take advantage of
the promise right in the productList() function. Notice how
you now only set parameters of the Ajax call in the first pa-
rameter and eliminate the success and error functions. In-
stead you use done() and fail() functions. The end result is
the same; it’s just two different methods for making the call.

productList: function () {
$.ajax({
url: BASE_URL,

codemag.com The Journey to Angular: Part 1 17


ONLINE QUICK ID 1605041

AngularJS 2
AngularJS has been a huge success. More than 1.1 million developers have embraced this platform and created thousands
of applications using it. Writing complex applications in JavaScript can be challenging, and AngularJS made it approachable.
In a language devoid of good design patterns and strict rules, AngularJS brought sanity and consistency. But let’s be honest;

although AngularJS was a huge improvement over writing • It allows for a more logical code structure than its
JavaScript by hand, it did have some issues. Learning An- predecessor. AngularJS 1 had the bad habit of pol-
gularJS was a steep curve. Buying into it was embracing luting your HTML, not giving you more control on
the whole platform. And most of all, there were so many CSS, and forcing you to think in MVC. AngularJS 2
ways to do it incorrectly, and so many ways to do it better allows you to do MVC, or Flux, or any other design
than the last developer. pattern you wish. It also allows you to logically de-
sign and arrange your application in components
Over time, as browsers improved and Web technologies rather than controllers. And finally, it tends to pol-
were applied to more than just browsers, AngularJS 1 lute your HTML less, and only in ways that seman-
NameMalik
Sahil Autor didn’t take full advantage of those scenarios. Plus, Type- tically enhance HTML. You don’t need ng-href or
www.winsmarts.com
www.internet.com Script, which, in my mind is the single most important ng-src, but you can still have your own tags, like
@sahilmalik innovation in JavaScript since fast JavaScript engines, al- <customer/>, etc.
asdfasdfasdfasdfker, a .NET ways felt like an afterthought in AngularJS 1. Yes, although • And the best part about AngularJS 2 is that it’s
Sahil
author,Malik is a Microsoft
consultant MVP,
and trainer. you could use TypeScript, it was hard to take full advantage easier than AngularJS 1. I’ll be honest, it took a lot
INETA speaker, a .NET author,
of it unless you consciously attempted to do so. As a result, of time to truly master AngularJS 1. And there were
Sahilasfasdfasdfasdfasdfasdfd-
consultant, and trainer.
fainings are full of humor and in an AngularJS 1 world, you are more likely to see lots of so many ways to mess it up. Parent scopes can be
Sahil loves
practical interacting
nuggets. withfind
You can fel- JavaScript or incomplete usage of TypeScript. so complicated. As my applications got bigger, my
low
moregeeks
aboutinhis
realtrainings
time. Hisattalks head exploded. Developers smarter than me crafted
and trainings are full of humor
http://wwasdfasdfasfasdfasdf This is not unexpected: Times change and technologies amazingly intricate card houses that collapsed eas-
and practical nuggets. You can evolve. AngularJS 2 is a natural evolution of AngularJS ily. I felt like an idiot. And this was after a few years
find more about his training at 1. AngularJS 2 brings it up to date with modern Web of AngularJS 1. AngularJS 2, on the other hand, felt
http://www.winsmarts.com/ standards, better design patterns, and takes advantage of a lot more logical, and it was easier to understand
training.aspx. what’s new and awesome today. and learn. I find myself more productive in Angu-
larJS 2, and I have the confidence that I’m writing
His areas of expertise are cross- more reliable and easier-to-maintain code. Much
platform mobile app develop- Why Bother with AngularJS 2 more so than AngularJS 1.
ment, Microsoft anything, and There are four main reasons you should seriously consider
security and identity.
AngularJS 2: The obvious elephant in the room of course is that Angu-
larJS 2, at the time of writing this article, is still in beta.
• It is fast. Very fast. It takes full advantage of mod- Still, I like AngularJS 2 so much that even in beta, I have
ern Web browsers and defaults to using the capa- no reservations in recommending this platform for new
bilities they offer to give you the best performance. development over AngularJS 1, especially if your release
If you wrote the same functionality in AngularJS 2 date is in the second half of 2016.
as you wrote for AngularJS 1, AngularJS 2 will most
likely far outstrip the performance of AngularJS 1.
• It is portable. Although it relies on the newest Thinking in AngularJS 2
standards, it uses polyfills to support almost every AngularJS 2 requires you to think differently. There are
browser you care about. Even IE9 is supported. some key differences compared to AngularJS 1, features
you need to learn and decisions you need to make. The
good news is that even though there are differences be-
Listing 1: AngularJS 1 Controller tween AngularJS 1 and AngularJS 2, many concepts port
(function () { over. As an AngularJS 1 developer, you’ll clearly see the
angular improvements where you see the differences. As a new-
.module(‚app‘, []) to-AngularJS 2 developer, you’ll find the new syntax and
.controller(‚appController‘, appController) features easier to learn.

function appController() { With that, let me go through the various differences, fea-
var vm = this; tures, and key decisions.
vm.name = „Sahil“;
} Language Choices
})();
JavaScript is evolving. It needs to, because the original
language simply isn’t going to scale to the level of the
complex applications that you need to build. When writ-
Listing2: Using an AngularJS 1 controller
ing for AngularJS 2, you have various choices:
<body ng-app=“app“ ng-controller=“appController as vm“>
Name: <span ng-bind=“vm.name“></span> • ES5: The obvious advantage of using ES5 is that it’s
</body> only JavaScript and it needs no compilation. But

18 AngularJS 2 codemag.com
it’s not strongly typed, and it doesn’t offer the code Listing 3: An AngularJS 2 component
structure advantages of other alternatives.
import {Component} from ‚angular2/core‘;
• ES6: ES6 is a superset of ES5. Although it does
give you some better code structure building
@Component({
blocks, it isn’t strongly typed, and it needs a com-
selector: ‚my-app‘,
pilation step. At the end of the day, it’s JavaScript,
template: ‚<h1>Hello {{name}}<h1>‘
and with time, browsers will support ES6 natively. })
It’s sure taking a very long time for them to do so.
• TypeScript: TypeScript is a superset of ES6. It’s export class AppComponent {
strongly typed. It gives you much better code name = „Sahil“;
structure building blocks, but it requires a com- }
pilation step. At the end of the day TypeScript is
JavaScript—okay, it’s a superset of JavaScript,
but you can rename your .js to .ts and pretend it’s
Listing 4: Bootstrapping an AngularJS 2 app
JavaScript.
• Dart: Dart seems to offer the worst of all worlds. import {bootstrap} from ‚angular2/platform/browser‘
It isn’t JavaScript and it requires compilation, but import {AppComponent} from ‚./app.component‘
it gives you better code structure alternatives. bootstrap(AppComponent);
Because it’s not a super set of ES5, ES6, or
TypeScript, using Dart feels like using an entirely
different language that doesn’t mentally translate Listing 5: Structural directives in AngularJS 1
into JavaScript. At least, not easily. <ul>
<li ng-repeat=“hobby in vm.hobbies“>
Given the above choices, I feel that we have a clear win- <span ng-if=“!hobby.hide“>
ner, and that’s TypeScript. I’m going to write my Angu- {{hobby}}
larJS 2 code in Typescript, and apparently the AngularJS </span>
2 team is doing so too. You are, however, free to use ES5, </li>
ES6, or Dart. But I don’t see why you wouldn’t prefer to </ul>
use Typescript.

Components versus Controllers


AngularJS 1 required you to create a controller. A control-
ler was the fundamental “brain” of your application. It
was way too easy to abuse the pivotal role of a control-
ler in AngularJS 1, which is why the best practice was to
separate most of the logic into services that the controller
could use. A typical AngularJS 1 controller looks like the
one shown in Listing 1.
Figure 1: Bootstrapping an AngularJS 1 app
You could use this controller as shown in Listing 2.

Controllers, over time, became very complex. They had to AngularJS 2 takes a different approach. AngularJS 2 likes
deal with parent and child scopes. There was no one-size- to split your application into components. And it allows
fits-all approach that you could use, making understand- you to bootstrap the starter component by importing it as
ing and debugging the application for the next developer a module first. This can be seen in Listing 4. This gives
a lot harder. And it forced you to do MVC, whether or not us a lot of control in modularizing the application. Be-
it was the right choice for your application. cause the module is a class that you export, you have
very clear control of which portions of the module are vis-
AngularJS 2 replaces “thinking in controllers” with ible and which are not. You can also bootstrap condition-
“thinking in components.” Components are the central ally; what’s perhaps most interesting is the first line in
artifact in AngularJS 2. Listing 4. AngularJS 2 imports bootstrap from angular2/
platform/browser. This means that the browser is sepa-
<my-app>Loading...</my-app> rate from the core AngularJS 2. You could theoretically
have different bootstrapping functionality for Cordova/
Using the component shown in Listing 3 is a matter of Electron etc.
referencing the selector. The component can nest other
components, and it can even give your “tag” its own CSS Structural Directives
area, so your CSS doesn’t interfere with the page’s CSS There are three kinds of AngularJS directives: there are
and vice versa. components; there’s a directive with a template in An-
gularJS 2; and there’s the attribute directive, which can
Bootstrapping change the behavior or appearance of an element (for ex-
Bootstrapping your app requires explicit action from you. ample, NgStyle); and structural directives.
AngularJS 1 allowed you to bootstrap your app by placing
certain attributes in your HTML, as shown in Figure 1. Or Structural directives can alter the structure of the DOM.
alternatively, you could bootstrap your app in AngularJS For instance, ngIf, ngSwitch, ngFor are structural direc-
1 using code also. tives.

codemag.com AngularJS 2 19
Listing 6: Structural Directives in AngularJS 2 Why am I using ng-bind to change the value of innerText?
And what if I wanted to bind to an alternate property such
<ul>
as CSS or width or href? This is where AngularJS 2 uses a
<li *ngFor=“#hobby of hobbies“>
much better syntax, as shown here:
<span *ngIf=“!hobby.hide“>{{hobby | json}}</span>
</li>
<span [innerText]=“name“></span>
</ul>

AngularJS 2 binds to any property of the surrounding ele-


ment. This is more intuitive to learn and program because
Listing 7: Dependency injection in AngularJS 1 there’s no hidden meaning of what an ng-bind may do.
(function () { You know that you’re modifying the innerText property,
angular no surprises there. And if you wanted to bind to an event,
.module(‚app‘, []) you’d use a slightly different syntax, like that as shown
.controller(‚appController‘, appController) here:

appController.$inject = [‚MyService‘]; <button (click)=“clickHandler()“>Click me</button>


function appController(MyService) {
var vm = this; Here, you’re binding to the click event of the button. Can
// other details.. you guess how you would bind to the “mouse-up” event?
} You can think of event binding as the reverse of data
})(); binding. Both are one-way bindings.

• And sometimes, you need two-way databinding.


You’ve seen structural directives in AngularJS 1. An ex- Two-way databinding in AngularJS 1 was imple-
ample can be seen in Listing 5. AngularJS 2 also has sup- mented as shown here:
port for structural directives. The same example written in
AngularJS 2 can be seen in Listing 6. <input ng-model=“vm.name“></input>

As you can see, the syntax is slightly different, but it still The same affect can be achieved in AngularJS 2 using the
works. “banana in a box syntax” or the [()] expression as shown
below:
Now here is the really interesting part. You can write your
own structural directives in AngularJS 2 using the @ <input [(ngModel)]=“name“>
Directive decorator. This gives you very fine control on
exactly how you want the DOM to be modified. Modifying This cleaner syntax of databinding that AngularJS 2 uses
the DOM is one of the most expensive things your appli- has another side benefit: You have fewer directives to
cation does, so this level of control is definitely very wel- learn.
come. Sure, you could do this in AngularJS 1, but there,
everything was a directive, and writing directives could Fewer Directives to Learn
get complex. AngularJS 2, with its @Directive decorator, Here’s an AngularJS 1 quiz. What did ng-href do? If you
puts writing complex directives within the reach of mere remember, you couldn’t databind directly to the href
mortals. property of an anchor tag in AngularJS 1. This is because
the browser understood the expression before the result
DataBinding of the expression, thereby breaking your href location.
Databinding is what truly set Angular apart. There are Not good! So you had to create directives like ng-href,
three kinds of databinding that AngularJS supports: In- ng-src, etc.
terpolation, one-way databinding, and two-way databi-
nding. Let’s look at them: Similarly, you had numerous other directives, such as
ng-style to modify the style of an element. Or ng-click,
• Interpolation, the {{expression}} double-mous- ng-blur, etc. to handle events! Because AngularJS 2 al-
tache syntax. Both AngularJS 1 and AngularJS 2 lows you to databind with a much more intuitive syntax
support interpolation in exactly the same manner. using the property name instead, all those directives are
The key difference is that AngularJS 1 databound no longer required.
to properties on the view model or $scope of the
controller. AngularJS 2 databinds to exported prop- For example, consider the following AngularJS 1 code:
erties of the underlying class that the component is
implemented as. <img ng-src=“vm.link“/>
• One way databinding, using ng-bind. This is where
AngularJS 2 shows its superiority over AngularJS 1. This can be simplified in AngularJS 2 as follows:
AngularJS 1 required you to do one way databind-
ing using the syntax shown below: <img [src]=“link“/>

Name: <span ng-bind=“vm.name“></span> And you can guess that you don’t need ng-click either,
because you can databind directly to the click property. In
This syntax was functional, but it required you to inter- fact, AngularJS 2 has removed the need for 40+ directives
sperse attributes that sometimes were not very intuitive. because of this superior syntax.

20 AngularJS 2 codemag.com
Services versus Class • Modules: AngularJS 1 and AngularJS 2 both have
It was very easy to abuse controllers in AngularJS 1. As a modules. But AngularJS 1 couldn’t make use of ES6
best practice, we were advised to abstract the heavy lift- modules because ES6 wasn’t around when Angu-
ing to services. But services weren’t just services. There larJS 1 was born. AngularJS 2 uses proper ES6 mod-
were Services, Providers, and Factories – three ways to ules, but yes, the concept of modules is still around.
create Services (and not very intuitively named, either). • Filters: Remember in AngularJS 1 there was a fil-
And then there were constants, values, and the config ter called “filter”? Confusing? They’ve changed the
method etc. on your module. You had to know exactly name of Filters to Pipes! It’s much more logical, es-
which one did what, and which got called before the oth- pecially given the syntax. But the concept is still
er. This innate knowledge of the nature of provider versus around.
service versus factory and config versus run, or constant • Routing: Routing in AngularJS 1 has undergone
versus value left many of us confused. It made the learn- evolution and improvements. The routing in Angu-
ing curve unnecessarily steep. lar 1.5x is quite similar to routing in AngularJS 2.
• HTTP: Because you need to interact with the server
But why did AngularJS 1 have to do all that? It was mak- too. The same concepts apply in Angular1 and An-
ing up for the shortcomings of JavaScript. AngularJS 2 on gular2.
the other hand has a class. A class can have a constructor, • Events: These are still around, but you have a much
exported properties, getters and setters, etc. And with better and logical syntax using event emitters.
TypeScript, the way you write these classes is also very There will be more on that in future articles.
second-nature to those coming from other languages • Promises: are still in there. AngularJS 2 has chosen
such as C# or Java. to give us another option, built on RxJS, called Ob-
servables. Observables can be thought of as a data-
In that sense, AngularJS 2 is much simpler to write and source of events that you can filter on. It’s a much
maintain because all those concepts are subsumed by the better architecture and it’s come out of reactive ex-
concept of a class—something you already know. tensions for C#. If you’ve used reactive extensions
in either JavaScript or C#, you probably already
Dependency Injection know that once you go RxJs, you don’t go back!
Dependency injection is a software design pattern that
implements inversion of control for resolving dependen- Perhaps the improvement I like the most in AngularJS 2 is
cies. A dependency is an object that can be used (such as much better error messages. As a developer, I’ve wasted
a service). An injection is the passing of a dependency to way too much time over poorly worded generic error mes-
a dependent object (a client) that will use it. sages. AngularJS 1 tried, it tried hard to give me a decent
error message about a typo. But frequently an ng-click
Dependency injection is a strength of AngularJS. It allowed mistyped as ng-clik yielded no error message. Stuff just
us to change the behavior of code at runtime by passing in didn’t work! Even when I did get an error message, it
the appropriate dependencies. This was achieved in Angu- looked like a cryptographic version of a SharePoint site
larJS 1 using the code shown in Listing 7. collection GUID salted in Russian. I am happy to say that
AngularJS 2 error messages are usually a lot cleaner and
It worked, but it had a huge downside: The magic string more intuitive than their AngularJS 1 counterparts.
problem. The MyService is a string in Listing 7, and if you in-
troduced a typo, it broke your code. What was worse, Angu-
larJS 1 allowed you to write variable names such as $scope Summary
and $http, and AngularJS 1 attempted to resolve those for This article isn’t intended to be an AngularJS 2 tutori-
you. Because a lot of code online showed such patterns, the al. It’s intended to illustrate the key improvements and
typical Google-driven development workflow meant that a changes and the reasons behind them. It’s intended to
lot of developers copy-and-pasted that code and painstak- illustrate why I’m excited about AngularJS 2 and why any
ingly made it work. As soon as the code was minified, all the developer should be excited as well. I’m certain that An-
variable names changed and nothing worked anymore. gularJS 2 will be quite successful. I’m also certain that it
will be used in platforms other than just the browser. It
AngularJS 2 supports dependency injection too, but a better will help us build bigger and better applications, applica-
and improved version of it. As can be seen from Listing 8, tions that will scale better and perform better. I’m truly
there is no longer the magic string issue going on. You type excited about AngularJS 2, and I hope to talk a lot more
the name of the class as it appears, and you can choose to about it in future articles.
alias it using standard ES6 and TypeScript constructs. You
can then set a class variable in the constructor that can hold In the meanwhile, happy coding!
an instance of the provided service and use it appropriately.
This means that your code works the same in both mini- Sahil Malik
fied and un-minified scenarios. Your dev environment code
doesn’t break mysteriously when it’s thrown into production.

Similarities and Other Improvements


As you can see, there are a number of differences between
AngularJS 1 and AngularJS 2. But fear not—there are a
lot of concepts that port over from AngularJS 1 also. For
instance:

codemag.com AngularJS 2 21
ONLINE QUICK ID 1605051

Taming the HTML5 Audio Control


I’m taking a brief hiatus from my usual legal topics. It’s been a while since I’ve written a technical piece. In this issue, I address
that by writing about one of the HTML5’s most useful features, the Audio Control. The HTML5 Audio control presents a standard
way to play audio. The same goes for the Video Control (which won’t be discussed in this article). In spite of that usefulness,

major issues exist when attempting to use the control The Importance of Testing with Different Browsers
“out of the box” on a mobile device. In this article, I’ll and Devices
take you through those issues with a simple prescrip- The disparity between the desktop and mobile versions
tion that will help you avoid the struggles and pitfalls underscores the importance of testing. It never ceases
with this control. If you’re new to Web development or to amaze me how often developers certify that some-
have always relied on using third-party JavaScript and thing is working without at least some rudimentary test-
CSS frameworks as abstractions in lieu of working directly ing to verify that assertion. This extends to cases where
with base JavaScript and CSS, this article may prove to be something must work on a mobile device and such cer-
good learning resource for you. tifications are issued in spite of never having run the
John V. Petersen application on a mobile device! Too often, the assump-
tion is made that if it works on the desktop, it works
johnvpetersen@gmail.com
linkedin.com/in/johnvpetersen The Code on a mobile device. Often, that assumption holds true.
@johnvpetersen The code for this solution can be found on GitHub: Consider the fact that with mobile devices, there is no
https://github.com/johnvpetersen/HTML5AudioControl- mouse. You have to make sure that cases on the desktop
John is a graduate of the Rut-
gers University School of Law CodeMagazineArticle. The code is licensed under the MIT where you account for a mouse click are compatible with
in Camden, NJ and has been Open Source License. the finger gestures employed on a mobile device. Stated
admitted to the courts of the simply, if your team isn’t undertaking this sort of dili-
gence, they’re doing it wrong!
Commonwealth of Pennsylvania
and the state of New Jersey.
The Use Case
For over 20 years, John has Let’s say that you’re tasked to build a Web page that can
developed, architected, and de- play a number of audio clips. Features include: JavaScript and CSS to the Rescue
signed software for a variety of To fully illustrate how to make things work regardless
companies and industries. John • Start/stop of platform, I’ll use baseline JavaScript and CSS. That
is also a video course author for • Advance the clip means that there are no dependencies on additional
Lynda.com. HIs latest course, • Display clip’s progress frameworks and libraries. JavaScript frameworks and
Foundations of Programming, • Restart clip libraries can be valuable. However, it’s also important
Open Source Licensing, teaches • Identical UX for desktop and mobile devices to understand that such things are not always required.
everything you need to under- For purposes of this article, I want to focus on the Audio
stand about the legal aspects Figure 1 shows a mock-up of what these use-case re- Control itself and how to make it work with the basics.
of open-source licensing. quirements might look like. You also get to dispense with the Angular versus Knock-
out versus Ember versus whatever arguments. By going
this route, I know for certain that you can take this code
The HTML5 Audio Control Out of the Box and work with it regardless of whatever frameworks and
The following code illustrates a simple usage: libraries you’ve chosen.

<audio controls>
<source src="myclip.mp3" type="audio/mpeg">
Your browser does not support the audio element. It never ceases to amaze me
</source> how often developers certify
</audio> that something works without
at least some rudimentary
The HTML5 Audio Control has the capacity to alleviate a lot testing to verify that assertion.
of work. Not too long ago, there was legitimate concern over
whether all browsers supported HTML5. That concern has
not been totally alleviated. Looking to Figure 2, you can
see simple markup that is rendered in two very different
ways. The desktop browser version looks good. The iPhone Starting from the End: Our HTML
browser, Google Chrome in this case, is broken. The fact that The HTML, listed in Listing 1 for this solution, is very
it’s Chrome doesn’t matter. Safari doesn’t work either. simple and is illustrated in Figure 3.

The main point is that unless your Web application is limit- Unlike what you see in Figure 2 with the default Audio
ed to the desktop, which isn’t likely, the HTML5 Audio Con- Control display, you now have parity between desktop and
trol default visual features won’t prove to be very useful. mobile browsers. To make things manageable, I followed
Even in the desktop scenario, there’s no way to style the a simple convention:
visual appearance. The important takeaway is that for most
cases, the HTML5 Audio Control’s visual facilities are use- • Div id = X: This is the div that displays the play or
less. Fortunately, there’s a remedy with JavaScript and CSS! pause image, depending on the audio control’s state.

22 Taming the HTML5 Audio Control codemag.com


• Div id = resetX: This is the div that displays the Before going too much further, let’s take a 10,000-
reset image and is used to allow the user to restart foot view of the code and how it relates to our layout.
an audio clip. Figure 4 illustrates the relationship between the various
• Div id = progressX/progressbarX: This is a nested JavaScript functions and the UI elements that are defined
div used to host a progress bar that displays a clip’s in HTML code in Listing 1.
progress as it is played.
• Audio id = clipX: This is the HTML5 Audio Control • Line 3, clips variable: Module-level variable to
for a specified clip. hold the Clips collection so that it may be refer-
enced for later use
This convention makes it easy to link-up and associate • Line 5, createClipHTML call: Combines data and a
different DOM Objects to work together. This avoids hav- markup template to produce HTML that is injected
ing to traverse the DOM hierarchy, which can be a major into the DOM
drain on performance. • Line 6, processClips call: Creates and iterates
through the Clips collection in order to call the
With the HTML markup out of the way, let’s get to the other functions
JavaScript and examine how the page comes to life. • The remaining functions initialize various event
handlers that will be discussed later in this article
The JavaScript
As stated earlier, the solution here is sans any third-party
JavaScript or CSS frameworks and libraries. The goal here
is to focus on a solution in such a way that it can be easily
applied to any context, regardless of any framework and
libraries used. To make things more digestible, I elected
to place all of the JavaScript code into one file. It should
go without saying that in a production application, such a
strategy would be ill-advised! All of the code blocks that
follow is sequential and is hosted within the following
anonymous code block:

(function(d) {

})(document);

Note that this anonymous block is automatically executed


when the script loads. Note also that a reference to the
DOM’s document object is injected into the function.
Where you see the variable “d”, that’s a reference to the
DOM’s document object. Figure1: This is a Desktop and mobile UI mock-up depicting the use case visual requirements.

Figure2: Depending on your device, the HTML5 Audio Control with the Controls option set may not be functional.

codemag.com Taming the HTML5 Audio Control 23


Listing 1: Sound clip HTML
<html> </audio>
<head> </div>
<meta name=”viewport” content=”width=device-width, initial- <div class=”clipContainer”>
scale=1.0”> <div id=”2” class=”play”></div>
<link rel=”stylesheet” type=”text/css” href=”background.css”> <p class=”artist”>Artist 2: <span class=”title”>Clip
</head> 2</span></p>
<body> <div id=”reset2” class=”reset”></div>
<div class=”clipContainer”> <div id=”progress2” class=”progress”>
<div id=”1” class=”play”></div> <div id=”progressbar2” class=”progressbar”></div>
<p class=”artist”>Artist 1: <span class=”title”>Clip </div>
1</span></p> <audio id=”clip2”>
<div id=”reset1” class=”reset”></div> <source src=”SoundClips/clip2.mp3” type=”audio/mpeg”>
<div id=”progress1” class=”progress”> </audio>
<div id=”progressbar1” class=”progressbar”></div> </div>
</div> </body>
<audio id=”clip1”> </html>
<source src=”SoundClips/clip1.mp3” type=”audio/mpeg”>

Listing 2: ClipData that defines the title, artists and audio file sources
var clipData = { “title”: “Clip 2”,
“clips”: [{ “artist”: “Artist 2”,
“title”: “Clip 1”, “media”: {
“artist”: “Artist 1”, “src”: “SoundClips/clip2.mp3”,
“media”: { “type”: “audio/mpeg”
“src”: “SoundClips/clip1.mp3”, }
“type”: “audio/mpeg” }]
} }
}, {

Listing 3: HTML template The Data


var clipTemplate = Web applications are rarely—if ever—made up of static
'<div class="clipContainer"> \ content. Although this is a very simple application with-
<div id="#id" class="play"></div> \ out the benefit of third-party libraries, why should this be
<p class="artist">#artist: <span class="title"> any different? Listing 2 illustrates the data that will be
#title</span></p> \ used for this solution.
<div id="#resetid" class="reset"></div>\
<div id="#progressid" class="progress">\ Each sound clip has the following pieces of information:
<div id="#progressbarid" class="progressbar"></div> \
</div> \ • Artist Name
<audio id="#clipid"> \ • Clip Title
<source src="#clipSource" type="#clipType"> • Media:
</source> \ • Clip’s file source
</audio> \ • Clip’s file type
</div>'
In a production application, this data is sourced from a
server and obtained via an Ajax call. With the data prob-
lem resolved, let’s get to the template.

The Template
Listing 3 illustrates the HTML template. I started with the out-
come, so Listing 1 illustrated the end-result of combining the
data in Listing 2 and the template in Listing 3. The process
of joining the data and template is shown in the next section.

Combining the Data and Template


The basics of any Web application start with some level of
templating. Listing 4 illustrates how that process works
here. The last line injects the newly generated HTML into the
document body.

Once the DOM has been hydrated, the process of wiring up the
event handlers can be initiated. Both the clipData and clipH-
Figure 3: Rendered display for the HTML in Listing 1. TML elements are processed in the createClipHTML() function.

24 Taming the HTML5 Audio Control codemag.com


Wiring Up the Event Handlers determine which clip is playing. The reason you need
Up to this point, your framework is takes care of every- ready access to the active clip is because the user may
thing. What follows here are things you have to provide play another clip. Out of the box, the audio controls are
regardless of framework. It’s here that you provide the not coordinated. In other words, one will play on top of
following capabilities: another unless your code intervenes in some way.

• Play and pause an audio clip


• Display a clip’s progress via a progress bar Listing 4: Code to loop through data and create HTML from template
• Interactive progress bar to allow the user to click var clipHTML = “”;
or touch the bar in order to move a clip forwards or for (var i = 0; i < clipData.clips.length; i++) {
backwards in time var newClip = clipTemplate
• Ability to re-start a clip from the beginning .replace(“#id”, i + 1)
.replace(“#resetid”, “reset” + (i + 1))
Using processClips() .replace(“#progressid”, “progress” + (i + 1))
The processClips() function hydrates the clips variable .replace(“#progressbarid”, “progressbar” + (i + 1))
and loops through the collection. In that loop, several .replace(“#clipid”, “clip” + (i + 1))
functions are called that will be discussed in a moment. .replace(“#artist”, clipData.clips[i].artist)
Listing 5 illustrates the processClips() function. One .replace(“#title”, clipData.clips[i].title)
variable that requires special attentions is the clips. .replace(“#clipSource”, clipData.clips[i].media.src)
activeClip variable. It’s important to remember that .replace(“#clipType”, clipData.clips[i].media.type);
JavaScript is a dynamic language and you can, on the clipHTML += newClip
fly, define new elements. In this particular case, you };
want a variable to hold the active clip. That way, you d.body.innerHTML = clipHTML;
don’t have to redundantly loop through the options to

Figure 4: Each UI element can be traced to a JavaScript function.

Figure 5: Illustration of how the play and pause CSS classes are implemented

codemag.com Taming the HTML5 Audio Control 25


Listing 5: processClips() function
function processClips() { processResetButton(clips[i]);
clips = d.getElementsByTagName(“audio”); processPlayPauseDiv(clips[i]);
clips.activeClip = “”; processClip(clips[i]);
}
for (var i = clips.length - 1; i >= 0; i--) { }
processProgressBar(clips[i]);

Listing 6: processProgressBar() function


function processProgressBar(clip) { processClickTouch(xy, this);
var progress = d.getElementById(“progress” + }
(clip.id[clip.id.length-1]));
progress.rect = progress.getBoundingClientRect();
progress.clip = clip; function processClickTouch(mouseEvent, progressBar) {
clip.progress = progress; progressBar.clip.currentTime =
progressBar.clip.duration *
progress.onclick = function(xy) { ((mouseEvent.clientX -
processClickTouch(xy, this); progressBar.rect.left) /
} (progressBar.rect.right - progressBar.rect.left));
}
progress.ontouchstart = function(xy) { }

Using processProgressBar() determine the appropriate object based on the ID when


The processProgressBar() function wires up all of the the user interacts with the application.
event handlers for the progress bar, which itself is noth-
ing more than a nested div element. For a specific clip, Note that the relationship is bi-directional. In other words,
based on its ID value, you can determine the correct the progress bar has a reference to the clip and the clip has
progress bar element to act on. To make things more a reference to the progress bar. This is important because
efficient, the progress bar itself gets a reference to its their respective event handlers act on the other object; the
associated clip. That way, you don’t have to continue to clip needs to act on the progress bar and vice versa.

The processProgressBar() accounts for both mouse clicks


Listing 7: processResetButton() function and touch. A more nuanced approach here is to condition-
ally wire a touch handler only in cases where a touch device
function processResetButton(clip) { is used. That requires user agent and feature detection,
var resetButton = d.getElementById(“reset” + which is not always a trivial matter. For purposes of this
(clip.id[clip.id.length-1])); article, it’s only important to acknowledge the issue so that
resetButton.clip = clip;
you can be aware of it. In this mobile-first world we live in,
I don’t know if it’s worth the bother to detect and instead,
resetButton.onclick = function(mouseEvent) {
simply wire it up in all cases. Listing 6 illustrates how the
this.clip.currentTime = 0;
processProgessBar() function is implemented.
}
}
Think about what you’re trying
to accomplish with your code
Listing 8: processPlayPauseDiv() function and whether the code’s text
function processPlayPauseDiv(clip) {
adequately conveys that story.
var playPauseDiv = d.getElementById((clip.id[clip.id.length-1]));
playPauseDiv.clip = clip;
clip.playPauseDiv = playPauseDiv;
The processResetButton()
playPauseDiv.onclick = function(mouseEvent) { Wiring up the reset button is very simple. Like the previous
if (this.className == “pause”) { example, a reference to the associated clip object is cre-
this.clip.pause(); ated for later reference. You can see in the onclick() han-
} else { dler where the clip reference is used. In this case, when the
if (typeof(clips.activeClip.id) != “undefined”) { resetButton (actually a div element) is clicked, the clip’s
clips.activeClip.pause(); current time is reset to zero. Listing 7 illustrates how the
} processResetButton() function is implemented.
this.clip.play();
} The processPlayPauseDiv()
} By now, you should see a distinct pattern as to object
} setup. In this case, the playPauseDiv holds a reference

26 Taming the HTML5 Audio Control codemag.com


to its clip and the clip holds a reference to its playPause- Listing 9: processClip() function
Div. I chose not to call it the playPauseButton because its
state can change. The resetButton, on the other hand, function processClip(clip) {
clip.ontimeupdate = function() {
never changes. It’s just a preference on my part. There’s
var id = this.id;
certainly nothing wrong with modifying the implementa-
var progress = (this.currentTime / this.duration) * 100;
tion to suit your needs. In fact, such a course of action
this.progress.childNodes[1].style.width = progress + ‘%’;
is encouraged. if (this.currentTime == this.duration) {
this.currentTime = 0;
The onclick() event makes use of the clips.activeClip prop- this.progress.childNodes[1].style.width = “0%”;
erty. This code block first checks to see if what was clicked this.playPauseDiv.className = “play”;
is using the pause class. If so, that tells you that the clip }
associated with the playPauseDiv you clicked is playing }
and also that no other clip is playing. Therefore, there’s clip.onpause = function() {
no need for further processing. On the other hand, if the clips.activeClip = “”;
playPauseDiv you click is using the play class, that means this.playPauseDiv.className = “play”;
that another clip may be playing. That’s why you have }
the clips.activeClip property. If that property contains an clip.onplay = function() {
active reference, you simply pause that clip and play the clips.activeClip = this;
current clip. this.playPauseDiv.className = “pause”;
}
Figure 5 illustrates the relationship between the CSS }
classes and the rendered HTML. What you don’t see in
Listing 8 is code that handles the class assignments. The
class assignments are handled in the clip event handlers joke. If you have to explain it, it’s not that good.” In The HTML 5 Audio and
discussed in the next section. my opinion, the same can be said of code. With that Video Controls
in mind, think about what you’re trying to accomplish
Prior to HTML 5, rendering audio
The processClip() with your code and whether the code’s text adequately and video required a third-party
There are three event handlers in the processClip() func- conveys that story. plug-in. Today, all major browsers
tion: support most of the HTML5/
Essentially, the entire JavaScript Module is nothing more CSS3. Nevertheless, as this article
• ontimeupdate: Fires whenever the audio con- than a view model. The only difference is that in this case, shows, there’s a dichotomy to
trol’s current time changes. Remember when you I didn’t rely on a third-party framework. the support as between desktop
assigned the clip’s progress property to refer- and mobile browsers. Even
ence the progress bar? This is where it comes into among desktop browsers, levels
play. As the clip’s time changes, the progress bar Conclusion of support can vary. For more
changes to reflect that percent of time played. In As you’ve learned in this article, even if a browser states information on how to use the
addition, notice where the playPauseDiv classname that it has full support for HTML5, you must still test and HTML5 Audio and Video controls,
is changed to reflect the associated clip’s current verify. With the HTML5 Audio Control, although a mobile the following link is a good place
state. browser supports the function, they don’t support the to start your research:
• onpause: Fires when the audio control is paused. control display. It’s unfortunate because it requires you http://www.w3schools.com/tags/
When a clip is paused, that means there’s no ac- to resort to alternative approaches. Nevertheless, even ref_av_dom.asp.
tive clip, which is why the clips.activeClip variable with the required intervention, without the aid of third-
is cleared. Like the ontimeupdate event, the play- party Javascript frameworks and libraries, the task isn’t
PauseDiv’s classname is adjusted to properly reflect that difficult.
the associated clip’s (audio control) state.
• onplay: Fires when the audio control is played. In this This article focused on taming the HTML5 Audio Control,
handler, the clips.activeClip property is set and the and I hope it’s proven instructive to you on how those
pausePlayDiv’s classname is set accordingly as well. other tools can work at a core level and some JavaScript
recommended practices. By no means am I suggesting
that you eschew JavaScript frameworks. For complex ap-
plications, they can be valuable. As it turns out, taming
A user interface is like a joke. the HTML5 Audio Control wasn’t that difficult after all.
If you have to explain it,
it’s not that good. John V. Petersen

The processClip code illustrated in Listing 9 is very


clean, in large part due to much of the housekeeping
already addressed. Early on, the clip was outfitted with
its reference properties. Therefore, there’s no need for
redundant code to search for the right objects to act on.
It goes without saying that good code is clean code. I
think that going from good-to-great is determined by
whether the code itself can tell a story. There’s a quote
that goes along the lines of “A user interface is like a

codemag.com Taming the HTML5 Audio Control 27


ONLINE QUICK ID 1605061

Why F#?
F# is a functional-first language on the .NET platform, which focuses on helping you solve complex problems with
simple, clean code. I’ll show you today how writing code that is similar to C#, and writing code that uses features
that are completely unique to F#, empowers you to create robust, maintainable solutions. Let’s get started!

Concise and Familiar Code You’ll notice first that the F# is somewhat shorter and
The ability to write clean and concise code that interop- lacking in punctuation, but that it’s otherwise quite com-
erates with all .NET languages is one of the most-cited parable. F# doesn’t need curly brackets or semicolons
favorite features of F#. It’s possible—and common—to because it’s whitespace-sensitive. For those of you who
use familiar .NET libraries from F#. Let’s compare two use, or have used, StyleCop, it’s like having some of that
very simple code samples that build a console app cre- functionality built right into the language!
ating a stopwatch calculating elapsed time. First, the
code in C#:

Rachel Reese using System; For those of you who use,


rachel@jet.com using System.Threading; or have used, StyleCop,
http://rachelree.se using System.Diagnostics; it’s like having some of that
https://twitter.com/rachelreese functionality built right
namespace cstopwatch into the language!
Rachel Reese is a long-time
{
software engineer and math
geek who can often be found class MainClass
talking to random strangers {
about the joys of functional public static void Main (string[] args) In addition to the lack of curly brackets, there’s a return
programming and F#. She { value but no return statement. This is because every
currently handles training and var sw = Stopwatch.StartNew(); function in F# is, well, a function; it should produce the
evangelism for Jet.com in the Thread.Sleep(150); same result every time it’s given the same input. When
NYC area, and has a habit of sw.Stop(); writing F#, consider your inputs and your outputs for
starting user groups, so far, Console.WriteLine( each function you write, and strive to minimize the side-
in Hoboken, NJ (Pluralsight “elapsed time is {0}”, effects in your code. Even the main function has a return
Study Group), Nashville, TN sw.ElapsedMilliseconds); value. To make it super easy, though, the return key-
(@NashFSharp) and Burling- } word is unnecessary. In F#, the last statement in a func-
ton, VT (@VTFun). She’s also } tion that’s evaluated is the return value. In this case,
an ASPInsider, an F# MVP, a } that’s 0.
Xamarin MVP, a community
enthusiast, one of the founding Next, the equivalent F#: Type Inference
@lambdaladies, and a Rachii. F# also has very powerful type inference. Based on the
You can find her on twitter, @
open System code samples above, it appears that F#’s type inference
rachelreese, or on her blog:
open System.Threading is similar to C#’s when using var. However, consider the
rachelree.se
open System.Diagnostics following C#:

[<EntryPoint>] public static int square(int x) {


let main argv = return x * x;
let sw = Stopwatch.StartNew () }
Thread.Sleep 150
sw.Stop () In F#, type inference works even at the function and pa-
Console.WriteLine ( rameter level. You only have to write:
“elapsed time is {0}”,
sw.ElapsedMilliseconds) let square x = x*x
0 // return an integer exit code
The function is automatically inferred to be of type x:int
-> int because the compiler has no additional informa-
tion as to what type it should be using. In F#, func-
tion signatures are written much differently. This means
that the function square takes in a single integer x as
a parameter, and returns an integer. But here’s where it
gets interesting: if you need to call that function later
using a different type, you have to convert the previous
function.

public static float inverse(float y) {


return 1/(square(y));
Figure 1: Sending code to F# Interactive }

28 Why F#? codemag.com


However, with F#, it’s merely a matter of writing the new (in Xamarin Studio). This loads the F# Interactive window
function. and sends the code to the REPL. It is automatically evaluated
and the result is printed, as in Figure 1 and Figure 2.
let inverse y = 1.0/(square y)

The previous function, square, is automatically updated Concise and Powerful Code
to be of type x:float -> float now, as will be any other F# has several features that let you succinctly model a
relevant code snippets because of the new information number of situations and lead you to write beautiful, de-
given to the compiler about these functions. clarative code. I’ll be covering discriminated unions, op-
tion types, and pattern matching in this article.
REPL
F# provides a REPL (Read-Eval-Print-Loop) to evaluate your Discriminated Unions and Pattern Matching
code easily. It’s a way to instantly evaluate your code with- If you’re unfamiliar with discriminated unions, you can
out compiling an entire project. You can either type code think of them in two ways. First, they’re similar to a C#
directly into the REPL, or, if you’re working in a script file, enum type. In the snippet below, I’ve declared a DateTi-
it’s simply a matter of highlighting the code you’d like to run meInfo that can be one of the six subtypes.
and choosing alt-enter (in Visual Studio) or control-enter
type DateTimeInfo =
| OrderDate
| PickDate
| ShipDate
| DeliveryDate
| CancelDate
| ReturnDate

Second, unlike an enum type, you can add qualifying in-


formation to each subtype. In this usage, the discrimi-
nated union really acts like a simple object hierarchy.
Figure 2: Code that has been evaluated in F# Interactive Consider the following Payment type:

codemag.com Why F#? 29


Listing 1: C# Simple hierarchy to compare to F# discriminated union
public abstract class Payment { } CreditCard = creditCard;
}
public abstract class CreditCard : Payment }
{
public CreditCardNumber CreditCard { get; private set; } public abstract class CheckingAccount : Payment
public CreditCard(CreditCardNumber creditCard) {
{ public RoutingNumber RoutingNumber { get; private set; }
CreditCard = creditCard; public AccountNumber AccountNumber { get; private set; }
} public CheckingAccount(RoutingNumber routingNumber,
} AccountNumber accountNumber)
{
public abstract class DebitCard : Payment RoutingNumber = routingNumber;
{ AccountNumber = accountNumber;
public CreditCardNumber CreditCard { get; private set; } }
public DebitCard(CreditCardNumber creditCard) }
{

Pattern matching is a natural fit with discriminated


unions. It’s very similar to a select case statement in C#;
it’s simply a way to branch your code based on certain
cases, but with several more options. See Figure 3 for the
many ways of handling pattern matching in F#. C# can
only handle the first pattern: the constant pattern.

These four lines of code


contain the same basic
information as an idiomatic
version of the same code in
C#, which is normally written
into four separate files!

What does pattern matching actually look like? For the


Payment type in the previous snippet, you have:

let makePayment payment =


match payment with
| CreditCard number -> payWithCredit number
| DebitCard number -> payWithDebit number
Figure 3: The F# pattern matching options, according to MSDN | Checking(rout,acc) -> payChecking rout acc

Because payment is a discriminated union, I’m able to


type Payment = naturally pattern-match on the sub-types, CreditCard,
| CreditCard of CreditCardNumber DebitCard, and Checking. I’m also able to access any addi-
| DebitCard of CreditCardNumber tional information—for example, the AccountNumber and
| Checking of Routing * AccountNumber RoutingNumber for the checking account—in order to use
it after the arrow. Even more useful, however, is this fea-
Each subtype here, CreditCard, DebitCard, and Check- ture: When you add a new sub-type to the discriminated
ingAccount, are types of payments, but have slightly union, such as ApplePay or AndroidPay, you’ll receive a
different requirements and need to be handled differ- warning the next time you compile for each and every
ently in each case. These four lines of code contain the time that you have pattern-matched on the Payment type
same basic information as in Listing 1, an idiomatic ver- but forgotten to include the new subtype. That doesn’t
sion of this code in C#, which is normally written into happen when you add a new overloaded class in C#!
four separate files. In fact, there’s even more informa-
tion in the F# version, as the C# code still lacks struc- Warning FS0025: Incomplete pattern matches on this
tural equality. In order to provide that, you’d have to expression. For example, the value 'ApplePay' may
override the equality implementation, the comparison indicate a case not covered by the pattern(s).
implementation, and the GetHashCode. Additionally, the
C# version still doesn’t have proper immutability; there It’s only a compiler warning so it can be ignored, but this
should be no setter at all, and the backing field should has saved many a developer from a 3am phone call to fix a
be read-only. bug in production.

30 Why F#? codemag.com


Expanded Feature Set [<Measure>] type C // Celcius
There are many features of F# that don’t exist in C#. So [<Measure>] type m // Meters
far, you’ve seen type inference, discriminated unions, and [<Measure>] type s // Seconds
pattern matching, which aren’t possible in C#, but do have
similarities to some C# features. Let’s next check out option let windChillAus (t:float<C>) (v:float<m/s>) rh =
types, units of measure, and type providers. None of these t + 0.33<C> *
are fully available in C#, but type providers are a completely (rh/100.0 * 6.105**((17.27*t)/(237.7<C> + t))) –
unique feature to F#. 0.7<C> * float(v) - 4.<C>

Units of Measure Option Types


Do you remember the Mars Climate Orbiter crash in 1999? Option types are a special kind of Discriminated Union,
NASA engineers lost a $125 million machine because a cru- similar to nullable types in C# with a few added features.
cial section of code expected metric units, but was unfortu- In F#, anything can be optional, not just a numeric type.
nately sent English units instead, resulting in catastrophic A string, a custom type, even a function all can be op-
miscalculations. If only those engineers had used F#! There’s tional. Let’s consider the following function, containing a
a feature that allows any numeric input to be tagged with pattern match to convert a string array to a string array
any identifier, indicating what type of unit it should have. It option. You use this in a console app to safely handle the
doesn’t have to be only scientific programming; in fact, it’s command line arguments.
easy to use units of measure in the code around a warehouse
to safely stock, pick, or ship a case instead of accidentally let input = match argv with
substituting a whole pallet of something. | [|””|] -> None Real-World F# at Jet.com!
| x -> Some x
At Jet.com, we’re heavy users
For example, the following snippet shows how you could
of F#, and all of the techniques
write a function to calculate the wind chill temperature in You can also use combinators, which are higher-order
you’ve seen in this article are
the US: functions, such as map, iter, and fold, to act on the op- leveraged extensively in our code
tional types. In the following code, you want to retrieve every day. To learn more about
[<Measure>] type F // Fahrenheit the first element of an array that could be empty, so the most exciting startup in
[<Measure>] type Mi // Miles you use Array.tryHead. This returns an option, possibly e-commerce, visit Jet.com.
[<Measure>] type Hr // Hour containing the first element of the array. Next, you use To see more of our code,
Option.map to evaluate the Name property of that first visit github.com/jet.
let windChillU (t:float<F>) (v:float<Mi/Hr>) = element, if it exists. If the element doesn’t exist, the fol-
35.74<F> + 0.6215 * t lowing code returns None.
- 35.75<F> * float(v) ** 0.16
+ 0.3965 * t * float(v) ** 0.16 items
|> Array.tryHead
First, declare the new types: F, Mi, and Hr, for Fahrenheit, |> Option.map (fun item -> item.Name)
miles, and hours. You don’t need to use standard abbrevia-
tions, although where standard abbreviations exist, using Type Providers
them would be a good practice. It’s also a good idea to use Let’s turn now to type providers, which is a powerful fea-
comments to clarify (as in my examples) especially in cases ture, completely unique to F#. Simply put, type providers
where there might be several standard units for a specific ab- are a means of accessing data, any data that has a sche-
breviation. In general, units of measure are often collected ma. The most common type providers connect you with
together in a single file, near the top of your project. More SQL Server, csv files, JSON, and XML, but there are type
on this later. providers available for nearly all data forms. There are
even type providers for other languages, including R and
Compare that code to the next example, which adds types for Python. Using type providers is quite easy, just a matter
Celsius and kilometers, and contains the formula for calcu- of a couple lines of code to connect to your data source.
lating the wind chill in Canada. Writing a type provider is a very complicated endeavor
and won’t be covered here.
[<Measure>] type C // Celcius
[<Measure>] type Km // Kilometers The benefits to using a type provider over an ORM, such as
Entity Framework, are huge.
let windChillC (t:float<C>) (v:float<Km/Hr>) =
13.12<C> + 0.6215 * t • Type providers work within both script files and the
- 11.37<C> * float(v) ** 0.16 REPL, making it much faster and simpler to proto-
+ 0.4275 * t * float(v) ** 0.16 type data-driven code
• There are no code-generated files that need to be
Here’s an interesting fact: When researching the wind maintained, even for the SQL Server-type provider
chill calculation, I discovered that, although the US and that sits on top of Entity Framework. The necessary
Canada use very similar formulas, the formula that Aus- code generation happens, the files are incorporat-
tralia uses is completely different and much more compli- ed into the dll, and then they’re cleaned up. This
cated! The US and Canada can use the simpler formulas means that your source is always in sync and there’s
by assuming that the temperature is already sufficiently no code lying around that you have to remember
cold—at warmer temperatures, relative humidity plays a to keep updated. Most importantly, though, your
significant role. The Australian formula looks like this, data layer is scalable to millions of types. There’s
where rh is the relative humidity: a type provider for the World Bank database, which

codemag.com Why F#? 31


The first piece of code sets up the type providers. Con-
necting to the World Bank is only one line of code. Setting
up the JSON type provider is only slightly more compli-
cated. You must provide a sample set of JSON so that the
type provider knows how to parse what it will receive. To
do this, you create a literal string value, pointing to a file
in the current directory. You declare the type using the
sample, then call GetSample. Now you’re connected. This
is all the set up needed to connect to a data source.

// Get data
let wb = WorldBankData.GetDataContext()

[<Literal>]
let Path =
__SOURCE_DIRECTORY__ + “\example.json”

type Venues = JsonProvider<Path>


let rest = Venues.GetSample()

The main piece of code involves parsing the JSON for each
city, but first, you need to load the response by calling
Venues.Load.

let venues =
try
Some(Venues.Load(nearPlaceUrl + city))
with
| _ -> None

This returns an option type, so the processing relies heav-


ily on option combinators to process the several levels of
returned information. First, you request all of the groups
Figure 4: Using the World Bank type provider for that city.

venues
F# is Fully Open-Sourced! contains thousands of sets of information for every |> Option.map (fun v -> v.Response.Groups)
country in the world. Freebase, the now-defunct on-
F# was completely open-sourced line database, also had a type provider; imagine an Next, you look for the group containing “recommended”
in 2010 and runs on many ORM trying to manage that scale! items, and ask for the first recommended item in that array.
platforms besides Windows. • Type providers also provide IntelliSense in the data
For information on learning, source, as you can see in Figure 4, which calls in to groups
teaching, or using F#, check out the World Bank type provider. For a database or csv |> Array.filter
the guides on the fsharp.org site,
file, you’ll see a list of table names and then column (fun g -> g.Name = “recommended” &&
the official home of the F#
names. For a Web service, you see a list of available g.Items.Length > 0)
Software Foundation
methods to call. |> Array.map (fun g -> g.Items)
|> Array.tryHead

Finally, you try to return the name of that first recom-


Your source is always in sync
mended item.
and there’s no code lying
around that you have to items
remember to keep updated. |> Array.tryHead
Most importantly, though, |> Option.map (fun item -> item.Venue.Name)))
your data layer is scalable
to millions of types! None of these levels necessarily exist, yet you’re able to
continue piping the requests in as normal, knowing that
the code is safe. Now that you have a function to handle
finding the venue for a city, you create a simple list ex-
Let’s see an example using two type providers: the World pression to return all cities. In this case, you choose Op-
Bank type provider and the JSON type provider. First, I’ll tion.iter because you’re printing each item to the output
connect to the World Bank type provider to find the capi- screen (and causing a side effect) rather than creating a
tal city for every country in the world. Then, using that in- list to manipulate later.
formation, I’ll call into the Foursquare API with the JSON
type provider to determine the top venue in each capital [for country in wb.Countries ->
city. For the complete code, see Listing 2. let city = country.CapitalCity

32 Why F#? codemag.com


if city <> “” then In F#, a code snippet can only reference another piece of
getVenuesFor city code that’s above it, literally. This is true both within a
|> Option.iter file and within the solution. For example, Figure 5 shows
(fun v -> printfn “Top recommended an example project containing some of the code from this
venue in %s, %s is article. Code that’s placed at the end of the TP.fsx file will
%s” city country.Name v)] be able to reference all of the code in the project. Code
in keys.fsx, however, won’t be able to reference any code
This is all the code you need—54 lines total—to take in either Intro.fsx or TP.fsx. This completely eliminates
data from two data sources, combine it, and produce a circular references in your code.
meaningful result. There’s no lingering generated code to
maintain and no cached files to sort through. As soon as
a new country is in the World Bank and the capital city Conclusion
has venues listed in Foursquare, your code will see it and As you can see, using the F# language allows you to write
print out a result. clean, concise code to solve complex problems. Using
some of the features that I’ve covered here, you can ac-
complish significant tasks in a very few lines of code. Visit
Getting Started fsharp.org, the F# Software Foundation’s official website,
Now that you know all the reasons to try F#, let’s get for additional information and learning tools.
started. If you don’t have a copy of Visual Studio installed,
you can download a free copy of Visual Studio Community Rachel Reese
Edition or Xamarin Studio. There are also plug-ins avail- Figure 5: File listing in a solution
able for Emacs and Atom, among others.

Once you’ve chosen your editor, it’s time to code. F# sup-


ports script files, so you don’t have to create an entire
solution just to play around with code; one file can act as
a whole project. To start, simply create a script file called
“code.fsx” and some of the code from this article.

F# is whitespace-significant, so be sure that your inden-


tations are correct. Next, highlight the code, and choose
Alt-Enter (VS) or Ctrl-Enter (Xamarin Studio). This brings
up the F# Interactive window (the REPL) and runs your
code automatically.

One more thing to note: In order for F#’s type inference


to work properly, F# also uses a strict file ordering in
projects. Files are not listed alphabetically in Visual Stu-
dio. They’re listed in compile order, from top to bottom.

Listing 2: Using the World Bank and JSON type providers


// Get data venues
let wb = WorldBankData.GetDataContext() |> Option.map (fun v -> v.Response.Groups)
|> Option.bind
[<Literal>] (fun groups ->
let Path = __SOURCE_DIRECTORY__ + “\example.json” groups
|> Array.filter
type Venues = JsonProvider<Path> (fun g -> g.Name = “recommended” &&
let rest = Venues.GetSample() g.Items.Length > 0)
|> Array.map (fun g -> g.Items)
// Parse venue data |> Array.tryHead
let foursquareBaseUrl = |> Option.bind
“https://api.foursquare.com/v2/” + (fun items ->
“venues/explore?client_id=” + keys.ClientId + items
“&client_secret=” + keys.ClientSecret + |> Array.tryHead
“&v=20150907” |> Option.map
let nearPlaceUrl = foursquareBaseUrl + “&near=” (fun item -> item.Venue.Name)))
let getVenuesFor city =
if city = “” then None // Get top venue by capital city
else [for country in wb.Countries ->
let venues = let city = country.CapitalCity
try if city <> “” then
Some(Venues.Load(nearPlaceUrl + city)) getVenuesFor city
with |> Option.iter
| _ -> None (fun v -> printfn “Top recommended venue in %s,
%s is %s” city country.Name v)]

codemag.com Why F#? 33


ONLINE QUICK ID 1605071

Arranging Views with


Xamarin.Forms Layouts
Xamarin apps run on a variety of device sizes—from small phones to bigger tablets—and the devices can change from
portrait to landscape mode in an instant. The app UI needs to adapt to these size and orientation changes, look good, and
be functional. Every UI framework has the notion of positioning and sizing elements on the screen. As systems have evolved,

these layout tools have advanced too, adding features want to use a custom set of colors; here’s how to make
that simplify commonplace layout problems. It’s these that happen. Start by creating a static class and add some
layouts that provide the means to building adaptive user static properties:
interfaces. In this article, I’ll look at the Xamarin.Forms
layout views and show how to use them to build various namespace Common {
UI design structures. static class Hues {

public static readonly Color Sky =


Views and Layouts Color.FromHex(“#226765”);
Walt Ritscher The visual elements in Xamarin.Forms fall into two sepa- public static readonly Color Fire =
waltr@scandisoft.com rate categories: controls and arrangers. Both are consid- Color.FromHex(“#AA4B40”);
425-269-5677 ered visual elements, share a common base class (View), }
xamlwonderland.com and are collectively known as Views. But their missions }
@waltritscher are different. View classes (the controls) are responsi-
Walt’s enthusiasm for crafting ble for gathering user input or showing information to In this example, I used the Color.FromHex method to de-
software interfaces blossomed the user. They are called controls or widgets in other UI fine the two custom colors. The Color struct has other
early. frameworks. methods to describe colors (FromRGB, FromHlsa, and
FromUint); use whichever method you prefer to define
Just a few days after discover- Layouts (the arrangers) serve a different purpose. A lay- your color set.
ing how to move pixels around out class is a View class that contains a collection of child
a computer screen, he was views. It’s responsible for arranging the child views into To use these custom colors in a page, add a custom XML
devouring books on the topic of position in the UI. It also collaborates with each child to namespace to the root element:
computer graphics and UI de- determine the final rendering size. To be clear, layouts are
sign. Before long, he was shar- also views, but are rarely called that by the community. <ContentPage
ing his discoveries with other xmlns=”...”
technology buffs, a lifelong Figure 1 shows a list of classes that derive from the View xmlns:x=”...”
pursuit that has led to teaching class. Most of them fall into the input/output control cat- xmlns:c=”clr-namespace:Common;assembly=Demo” >
engagements at universities,
egory. The classes outlined with red rectangle in Figure 1
private training companies, and
are the base classes for the layout views. I used the prefix c for my XML namespace. Normally, I’d
the international conference
circuit. As a consultant, he has use a more readable name, like common, but I chose
worked with a wide spectrum Layout Classes the shorter name so that the example fits into the code
of clients, including Microsoft, The layout classes do the work of arranging the elements snippet size constraint for the magazine. Notice the use
HP, and Intel. He’s now a staff on the screen. Each layout specializes in a style of ar- of the clr-namespace: syntax in the namespace declara-
author at Lynda.com, part of rangement. If you’re familiar with other XAML frame- tion: That’s how you indicate which .NET namespace to
the LinkedIn family, where his works, many of these layout classes (shown in Figure 2) use.
content team produces hundreds will seem familiar, albeit with different names.
of technical training courses for This snippet uses the Common namespace in the Demo
software developers each year. The simplest layout containers are the ContentView, assembly. Look at the code snippet shown earlier and you
Frame, and ScrollView. They’re designed to provide a can see that the color properties are inside the Common.
His current UI obsession re- few simple services to the child items. Although they can Hues class. Now that the c namespace is registered, I can
volves around the XAML space; contain multiple child items, there’s no good reason to access the colors with this snippet:
Windows 10 Universal Apps, have more than one child in these layouts. They simply
HoloLens, and WPF APIs. Walt is don’t offer layout options that help arrange multiple BackgroundColor=”{x:Static c:Hues.Sky}”
also an MVP and the author of
child items. The other layouts (AbsoluteLayout, Grid,
the free Shazzam Shader Editor
RelativeLayout, and StackLayout) excel at arranging The ContentView and Frame
at Shazzam-tool.com.
multiple child items. It’s common to mix and combine ContentView is not intended to be used directly in your
multiple layouts into the page UI. Therefore, understand- XAML tree. Rather, it’s designed to be a base class for
ing the strengths of each layout is essential for crafting building your own composite views. The Frame, which de-
your pages. rives from ContentView, is a better choice for a wrapper
around a child view. Its biggest asset is that it can render
A Word About Color a visible border around the child. This next snippet shows
The Xamarin.Forms prebuilt color palette is small. There how to set the OutlineColor and add a dropshadow to the
are nineteen color constants available. For this article, I Frame:

34 Arranging Views with Xamarin.Forms Layouts codemag.com


<Frame OutlineColor=”White” WidthRequest and HeightRequest property on the child
HasShadow=”True” > view.
<Label Text=”The Label” />
</Frame> There will be times when the requested size (or desired
size) is smaller than the layout container. For example,
The Frame inherits a useful property, Padding, from the a 180-pixel width Label within a 300-pixel width Stack-
Layout base class. Non-layout views don’t have margin Layout. In this scenario, the panel defers to the Vertica-
or padding properties. The only way to add space around lOptions and HorizontalOptions properties to determine
a view is it to put it inside a layout and set the Padding where to place the child element within the extra space.
property like this:

<Frame Padding=”30”>
<Label Text=”The Label” />
</Frame>

Because the Padding property is part of the Layout base


class, it’s settable on any of the other layout classes.

VerticalOptions and HorizontalOptions


Every view has a size that’s set by a collaboration be-
tween the child view and its layout container. Use the
VerticalOptions, HorizontalOptions, WidthRequest,
and HeightRequest properties to influence the final
rendered size. Let’s look at the default size of an ele-
ment.

<Frame
Padding=”10,20”
BackgroundColor=”{x:Static c:Hues.Sky}”>
<BoxView
Color=”{x:Static c:Hues.Fire}”/>
</Frame>

The example in the code snippet uses a Frame as the lay-


out and a BoxView as the child. The BoxView is a simple
view, useful for drawing solid color rectangles. I’m not
specifying a width or height for the BoxView. Nor am I
setting any value for the VerticalOptions and Horizonta-
lOptions. Figure 3 shows the UI running on an Android
emulator.

By default, the BoxView is sized to match its container,


the Frame. The blue buffer shown around the edge of the
BoxView is due to the Padding = “10,20” property on
the Frame. In this case, that means 10 pixels of padding Figure 1: The View classes in Xamarin.Forms
on the left and right and 20 pixels of padding on the top
and bottom.

The Dynamics of Sizing


Sizing and positioning can get complicated, especially
in sophisticated multilayered interfaces. Here are some
pointers that will help understand the way the system
works.

Each view has a desired size, the size that it wants to be


rendered at, if possible. The desired size is calculated
internally within the child view. Take a Label as an ex-
ample. Its desired width depends on many factors. How
many characters are in the Text property? What is the
font size?

It’s the same with the desired height. The desired height
will be taller when there are lots of characters, a big
font size, and word wrap are enabled. In general, it’s
better to let the view decide on its own size. You can
overrule the desired size if necessary by setting the Figure 2: The layout classes in Xamarin.Forms

codemag.com Arranging Views with Xamarin.Forms Layouts 35


There are several settings available for the LayoutOp- Color=”{x:Static c:Hues.Fire}”
tions enumeration. The discussion here is around the HeightRequest=”1400” />
HorizontalOptions and it’s similar for the VerticalOp- </ScrollView>
tions property.
Figure 4 shows the result. If you look closely at the An-
• Start droid and Windows Phone screenshots, you can see the
• Center scrollbar on the right side of the screen. It’s not visible on
• End the iPhone screenshot, but that’s due to the limitations of
• Fill (Default) my screen capture software.
• StartAndExpand
• CenterAndExpand StackLayout
• EndAndExpand This layout is one of my favorites, and I use it everywhere
• FillAndExpand in my UI. It has a simple mission: position the child el-
ements in a stack, either horizontally or vertically. The
I’ll look at the top four items in this list. LayoutOp- order that the child elements are added to the layout is
tions.Start sets the child width to the requested size the order in which they are stacked. This snippet adds two
and then positions the element to the side of the con- BoxViews with default HorizontalOptions, and three more
tainer. In left-to-right languages, the start position is with specific HorizontalOptions set:
the left side of the container, in right-to-left languages,
the start position is on the right side. LayoutOptions. <StackLayout >
Testing on Each Platform End does the opposite, positioning the element on the <!-- defaults to HorizontalOptions=”Fill”-->
right side in left-to-right languages and on the left <BoxView Color=”{x:Static c:Hues.Fire}” />
Xamarin.Forms does an excellent
side in right-to-left languages. LayoutOptions.Center <BoxView Color=”{x:Static c:Hues.Sky}” />
job of hiding the platform-
centers the element and keeps the requested size. Lay-
specific layout mechanics behind
their layout views. Quirky issues outOptions.Fill stretches the width of the child element <BoxView Color=”{x:Static c:Hues.Sky}”
are bound to appear during to match the parent container. LayoutOptions.Fill is the HorizontalOptions=”Start”/>
development. Be sure to test your default LayoutOption setting.
layouts on each platform to see
that the UI looks and works as Take a look at this next snippet. The BoxView doesn’t
expected. specify a size, so it’ll get the default size. It also doesn’t
indicate the VerticalOptions or HorizontalOptions ei-
ther, so it defaults to the LayoutOptions.Fill value. As a
result of these settings, the parent Frame stretches the
BoxView to fit horizontally and vertically.

<Frame Padding=”30” BackgroundColor=”#226765”>


<BoxView BackgroundColor=”#AA4B40” />
</Frame>

To override LayoutOptions, use this this XAML:

<Frame Padding=”30” BackgroundColor=”#226765”>


<BoxView BackgroundColor=”#AA4B40”
HorizontalOptions=”End”
VerticalOptions=”Start” />
</Frame>

Now the BoxView is positioned to the upper-left posi-


tion on my phone (because English is a left-to-right lan-
guage). The BoxView isn’t stretched inside the Frame, so
it will fall back to its default size of 40x40-pixels.

ScrollView
ScrollView is useful when the child content is bigger than
can fit in the UI. For example, when the text content on
a page is too tall to fit on the screen, wrap the Label in
a ScrollView. This can make your UI readable on smaller
screen sizes. Content that fits on a big-screen phone like
the Nexus 6 will still be readable on the smaller Moto G
phone. This code snippet shows a tall BoxView within the
ScrollView:

<ScrollView
Padding=”30”
BackgroundColor=”{x:Static c:Hues.Sky}” >
<BoxView Figure 3: Default Size for BoxView on Android

36 Arranging Views with Xamarin.Forms Layouts codemag.com


Figure 4: ScrollView in action

Figure 5: StackLayout on the devices

codemag.com Arranging Views with Xamarin.Forms Layouts 37


<BoxView Color=”{x:Static c:Hues.Fire}” <Grid.ColumnDefinitions>
HorizontalOptions=”Center”/> <!-- Absolute size-->
<BoxView Color=”{x:Static c:Hues.Sky}” <ColumnDefinition Width=”113”/>
HorizontalOptions=”End”/> <ColumnDefinition Width=”37”/>
Figure 6: Horizontal layout of </StackLayout> </Grid.ColumnDefinitions>
images
Figure 5 shows the results. An Auto-sized column’s width is determined by its con-
tent. An Auto-sized column with a 120-pixel-wide label
Each item is positioned immediately below the previous and an 80-pixel-wide button will be set to 120 pixels.
one, with six pixels spacing between the items. The spac- This example shows two columns with automatically sized
ing is adjustable with the Spacing property. widths:

<StackLayout Spacing=”18”> <Grid.ColumnDefinitions>


<!-- Auto size-->
Figure 6 is an example of a StackLayout with a horizontal <ColumnDefinition Width=”Auto”/>
orientation: <ColumnDefinition Width=”Auto”/>
</Grid.ColumnDefinitions>
<StackLayout Orientation=”Horizontal”>
<Image Source=”twitter.png”/> A Star sized column (also known as a proportional size)
<Image Source=”facebook.png”/> width is determined by its relation to the other columns
<Image Source=”pinterest.png”/> in the grid. Take a look at this example:
</StackLayout>
<Grid WidthRequest=”450”>
Two-Dimensional Layout with the Grid <Grid.ColumnDefinitions>
The grid is a time-tested way to lay out information in <ColumnDefinition Width=”113”/>
a two-dimensional space. Designers determine placement <ColumnDefinition Width=”37”/>
of important elements with gridlines. As UI design has <ColumnDefinition Width=”2*”/>
formalized, the grid has triumphed as a prime tool in the <ColumnDefinition Width=”3*”/>
layout workflow. <ColumnDefinition Width=”5*”/>
</Grid.ColumnDefinitions>
The Xamarin Grid is similar to other XAML-based grids, </Grid>
although it has one feature that you haven’t seen before.
It sports the ColumnSpacing and RowSpacing attributes, To determine the sizes of each column, the Grid starts
which define how much room to put between the rows and by resolving the Absolute-size and Auto-size columns.
columns in the grid. In this case, the two Absolute-sized columns total 150
pixels. The Grid has requested 450-pixels width. Assum-
<Grid ColumnSpacing=”6” ing that the Grid is rendered at 450-pixels, that leaves
RowSpacing=”4”> 300-pixels for the remaining three columns. Next, the
grid tallies a sum of all the star-sized items (2* + 3* +
Other than this small change, the other Grid attributes are 5*=10*) and divides each column by the column star val-
familiar territory for XAML devs. For those new to XAML, ue. The results for the third, fourth, and fifth columns are
here’s the overview. You define columns within a column (2/10 (20%), 3/10 (30%), and 5/10 (50%)). Using these
definition section and rows in a row definition section: percentages, the final rendered sizes for the columns are:
113, 37, 60, 90, and 150.
<Grid ColumnSpacing=”6”
RowSpacing=”4” Even though I’m not showing examples of RowDefinitions,
BackgroundColor=”{x:Static c:Hues.Sky}”> they work the same way for adjusting row heights.
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”100”/> Once the grid is defined, it’s time to add the child ele-
<ColumnDefinition Width=”Auto”/> ments. Unless otherwise indicated, a child is positioned
</Grid.ColumnDefinitions> in column 0, row 0. To modify the default placement, use
<Grid.RowDefinitions> the Grid.Column and Grid.Row attributes.
<RowDefinition Height=”3*”/>
<RowDefinition Height=”3*”/> <BoxView Grid.Row=”1” Grid.Column=”2”/>
</Grid.RowDefinitions>
<!-- child elements go here. --> You can also use the Grid.ColumnSpan and Grid.RowSpan
</Grid> attributes to specify how many columns and rows the
child view should span.
This snippet creates a two-row, two-column grid. To control
the size of the row or column, use the sizing option speci- <BoxView Grid.RowSpan=”2”
fied with the GridUnitType enumeration. There are three Grid.ColumnSpan=”4” />
choices for GridUnitType sizes: Absolute, Auto, and Star.
AbsoluteLayout
An Absolute-size column’s width is hard-coded to the Use the AbsoluteLayout when you need precise control
specified value. This example shows two columns with over the x and y positions, and the width and height of
fixed widths: the child elements. It has its place in the layout world. In

40 Arranging Views with Xamarin.Forms Layouts codemag.com


most situations, it’s better to use one of other layouts; Proportional sizes are an improvement over the absolute
they make for a more responsive design. Absolute layout sizes; an even better option is to use the RelativeLay-
harkens back to the old days when we brute-forced screen out.
elements into position. Although that’s less common
now, it does have its place for certain layout challenges. RelativeLayout
A RelativeLayout is useful for creating adaptive layouts
Each child element describes its location and size with where the UI adjusts to screen rotation and screen sizes.
the AbsoluteLayout.LayoutBounds attribute. Use a com- Use it to lay out UI elements based on their parent’s posi-
ma-separated list to indicate the bounding rectangle (x, tion and dimensions as well as other views’ positions and
y, width, and height) values: dimensions. Another key benefit of the RelativeLayout
(and the AbsoluteLayout) is the ability to overlap or layer
<AbsoluteLayout> child elements.

<BoxView Each element in the RelativeLayout can define a con-


AbsoluteLayout.LayoutBounds=”90, 50, 75, 25” straint, which is a rule that defines how the element re-
BackgroundColor=”{x:Static c:Hues.Sky}” /> lates to other items (parent, siblings).
</AbsoluteLayout>
There are several constraint types available:
The parameters for the AbsoluteLayout.LayoutBounds at-
tribute are as follows: • RelativeLayout.YConstraint
• RelativeLayout.XConstraint Xamarin Test Cloud
• X : the horizontal position of the element • RelativeLayout.WidthConstraint
The Xamarin Test Cloud is a paid
• Y: the vertical position of the element • RelativeLayout.HeightConstraint
service available from Xamarin.
• Width: the width of the element
Within the cloud are thousands
• Height: the height of the element The names are self-explanatory. It’s not hard to under- of physical devices, ranging
stand what each constraint type does. Next, I’ll look at from older Android phones
This snippet results in a 75-pixel wide, 25-pixel tall Box- several of the constraints to show you how they work. to the newest iPhones. This is
View that is positioned 90-pixels left and 50-pixels down an effective way to test your
from upper-left corner of its parent. Imagine a scenario where you have two views, a Label and Xamarin.Forms user interface and
a Button. The Label is positioned at the top of the Rela- verify that it looks and acts as
As I said, hard-coded size and position is a throwback to tiveLayout and set to 90% of the parent’s width. The But- anticipated.
older times. It’s better to use a proportional size in the ton goes below the Label and matches the Label’s width
AbsoluteLayout. To switch to proportional layout, use the and is positioned at the left edge of the button. The width
LayoutFlag attribute: of the RelativeLayout changes when the user rotates the
phone to landscape mode. The Label’s width needs to ad-
<AbsoluteLayout> just accordingly and the left position of the Button needs
to change too.
<BoxView
AbsoluteLayout.LayoutFlags=”All” A constraint can have the following values:
AbsoluteLayout.LayoutBounds=”90, 50, 75, 25”
BackgroundColor=”{x:Static c:Hues.Sky}” /> • ElementName: the name of the element that the
</AbsoluteLayout> constraint is relative to
• Type: whether the constraint is relative to the par-
This sets all four values in the LayoutBounds attribute to ent or another view
proportional size. Now the BoxView is 75% of the width • Property: which property on the relative element to
of the parent, instead of 75-pixels. It’s the same for the use for the constraint
other three values; for example, the top of the BowView • Factor: the multiplier for the constraint
is located at the halfway mark in the parent instead of • Constant: an offset for the constraint
50-pixels from the top.
Here’s the XAML for the Label:
The All flag sets each value in the bounding box to pro-
portional. There are other flags that switch on propor- <RelativeLayout
tional values for the other bounding box values: BackgroundColor=”{x:Static c:Hues.Sky}” >
<Label x:Name=”MainLabel” Text=”Example”
<AbsoluteLayout> BackgroundColor=”Black” FontSize=”24”
RelativeLayout.WidthConstraint=
<BoxView “{ConstraintExpression
AbsoluteLayout.LayoutFlags=”WidthProportional” Type=RelativeToParent,
AbsoluteLayout.LayoutBounds=”90, 50, 75, 25” Property=Width,
BackgroundColor=”{x:Static c:Hues.Sky}” /> Factor=0.9,
</AbsoluteLayout> Constant=0}”
RelativeLayout.XConstraint=
The WidthProportional flag sets the Width to a propor- “{ConstraintExpression
tional value and the other three values remain absolute. Type=RelativeToParent,
Check out the Xamarin documentation to see all the com- Property=X,
binations. Constant=20}” />

codemag.com Arranging Views with Xamarin.Forms Layouts 41


The Label has two constraints, WidthConstraint and XConstraint. “{ConstraintExpression
The Type=RelativeToParent parameter sets the constraint to the Type=RelativeToView,
parent RelativeLayout. The width of the Label is tied to the par- ElementName=MainLabel,
ent width with the Property=Width value and the Factor=0.9 Property=Y,
sets the Label width to 90% of the parent. The Property=X and Constant=40}”
Constant=20 values set the X Position of the Label. RelativeLayout.XConstraint=
“{ConstraintExpression
Here is the XAML for the Button: Type=RelativeToView,
ElementName=MainLabel,
<Button Text=”Do Work” Property=X,
RelativeLayout.YConstraint= Constant=0}” />

Note the use of Type=RelativeToView and Element


Name=MainLabel to set the YConstraint and XConstraint
to the MainLabel view. Next, set the Property=Y and Con-
stant=40 values to position the Button 40 pixels below
the Label. Also use the Property=X and Constant=0 val-
ues to keep the left edge of the Button aligned with the
left edge of the Label.

Figure 7 shows the RelativeLayout in action on the An-


droid emulator.

Figure 8 shows the same UI in landscape mode.

Conclusion
Generally speaking, the Xamarin layout views follow a
similar structure to other XAML frameworks. They’re de-
signed to work in a cross-platform situation, which re-
sults in some unfamiliar territory for XAML veterans. Each
layout solves a specific problem. Once you understand
how each one works, you’ll find yourself layering them
together to build the UI of your dreams.

Walt Ritscher

Figure 7: Label and Button and RelativeLayout

Figure 8: Label and Button and RelativeLayout in Landscape mode

42 Arranging Views with Xamarin.Forms Layouts codemag.com


ONLINE QUICK ID 1605081

Integrating ASP.NET MVC and


AngularJS
AngularJS took the Web development world by storm. Overnight, writing Single Page Applications (SPAs) was the hot new thing
and everyone wanted to do it. Most people set out to learn via books, blogs, and video courses, but there’s one problem with
that. Angular is a Google product and has no dependency on the Microsoft stack. I’m not saying this as a negative statement,

it’s just a fact. Most training uses other editors and teach- The Single Layout Shell (w/o ASP.NET)
es you how to use HTML and JavaScript (Angular), period. I’m going to start by explaining and illustrating a tra-
But many of us are Microsoft developers and have a lot ditional Angular SPA. Keep in mind that I won’t be ex-
invested in the Microsoft stack, so we shouldn’t have to plaining what views and view-models are or how MVVM
turn away from it in order to jump on the Angular band- binding works. I’ll be assuming that anyone reading this
wagon. has Angular knowledge already, and later I’ll be making
the same assumption about ASP.NET MVC skills. By start-
If you start to look into typical Angular training, you’ll ing with a single layout SPA, and then building on my
Miguel Castro learn how to ditch Visual Studio, learn Web Storm and examples to show you how to handle a more complex site
miguelcastro67@gmail.com Node, and dive head first into the world of HTML and Ja- with more than one layout, I’ll be able to describe the
@miguelcastro67 vaScript without many—if any—other dependencies or problems I’ll solve later when I introduce ASP.NET MVC
additional technologies. This isn’t totally bad because if into the mix.
Whether playing on the lo-
you’re going to learn something like Angular, you do need
cal Radio Shack’s TRS-80 or
to learn it in full and understand all its parts intimately. A typical Angular-based SPA has an HTML view that sets
designing systems for clients
This article is not about that. This article won’t teach you up the layout of the website and a template placehold-
around the globe, Miguel has
been writing software since he Angular from the ground up. There’s a lot of great mate- er noted by the ng-view directive. This HTML page also
was 12 years old. He insists rial, both printed and digital about Angular and how to needs to load up any necessary JavaScript file, including,
on staying heavily involved work with it. This article is about showing you how to but not limited to, the Angular framework itself, the site’s
and up-to-date on all aspects leverage your ASP.NET MVC skills together with your An- module, and all required view-models. What I call view-
of software application design gular skills in order to have your cake and eat it too. Not models are, in fact, what Angular refers to as controllers.
and development, and projects only will I show you how to integrate the two technolo- Listing 1 shows you a sample Angular shell view called
that diversify into the type gies into a hybrid app, but I’ll also teach you my design Index.html. Notice that it uses an Angular module called
of training and consulting he and organization style that I use everywhere I have to appMain along with an Angular view-model called index-
provides to his customers. build these kinds of applications, including file location ViewModel. I refer to the Index.html view as the “shell
He believes that it’s never choices and coding conventions that I hope you’ll also view” because its content defines the shell layout for this
just about understanding the find beneficial. simple SPA site.
technologies but how technolo-
gies work together. In fact, it’s
on this concept that Miguel
bases his Pluralsight courses. Leverage your ASP.NET MVC What I call view-models are,
Miguel has been a Microsoft skills together with your in fact, what Angular refers
MVP since 2005 and when he’s to as controllers.
Angular skills in order to have
not consulting or training, he
speaks at conferences around your cake and eat it too.
the world, practices combining
on-stage tech and comedy, and
never misses a Formula 1 race. The layout for this site is very simple. It consists of a
But best of all, he’s the proud The Traditional SPA heading provided by the variable headingCaption, a
horizontal line, and some content beneath it. The content
father of a very tech-savvy
12-year-old girl. Frameworks like Angular, Ember, Backbone, and even swapped into the ng-view directive comes from various
Knockout are used to build something that’s become HTML templates, each binding to their own view-model.
known as a Single Page Application, or SPA. IMHO, this is And of course, this is all configured in the module setup
one of the most misused and dangerous terms I’ve seen using Angular’s routing capability, as shown in Listing 2
come around in a long time. You see, the sad truth is that along with the indexViewModel view-model that’s bound
many people take the terms they hear very literally, and in to this layout view in its <html> tag.
this case, they set out to write a Web application that is
indeed one single page with just a lot of view templates Basic Routing
swapped in and out of a placeholder. If the term SPA is to Each one of the HTML templates displays not only content
be taken literally and we all set out to write our Web ap- but also links that route to other views. These links are
plications in this fashion, things start out nice, pretty, and intercepted by the routes defined in Listing 2 and the
simple at first, but as the application grows, all hell can appropriate view and view-model is brought together and
break loose. Why would I say something like that? Well, replaced as the content in the ng-view placeholder. The
because literal SPAs have some limitations and can grow first route in the routing definition shows what view and
to be hard to manage, especially in a team environment. view-model is used when the routing path is a simple “/”,

44 Integrating ASP.NET MVC and AngularJS codemag.com


meaning the root of the application. The views for the the initial browsing URL ({host}/Index.html), it runs
single-shell-layout app are shown in Listing 3 and the that route through the routing table. Because there’s no
rest of the view-models are in Listing 4. route that specifies that page, the otherwise clause is
hit and the route switches over to /customer. This not
Take a look at the first view in Listing 3, Home.html. As only loads the CustomerHome.html template and binds
you can see, it shows a heading variable and two simple it to the homeViewModel view-model, but it also has the
links to the routes /customer/list and /customer/detail. effect of changing the URL that appears on the browser
I’ll use the first link to describe what happens. This route bar to /customer. Without some additional help, I can’t
gets picked up by Angular and runs through the routing ta- “friendly-up” the URLs any further for that initial brows-
ble, and the result is the display of the CustomerList.html
view bound to the customerListViewModel view-model.
Listing 1: A simple Angular shell view
<html data-ng-app=”appMain” data-ng-controller=”indexViewModel”>
The ngRoute Angular module <head>
<title>{{ headingCaption }}</title>
is necessary for angular <link href=”Content/bootstrap.min.css” rel=”stylesheet” />
routing to function. </head>
<body>
<h2>{{ headingCaption }}</h2>
<hr />
It’s important to understand the order of operation here <div ng-view></div>
as it will become even more important in the next sec-
tion, and is crucial to understand when I begin involv- <script src=”Scripts/angular.min.js”></script>
ing ASP.NET MVC. The initial browsing must happen to <script src=”Scripts/angular-route.min.js”></script>
Index.html. Until this page loads, Angular hasn’t loaded <script src=”Scripts/App.js”></script>
and the routing tables haven’t been defined. Once this </body>
page is rendered, Angular takes over and remembering </html>

Listing 2: A simple Angular module and routes


var appMainModule = angular.module(‘appMain’, [‘ngRoute’]) });
.config(function ($routeProvider, $locationProvider) { $routeProvider.otherwise({ redirectTo: ‘/’ });
$routeProvider.when(‘/’, { $locationProvider.html5Mode({
templateUrl: ‘/Templates/Home.html’, enabled: true,
controller: ‘homeViewModel’ requireBase: false
}); });
$routeProvider.when(‘/customer/list’, { });
templateUrl: ‘/Templates/CustomerList.html’,
controller: ‘customerListViewModel’ appMainModule.controller(“indexViewModel”, function ($scope,
}); $http, $location) {
$routeProvider.when(‘/customer/detail’, { $scope.headingCaption = ‘Customer Maintenance’;
templateUrl: ‘/Templates/CustomerDetail.html’, });
controller: ‘customerDetailViewModel’

Listing 3: Views Single Shell Layout App


Home.html </thead>
<tbody ng-repeat=”p in people”>
<h2>{{ heading }}</h2> <tr>
<br /> <td>
<br /> <a href=”#” ng-click=”showPerson(p)”>select</a>
<a href=”/customer/list”>Go to customer list view</a> </td>
<br /> <td>{{ p.FirstName }}</td>
<a href=”/customer/detail”>Go to customer detail view</a> <td>{{ p.LastName }}</td>
</tr>
CustomerList.html </tbody>
</table>
<h3>{{ heading }}</h3> <br />
<br /> <br/>
<table class=”table table-hover”> <a href=”/customer/detail”>Go to customer detail view</a>
<thead>
<tr> CustomerDetail.html
<th></th>
<th>First Name</th> <h3>{{ heading }}</h3>
<th>Last Name</th> <br />
</tr> <a href=”/customer/list”>Go to customer list view</a>

codemag.com Integrating ASP.NET MVC and AngularJS 45


ing experience. There is no ASP.NET involved here at all, it’s also very possible for different site sections to have a
so the browsing is physically performed directly to the sort-of sub-theme within themselves. Perhaps you want the
Index.html page. Product section of the site to show some fixed information
on the left and the switchable content on the right, whereas
You can add as many views/view-models as you need to the Customer section is to show some fixed information
continue building this single-shell SPA application. Each on the right with the switchable content on the left. With
requires an entry in the module’s routing definition and the existing stack, you’re now forced to have multiple shell
each requires the shell view, Index.html, to load its nec- views. The challenge there is code-repetition and navigation.
essary JavaScript file. In the example, all of the view-mod-
els are contained in the App.js file that’s loaded by the First of all, I now need more than one shell view. Sec-
shell view, but remember that this file can grow and grow ondly, to navigate to that shell view, I need a server trip.
and grow as the application gets larger. The first drawback This isn’t a problem; I just need to know that the naviga-
here is that your user may never get to use some of the tion currently taking place with the anchor tags is being
JavaScript view-models because he never even gets to a routed by the client through the Angular routing engine.
particular view. In small apps, this may not be a problem, Obviously, this means it isn’t doing a server trip and any
but in larger ones, it can result to the unneeded loading view that’s loaded gets placed in the ng-view placehold-
of a lot of JavaScript that may never be used. er. This is not what I want if I need to do what will now
become a kind of cross-shell-view navigation.
This can easily become the case if the application grows
to a point where there are different sections, for example,
Customer, Product, and Order sections. The second drawback Multi-SPAs
is that this single-shell application is, in fact, a SPA in its What I’m really after here is two separate SPAs, if you
entirety. This means that I can add views for product- and or- will. One for the Customer section of my site and another
der-based information and their corresponding view-models, for the Product section. I’m after two separate sections
and all of them load into the existing ng-view directive that because the shell layout of each one will be different. If
you saw in the index.html file. This limits you to a single I make the Customer and Product sections both as part of
layout for the entire site. That sounds fine, except that now my original shell and add navigation information to the
we’re talking about multiple sections of the application. It’s Angular routing definition, I’m forced to share the visible
normal for a site as a whole to share a common theme, but layout as defined by my single shell view.

Listing 4: All other View-Models for Single Shell Layout App


appMainModule.controller(“homeViewModel”, function ($scope, { FirstName: ‘Kevin’, LastName: ‘Goff’ }
$http, $location) { ];
$scope.heading = ‘This is the Home view.’;
}); $scope.showPerson = function (person) {
alert(‘You selected ‘ + person.FirstName + ‘ ‘ +
appMainModule.controller(“customerListViewModel”, function ( person.LastName);
$scope, $http, $location) { }
$scope.heading = ‘Customer List View’; });

$scope.people = [ appMainModule.controller(“customerDetailViewModel”, function


{ FirstName: ‘Miguel’, LastName: ‘Castro’ }, $scope, $http, $location) {
{ FirstName: ‘Rod’, LastName: ‘Paddock’ }, $scope.heading = ‘Customer Detail View’;
{ FirstName: ‘Sahil’, LastName: ‘Malik’ }, });
{ FirstName: ‘John’, LastName: ‘Petersen’ },

Listing 5: CustomerIndex.html
<html data-ng-app=”appCustomer” data-ng-controller=”customerIndexViewModel”> <a href=”/ProductIndex.html” target=”_self”>
<head> Go to the product home page (link-based)
<title>{{ headingCaption }}</title> </a>
<link href=”Content/bootstrap.min.css” rel=”stylesheet” /> <br />
</head> <a href=”#” ng-click=”ProductHome()”>
<body> Go to the product home page
<h2>{{ headingCaption }}</h2> </a>
<hr /> </div>
<div class=”row”> <div class=”col-md-9”>
<div class=”col-md-3”> <div ng-view></div>
<a href=”/customer/list”> </div>
Go to customer list view </div>
</a>
<br /> <script src=”Scripts/angular.min.js”></script>
<a href=”/customer/detail”> <script src=”Scripts/angular-route.min.js”></script>
Go to customer detail view <script src=”Scripts/AppCustomer.js”></script>
</a> </body>
<br /> </html>

46 Integrating ASP.NET MVC and AngularJS codemag.com


codemag.com Title article 47
Listing 6: ProductIndex.html
<html data-ng-app=”appProduct” data-ng-controller=”productIndexViewModel”> Go to product detail view
<head> </a>
<title>{{ headingCaption }}</title> <br />
<link href=”Content/bootstrap.min.css” rel=”stylesheet” /> <a href=”/CustomerIndex.html” target=”_self”>
</head> Go to the customer home page
<body> </a>
<h2>{{ headingCaption }}</h2> </div>
<hr /> </div>
<div class=”row”>
<div class=”col-md-3”> <script src=”Scripts/angular.min.js”></script>
<a href=”/product/list”> <script src=”Scripts/angular-route.min.js”></script>
Go to product list view <script src=”Scripts/AppProduct.js”></script>
</a> </body>
<br /> </html>
<a href=”/product/detail”>

Multiple Layouts CustomerIndex.html page, Angular bootstraps and the


Using raw HTML and AngularJS, I can break up my appli- modules and view-models are defined, along with the
cation into sections, each with its own shell layout. Each routing table. And, as in my first example, the original
section is, in effect, a SPA. What’s important to understand URL, {host}/CustomerIndex.html, is remembered by
here is that each section is rendered with a server trip, Angular. This means that when the page loads and the
just like the Index.html page in my previous example, and ng-view is encountered, Angular looks at the routing
everything housed within it is handled by the client. I’ve table to see what view/view-model needs to be loaded
set up two index pages, called CustomerIndex.html and into that placeholder. Because no route actually matches
ProductIndex.html and they can be found in Listing 5 and the CustomerIndex.html path, the “otherwise” clause is
Listing 6. Note that each of these represents a fully valid hit and the route switches over to “/customer”, loading
HTML page, complete with html, head, and body tags, and the CustomerHome.html template into the placeholder
each loads up the appropriate Script and Content files. as well as replacing the URL displaying in the browser bar.
Each of these two pages is also the container for the An-
gular ng-view directive, but notice that the layout slightly A rather negative side effect of my current routing defini-
varies. The Customer page has some navigation links on the tion is that if I load up CustomerIndex.html, letting it go
left, with the ng-view on the right. The Product page has through the process I described above, and then clicked
them reversed. I made the difference in layout simple for “refresh,” I’m presented with a 404 error. This is because
the sake of the article, but this could have just as well been Angular has changed the URL in the browser bar to the
a massive visual difference between Customer and Product one that matches the route it was able to process, in
sections, complete with images and everything. Navigation this case “/customer”. Hitting the refresh button causes
within and without of the current SPA occurs a little differ- a complete reload of that URL from the server. Because
ent, as I’ll explain soon. we’re not using ASP.NET, there’s nothing to handle the
route “/customer” and so a 404 is returned. This can be
Each of these shell views loads its own Angular module and fixed by adding a route to the routing definition.
set of view-models. The files that contain this JavaScript
are called AppCustomer.js and AppProduct.js. The rout- $routeProvider.when(‘/CustomerIndex.html’, {
ing table definitions for both sections vary in their URLs of templateUrl: ‘/Templates/CustomerHome.html’,
course. What is also very different from my first example is controller: ‘homeViewModel’
the URL path that renders the Home view, which is essen- });
tially the landing view for this SPA. In my first example, the
Index.html view came up as the root of the site. In this ex- Although this is an acceptable solution, because this
ample, I don’t really have a root of the site, though I most route is now found by Angular, it’s the route that displays
certainly could have, if needed. Instead, the Customer sec- in the browser bar. You can decide if this is good or bad.
tion’s landing view comes up if the path is “/customer”. It certainly isn’t a pretty URL, and it is, in fact, one of the
problems I’ll address with ASP.NET later.
$routeProvider.when(‘/customer’, {
templateUrl: ‘/Templates/CustomerHome.html’, As in my first example, you can click on links that are con-
controller: ‘homeViewModel’ figured to a route in their href attribute, and that route
}); will be parsed by Angular. However, to jump sections and
go out of the current SPA is a different story. Traditionally,
Similarly, the Product section’s landing view comes up if an href route is handled by Angular and the proper view
the path is “/product”. As I explained earlier, the initial template and view-model is loaded and displayed in the
browsing point is the shell view, either CustomerIndex. shell view’s ng-view placeholder. If I’m sitting somewhere
html or ProductIndex.html. It’s not until one of these in the Customer section and want to jump to somewhere
pages loads that Angular can take over and provide ad- in the Product section, I have to handle things a little
ditional routing help. This lack of URL friendliness is differently. My goal now becomes trying to route over to
one of the problems I’m going to address later when I {host}/ProductIndex.html from somewhere in the Cus-
introduce ASP.NET MVC into the mix. By browsing to the tomer section. Although it may seem that you can easily

48 Integrating ASP.NET MVC and AngularJS codemag.com


do this by simply adding another route to the Customer’s customerIndexViewModel is the view-model bound to
routing table, it can get a little complicated. Because I’m the shell view and logically sits above the ng-view direc-
sitting in the Customer section, it’s the appCustomer An- tive, thus sitting above any view-models bound to views
gular module that’s currently loaded, and thus its view- placed in the placeholder. View-models bound to views that
models. Adding a route definition for /ProductIndex.html render in the ng-view placeholder are considered nested
tells Angular that a view template and view-model needs view-models and have access to $scope variables set by
to be loaded from the current module and the view placed the view-model bound to the shell view. This is the case for
in the CustomerIndex.html’s ng-view placeholder. Now anything I place in the $scope variable in this view-model.
you see the problem. These two sections should be treat-
ed separately, as indeed, they’re separate SPAs. The rest of the appCustomer.js file is the same as I showed
you in Listing 4, when I discussed the single-shell app. It
If you look back at Listing 5, you’ll notice that the consists of the appCustomer Angular module with its routing
anchor-tags for the links differ a little. The first two are definitions, as well as all the same view-models that are in
customer-section-based and are routed easily by the cur- the single-shell-layout app. The rest of the Product section
rent routing table, as defined in the appCustomer Angu- is set up very similarly to the Customer section. It consists of
lar module. The other two links are designed to jump to the shell view that you’ve already seen, as well as the app-
the Product section by loading ProductIndex.html. What Product.js file that contains the appProduct Angular module,
makes the first link unique is the target attribute. routing definitions, and all view-models. The sidebar shows
you where you can download the complete set of projects.
<a href=”/ProductIndex.html” target=”_self”>
Go to the product home page
</a>
View-models bound to views
Without it, that route is handled by the currently loaded that render in the ng-view
Angular routing table and will, of course, fail. Proactively placeholder are considered
specifying a target causes the route to execute a full page-
load from the server, just as if you altered the browser bar
nested view-models and have
yourself and pressed enter. This starts the process from the access to $scope variables
very beginning, but loads up the ProductIndex.html page set by the view-model bound
instead, thereby loading its Angular module, defining its to the shell view
own routing table, and defining its own view-models.

The second link to the Product section demonstrates how


to accomplish this from the view-model. There are many Although the multi-shell approach I’ve taken here is quite
times that you need to execute code before navigating acceptable, notice that the two shell views do have some
somewhere. For these scenarios, you can simply tell the repetitive code. The navigation links and ng-view place-
link to call a function in the view-model. In this case, I’m holder are reversed in position and the rest of the view is
calling a function called ProductHome. This function is exactly the same. The header is the same, as is the load-
defined in the customerIndexViewModel like this: ing of the scripts. The exception is the AppCustomer.js
versus AppProduct.js scripts that load appropriately for
appCustomerModule.controller(“customerIndexViewModel”, each view. Common code can be extended to become a
function ($scope, $http, $location, $window) { full header and footer, site-map information, or anything
$scope.headingCaption = ‘Customer Maintenance’; you need to give your site a polished production look-
and-feel. In such a case, all that common markup needs
$scope.ProductHome = function () { to be duplicated in each shell view. Although I’m certain
// assume it’s a route in the current SPA that there are products or frameworks out there to help
//$location.path(‘/ProductIndex.html’); you accomplish this, you’re reading this because you’re
an ASP.NET developer, so why don’t I show you how to le-
// perform a full page-load verage what you already know and accomplish this easily?
$window.location.href = ‘/ProductIndex.html’;
}
}); The ASP.NET MVC/Angular Hybrid App
I know I’ve said this previously, but I still can’t help but
The two techniques you see are the equivalent of an an- be amazed at how many developers see AngularJS applica-
chor tag with or without a specified target attribute. The tions and ASP.NET MVC applications as two different things.
one that’s commented out looks for the route within the Yes, they are two different technologies, but I think there
current SPA and is handled by the currently loaded rout- is too much of an “our way or their way” mentality in Web
ing table. This is the procedural equivalent to a standard development. Our way, meaning with the Microsoft stack,
<a> link WITHOUT a target attribute. The second one, and their way meaning without. Coming from a Web Forms
which is the active code, performs a full page-load. Notice background, it took me a while to get on the MVC bandwag-
that each of these depends on an Angular service, $loca- on, but once I did, I never looked back. Having said that, I
tion or $window, which I inject into the view-model. rarely develop an application in the conventional ASP.NET
MVC fashion. By conventional, I mean using MVC control-
A nice benefit of where I decided to place the Produc- lers for Gets and Posts, and using Razor with HTML Helpers
tHome function is that it’s available to all the view-models for all of my form rendering. This was great when it came
loaded by the appCustomer module. This is because the out, but we have so many better ways to do it now! Again,

codemag.com Integrating ASP.NET MVC and AngularJS 49


I never looked back. ASP.NET MVC remains a fantastic de- NET MVC site and renders one or more views using an MVC
livery platform for HTML, and JavaScript for that matter. controller and action as any other MVC app. Primary site
That statement is key in my integration of MVC and Angular, navigation is defined in the Layout page and uses the MVC
because it’s in that capacity that I will concentrate next. routing engine to route to other MVC views. These views
constitute the root of each site section. Note that previ-
Overview ously, a site section was an entire HTML page, each with
The overall architecture of this Hybrid App, as I’m call- repeated static content. The root view of each section
ing it, is quite simple and is displayed in Figure 1 and is considered the root of a SPA and renders everything
Figure 2. The Web application itself is, of course, an ASP. that SPA needs, and provide the layout for that SPA. In

Figure 1: Architecture of the Web Application

Figure 2: Structure of a SPA Silo

50 Integrating ASP.NET MVC and AngularJS codemag.com


Listing 7: The ASP.NET MVC Layout View
<!DOCTYPE html> “Product”,
<html> “Home”)</li>
<head> <li>@Html.ActionLink(“Orders”,
<meta charset=”utf-8” /> “Order”,
<meta name=”viewport” “Home”)</li>
content=”width=device-width, initial-scale=1.0”> </ul>
<title>@ViewBag.Title - ASP.NET MVC with Angular JS</title> </div>
@Styles.Render(“~/Content/css”) </div>
@Scripts.Render(“~/bundles/modernizr”) </div>
</head> <div class=”container body-content”>
<body data-ng-app=”main”> @RenderBody()
<div class=”navbar navbar-inverse navbar-fixed-top”> <hr />
<div class=”container”> <footer>
<div class=”navbar-header”> <p>&copy; @DateTime.Now.Year</p>
<button type=”button” class=”navbar-toggle” </footer>
data-toggle=”collapse” </div>
data-target=”.navbar-collapse”>
<span class=”icon-bar”></span> @Scripts.Render(“~/bundles/angular”)
<span class=”icon-bar”></span> @Scripts.Render(“~/bundles/jquery”)
<span class=”icon-bar”></span> @Scripts.Render(“~/bundles/bootstrap”)
</button> <script type=”text/javascript”>
@Html.ActionLink(“ASP.NET MVC/Angular JS”, window.MyApp = {};
“Index”, “Home”, MyApp.rootPath = ‘@Url.Content(“~”)’;
new { area = “” }, </script>
new { @class = “navbar-brand” }) <script src=”~/App/Validator.js”></script>
</div> <script src=”~/App/App.js”></script>
<div class=”navbar-collapse collapse”> @RenderSection(“scripts”, required: false)
<ul class=”nav navbar-nav”> <script type=”text/javascript”>
<li>@Html.ActionLink(“Customers”, @RenderSection(“jsCode”, required: false)
“Customer”, </script>
“Home”)</li> </body>
<li>@Html.ActionLink(“Products”, </html>

the previous examples, I referred to these views as shell Layout page. This pattern isn’t new and is core to any ASP.
views. This layout is rendered within the layout defined NET MVC application. The Layout page sets up the com-
for the site as a whole in the MVC Layout page. This is il- mon look and feel for the entire application. This means
lustrated in Figure 1. Once in a site section, we’re inside that it needs to define the static content that resides out-
a SPA and, for the most part, everything is the same as side of each SPA section. The Layout page in its entirety
the previous SPA examples I’ve shown you. I’ll go through can be seen in Listing 7. I refer to each SPA section as a
the order of operation starting with what is now the pri- SPA Silo, a term coined by my friend, author Brian Noyes.
mary shell of the entire Web application, the Layout page. Navigation links on the Layout page route to a conven-
tional MVC controller action, as in any other ASP.NET MVC
The Layout Page application.
In the previous example, I demonstrated how to set up
an application with two sections, each being its own SPA <ul class=”nav navbar-nav”>
and each having its separate Angular module, views, and <li>
view-models. However, you might recall that I was forced @Html.ActionLink(“Customers”,
to repeat some code in each of the shell views. Now I’ll “Customer”, “Home”)
work in an ASP.NET MVC application with Web API servic- </li>
es. This is a standard choice when creating a Web project <li>
in Visual Studio. My project will also have the AngularJS @Html.ActionLink(“Products”,
and Bootstrap NuGet packages installed. “Product”, “Home”)
</li>
I won’t be making any adjustments to the Global.asax or </ul>
the Web.config in the interest of simplicity, but if you use
my techniques, you’re free to add anything you need to The body of the Layout page can look however you want
your Web application, including a DI container, custom fil- and contain any static content you need. The placeholder
ters, or anything else. As in the prior example, this site will for the actual SPA Silo that makes up the section of the
have a Customer section and a Product section. The code site is a standard ASP.NET MVC RenderBody statement.
download that accompanies this article also includes an Or-
der section but in the interest of space, I won’t be covering <div class=”container body-content”>
it in the article. @RenderBody()
<hr />
The shell views, as I described them before, still exist, but <footer>
as CSHTML views. These views start by sharing a common <p>&copy; @DateTime.Now.Year</p>

codemag.com Integrating ASP.NET MVC and AngularJS 51


</footer> <script> tags needed for that SPA Silo. Remember, this
</div> view constitutes the Root View of that SPA Silo, similar
to the shell views in the previous example, but one level
The bottom of the Layout page adds any scripts that are beneath the primary Layout page, which is now the site’s
to be common to the entire application. This is one of main shell. The second section is called jsCode and re-
the items that I needed to repeat in each shell view in sides inside <script> tags, so the code contained in that
the previous example. Here, I only need to add it once section is raw JavaScript. Later, when views are rendered
in the Layout view. What I won’t be adding in this view by the RenderBody statement, whatever is placed in the
are the Angular modules and view-models used by each scripts and jsCode sections is rendered in these place-
SPA Silo. holders of the Layout view.

@Scripts.Render(“~/bundles/angular”) If you look at the complete Layout page code in List-


@Scripts.Render(“~/bundles/jquery”) ing 7, you may notice that I’m bootstrapping an Angular
Scripts.Render(“~/bundles/bootstrap”) module called main in the <body> tag.

Next, I want a set of a global variables that contains the <body data-ng-app=”main”>
root URL to this application. This makes it easy to de-
ploy anywhere later without worrying about what the root This module is the only Angular module bootstrapped de-
address is. This problem rears its ugly head quite a bit claratively. Angular doesn’t allow more than one module
when you’re developing applications on your localhost to be assigned using data-ng-app, but it doesn’t mean
using a virtual directory, and then deploy to an actual that only one module is allowed. Later, you’ll see that
website where your applications sit at the root level. In this is the reason for the aforementioned jsCode section
many situations, you may need to refer to the root path of the Layout page. Also, if I wanted, I could also as-
of the application and having this variable handy makes sign an Angular view-model to the Layout page using the
that much easier. data-ng-controller directive. This gives my Layout page
the ability to benefit from binding to $scope variables
<script type=”text/javascript”> like any other Angular view. I’ve chosen, however, to keep
window.MyApp = {}; the Layout page simple and limit it to providing the static
MyApp.rootPath = ‘@Url.Content(“~”)’; shell layout design for the site and a place to put site-
</script> section navigation links, as I’ve already shown you. This
does bring me to the main Angular module. Because this
The root path of the application is easily obtained at the module is assigned here in the Layout page, the script file
server, so combining Razor syntax here with JavaScript that contains its definition is here as well. This is the App.
will work nicely. Remember, this view is being parsed and js file you saw earlier.
rendered by ASP.NET, so I’m free to include and leverage
any server-side power that I want. The creation of the The Site-Wide App.js and Index.cshtml View
MyApp namespace is so not to pollute JavaScript’s global Following the regular ASP.NET MVC order of operations,
namespace and avoid any potential conflict—although running my site would use the default MVC route {con-
the possibility of a conflict is minimal. troller}/{action}/{id}, and thus seek out a controller
class called HomeController and an action called Index.
Now I need to load up any additional scripts that the en- It’s entirely up to me to maintain this pattern or change it
tire site will use. to a different default route or a different default view. To
keep things simple, I’m maintaining the default pattern
<script src=”~/App/App.js”></script> and going with a default view called Index.cshtml.

The App.js file contains JavaScript code that’s available The App.js file I recently mentioned is used to contain
and leveraged to the entire application, meaning all SPA code used by the entire site, hence its declaration in the
Silos. I’ll go over its design and contents in detail later. Layout page. The location of this file is a folder called
Notice that this file resides in the App folder. This folder App. This is the pattern I’ve chosen for my MVC applica-
contains all of the Angular-related code for the entire ap- tion. The App folder itself contains this JavaScript file and
plication. You’ll see other App.js files in this same Web any others that are used by the site. Later, you’ll see the
application later, but their locations will be very different. sub-folder structure I’ll add in the App folder. This file
declares two modules that are very important. The first
The last two parts of the Layout page are code section Angular module declared is called common.
definitions. This is a feature that’s been used by traditional
MVC applications to render HTML code-parts but can also var commonModule =
be used for scripts. I’ve added two sections, both non- angular.module(‘common’, [‘ngRoute’]);
required.
This module won’t be attached to any view directly. I
@RenderSection(“scripts”, required: false) use it as a place to hang shared services from and also
<script type=”text/javascript”> as a place to inherit other modules from, as in this case,
@RenderSection(“jsCode”, required: false) ngRoute. You might have noticed the ngRoute module
</script> in previous code examples. It’s declared in the Angular
script and is necessary for routing to function properly.
The first, called scripts, will be used by the view that gets Adding other Angular services to my site will become
rendered by the RenderBody statement to contain any easier now, because I just need to add them to the in-

52 Integrating ASP.NET MVC and AngularJS codemag.com


Listing 8: Index.cshtml
@{ <p>AngularJS is the leading JavaScript-based client
ViewBag.Title = “Integrating ASP.NET MVC and AngularJS”; framework for web development.</p>
} <p>ASP.NET MVC remains Microsoft’s prefered web
<div data-ng-controller =”indexViewModel”> development framework and HTML delivery platform</p>
<div class=”jumbotron”> <p>
<h1>{{ topic }}</h1> When combined, these two platforms can build rich
<h2>Author: <b>{{ author }}</b></h2> web applications while maintaning great code
<p class=”lead”>This site brings together two great manageability as well as offer great
platforms for web development.</p> server-side support.
</div> </p>
</div>
<div class=”row”> </div>
<div class=”col-md-8”> </div>

heritance array in the common module declaration. The above syntax, the name of the module as attached to the
App.js file also declares a shared service called view- Layout page is main, but the variable that represents the
ModelHelper. Its contents are beyond the scope of this module for procedural code is mainModule.
article, but it’s included in its entirety with the accom-
panying code download. I declare the viewModelHelper The Index.cshtml view that comes up by default (based
service by using the factory method from the common on the default MVC route) when the site runs is bound
module. to an Angular view-model called indexViewModel. This
view-model is also declared in this App.js file and it
commonModule.factory(‘viewModelHelper’, hangs off of the main module.
function ($http, $q, $window, $location) {
return MyApp.viewModelHelper( mainModule.controller(“indexViewModel”,
$http, $q, $window, $location); function (
}); $scope, $http, $q, $routeParams, $window,
$location, viewModelHelper) {
Then, I simply create the viewModelHelper function.
var self = this;
(function (myApp) {
var viewModelHelper = function ( $scope.topic =
$http, $q, $window, $location) { “Integrating ASP.NET MVC and AngularJS”;
$scope.author = “Miguel A. Castro”;
var self = this; });

// function members go here In the case of this view, the currently bootstrapped An-
gular module is main because it was attached in the
Layout page. The services I’m injecting into this view-
return this; model are the common ones that I inject into all my
}; view-models, although I’m not really using any of them
myApp.viewModelHelper = viewModelHelper; here except $scope. Notice the injection of the view-
}(window.MyApp)); ModelHelper service as well. The Index.cshtml view can
be seen in Listing 8, where you can see me use the
Notice that I’m using the myApp namespace I declared topic and author variables as they are declared in the
back in the Layout page. As I stated earlier, this is to view-model.
avoid polluting the global namespace.
Clicking on the site heading of the Layout page routes you
Having the common module makes it easy for the main to the Index.cshtml view from anywhere in the site in
module and all other Angular modules going forward to the conventional MVC fashion. Clicking on any of the links
inherit functionality that I need across the entire site, be- for Customer or Product calls upon the Home Control-
cause all they have to inherit from in order to gain such ler’s Customer or Product action methods. These actions
functionality is the common module. The declaration of are designed to render the Customer.cshtml or Product.
the main module does just that. cshtml MVC views respectively. These views are the root
views for the Customer and Product SPA Silos.
var mainModule = angular.module(
‘main’, [‘common’]); The SPA Root Views
The standard MVC route {controller}/{action}/{id} al-
This module is attached to the Layout page’s <body> tag, lows me to route to Home/Customer or Home/Product
as you saw earlier, and because it inherits from the com- and get to the Customer.cshtml and Product.cshtml
mon module, it also inherits from the ngRoute module views. Later, I’ll alter these routes, but for now, I’ll con-
and the declaration of the viewModelHelper shared ser- tinue based on the fact that it was the default route
vice. Using this service in a controller now is as easy as table entry that got me to these views. For the purposes
injecting it by using its name. Note that, as noted in the of the example going forward, I’ll stick to the Customer

codemag.com Integrating ASP.NET MVC and AngularJS 53


section, but the Product section will be set up exactly
the same way.

The Customer.cshtml view is the “root” of the Customer


SPA Silo. The primary goal for this view is similar to the
shell views in the first examples I went over when de-
scribing more traditional SPAs. It sets up the layout for
this section of the website and loads up any necessary
scripts. The main difference between this and the shell
views is that this is the root of the Customer section and
it is, in its entirety, rendered inside the Layout page by
the RenderBody statement. This is where you see a huge
benefit of using ASP.NET MVC as the primary delivery
mechanism. I can have site-wide layout and site-wide
scripts, and also section-wide layouts and section-wide
scripts. For this difference, I refer to Customer.cshtml
as a root view.

Because this view is the root view for a SPA Silo, the Cus-
tomer SPA Silo, it uses a separate Angular module along
with its own set of Angular view-models. The JavaScript
files that contain all of this information are loaded in the
scripts section of this view. Remember, this view is loaded
by ASP.NET MVC, meaning that I have all the power of the
server-side Razor engine at my disposal. The scripts sec- Figure 3: Hybrid App Folder Structure
tion is combined with the Layout page where the section
was defined.
SPA Silo, and a Views folder that contains the HTML
@section scripts { templates. The files in these two folders have a one-to-
<script src=”~/App/Customer/App.js”> one correspondence with one another and their naming
</script> differs only in their suffixes, ViewModel and View. Ad-
<script src=”~/App/Customer/ViewModels/ ditional sub-folders can include scripts and content as
RootViewModel.js”> well. Given this convention, my site’s App folder looks
</script> like Figure 3.
<script src=”~/App/Customer/ViewModels/
CustomerHomeViewModel.js”> In reference to the recent code-snippet, where I show
</script> you the “scripts” section, notice that I’m loading four
<script src=”~/App/Customer/ViewModels/ view-models. The one declared in the RootViewModel.
CustomerListViewModel.js”> js file is the view-model that applies to this root view.
</script>
<script src=”~/App/Customer/ViewModels/ This view needs to bind to its own Angular module. The
CustomerViewModel.js”> reason for this is primarily to isolate the view-models,
</script> services, and routes that will be handled within this
} section. It also makes things much more manageable.
The module, to be called customer, cannot however be
You may recall me mentioning that there will be other attached using data-ng-app. That directive can only
App.js files later. You can see one here, but notice its be used once per current rendering, and if you recall,
location. This is key to the naming convention I use. I used it in the <body> tag of the Layout page to at-
Because I declared this to be the Customer section of tach the main module. I can, however, load and attach
my site, I have a Customer folder under the App folder. it procedurally, and that is what the jsCode script sec-
The App.js file in this folder accommodates everything tion is for.
for the Customer section only, whereas the App.js that
is one level up in the App folder accommodates all sec- @section jsCode {
tions. angular.bootstrap(
document.getElementById(“customer”),
The Customer folder under the App folder is an example [‘customer’]);
of the folder structure I use throughout my entire site. }
The sub-folders immediately beneath the App folder
each represent a site section. I use the same name as Here, I’m telling Angular to attach the customer module
the action method in the HomeController MVC control- (in the square brackets) to the element with the name
ler class that navigated me to this section. Under these customer (in the parentheses).
sub-folders, I have the SPA Silo’s App.js file, which I’ve
just described. I also have sub-folders for everything The body of the view is wrapped in a div tag marked with
else that deals with this particular SPA Silo. These sub- the Angular ng-non-bindable directive.
folders include, but are not limited, to a ViewModels
folder that contains the Angular view-models for this <div ng-non-bindable>

54 Integrating ASP.NET MVC and AngularJS codemag.com


By definition, this tells Angular to ignore the contents
of the div tag. In reality, what it’s telling it is to ignore
what’s been set up for Angular before this. I’m referring
to the main module that was bootstrapped by the Layout
page. This allows another module to be attached without
confusing the system. I’ll identify the next div tag down
with the name customer, performing the procedural
bootstrapping that I showed you earlier.

<div id=”customer”
data-ng-controller=”rootViewModel”>

I’m also binding this tag and all its content to the root-
ViewModel Angular view-model.

The rest of the view is made of HTML markup in combina-


tion with Angular directives and bindings. It draws the
layout for the Customer section and provides any state
and behavior that will be used throughout the entire sec-
tion. The area to be used to swap inner views around is
handled, of course, by the ng-view directive. The body of SPONSORED SIDEBAR:
this view in its entirety can be seen in Listing 9. Notice
the link to take me to the Products section. It has the ad- CODE Framework:
ditional attribute target, as I described earlier in this ar- Free, Open Source,
ticle. This forces the link to go to the server, thus turning and Fully Supported
the process back over to ASP.NET MVC. Later I’ll explain
why this route is /product and not the /home/product CODE Framework consists of
that the default MVC route table entry requires. Every- various components and tools
thing in the body of this view is bindable to any $scope that help developers with
exposed by the rootViewModel Angular view-model that’s common aspects of business
application development;
declared in the App.js file located in the App/Customer
such as simplified SOA
folder. The contents of this file, in conjunction with the
development with various
other view-models loaded by this root view, along with
clients, WPF development,
the Customer.cshtml root view itself, make up the Cus- data access, and much
tomer SPA Silo as illustrated back in Figure 2. more. Best of all, the CODE
Framework is completely
A SPA Silo free and open source with
The Customer SPA Silo is where a user finds anything to no strings attached! This
do with managing customer information. The root view, framework is supported with
Customer.cshtml, designs the layout and provides the periodic feature updates.
ng-view placeholder for every sub-view to be contained Email info@eps-software.com
within. The rootViewModel Angular view-model is bound with any questions; we’ll never
to the root view, as previously described, and that view- charge you for answering
model is created from the customer Angular module, also a few questions in email.
as previously described. The customer module is the first For those looking for more
construct contained in the Customer section’s App.js file. sophisticated and hands-
This module inherits from the aforementioned common on support, we also offer
module. premium support options.

var customerModule =
angular.module(‘customer’, [‘common’]);

This module also defines the routing tables to be used by


the Customer SPA Silo. Each route results in a view and
view-model combination to be placed in the root view’s
ng-view placeholder.

customerModule.config(function
($routeProvider,
$locationProvider) {
$routeProvider.when(‘/customer’, {
templateUrl: ‘/App/Customer/Views/
CustomerHomeView.html’,
controller: ‘customerHomeViewModel’
});
$routeProvider.when(‘/customer/list’, {

codemag.com Integrating ASP.NET MVC and AngularJS 55


templateUrl: ‘/App/Customer/Views/ $routeProvider.when(MyApp.rootPath +
CustomerListView.html’, ‘/customer’, {
controller: ‘customerListViewModel’ templateUrl: MyApp.rootPath +
}); ‘/App/Customer/Views/
$routeProvider.when(‘/customer/show/ CustomerHomeView.html’,
:customerId’, { controller: ‘customerHomeViewModel’
templateUrl: ‘/App/Customer/Views/ });
CustomerView.html’,
controller: ‘customerViewModel’ Now, no matter what my execution location is, I also have
}); the correct URL path.
$routeProvider.otherwise({
redirectTo: ‘/customer’ The Customer Silo’s App.js file also contains the declara-
}); tion of the customerService Angular service. This service
$locationProvider.html5Mode({ can be used to share state and behavior among all the
enabled: true, view-models bound to views that get placed in the ng-
requireBase: false view placeholder.
});
}); customerModule.factory(‘customerService’,
function ($http, $location,
Notice that each route starts with the path /customer. viewModelHelper) {
Also, notice the physical path to the view templates, / return MyApp.customerService($http,
App/Customer/Views. If you recall back in the root view’s $location, viewModelHelper);
scripts section, the location of the view-model files was });
/App/Customer/ViewModels. In my environment, I’ve
been running this project using IIS Express right in Vi- (function (myApp) {
sual Studio. I’ve found that if I set it up to run in full- var customerService = function ($http,
blown IIS, I sometimes run into that problem I previously $location,
described where it can’t find certain files when the path viewModelHelper) {
merely starts with /. This has to do with how I set up the
application to run in IIS, be it in an application or a virtual var self = this;
directory. To avoid this and any other confusion that may
occur during deployment, I can preface the URL path as // shared state and behavior can go here
well as the templateUrl path with MyApp.rootPath.

Listing 9: Body of the Customer.cshtml View


<div ng-non-bindable> </button>&nbsp;
<div id=”customer” data-ng-controller=”rootViewModel”> <input type=”text”
<h2>{{ pageHeading }}</h2> ng-model=”customerService.customerId” />
<div class=”row”> </div>
<div class=”col-md-4”> </div>
<button class=”btn btn-primary” <hr />
ng-click=”customerList()”> <div ng-view></div>
Customer List <hr />
</button> <div>
</div> <a href=”/product” target=”_self”>Products</a>
<div class=”col-md-4”> </div>
<button class=”btn btn-primary” </div>
ng-click=”showCustomer()”> </div>
Customer

Listing 10: Customer SPA Silo’s rootViewModel


customerModule.controller(“rootViewModel”, viewModelHelper.navigateTo(‘customer/list’);
function ($scope, customerService, $http, viewModelHelper) { }

$scope.viewModelHelper = viewModelHelper; $scope.showCustomer = function () {


$scope.customerService = customerService; if (customerService.customerId != 0) {
$scope.flags.shownFromList = false;
$scope.flags = { shownFromList: false }; viewModelHelper.navigateTo(
‘customer/show/’ + customerService.customerId);
var initialize = function () { }
$scope.pageHeading = “Customer Section”; }
}
initialize();
$scope.customerList = function () { });

56 Integrating ASP.NET MVC and AngularJS codemag.com


return this; default route pattern, this was /Home/Customer. Now that
}; the Angular module has loaded and an ng-view directive
myApp.customerService = customerService; has been found in the Customer.cshtml root view, Angular
}(window.MyApp)); will attempt to take that route and run it through the rout-
ing table that I declared into the customer module. If you
The rootViewModel view-model that’s loaded and bound look back at the code-snippet above that where I showed
to the Customer.cshtml root view is also contained in the the routing configuration, you’ll see that the route /Home/
App/Customer folder under the ViewModels sub-folder. Customer isn’t in the list. This means that the otherwise
Listing 10 shows this view-model in its entirety. I de- clause will be hit and the route will be changed to /custom-
clared it from the customer module, depicted by the cus- er. Again, Angular runs this through the list of configured
tomerModule variable, and am injecting into it not only routes and this time it finds it. The result is that it loads
some standard Angular services, but also the viewModel- the Home.html view from the App/Customer/Views folder
Helper service declared in the application-centric App.js and binds it to the customerHomeViewModel Angular view-
file and the customerService declared in the customer- model. This view-model was declared when the Customer-
section-centric App.js file. HomeViewModel.js script was loaded in the scripts MVC
section in the Customer.cshtml root view.
The contents of this view-model are specific to the Cus-
tomer.cshtml root view, so if you look again at Listing customerModule.controller(
9, you can reconcile the customerList() and showCus- “customerHomeViewModel”,
tomer() function calls with the functions declared in function ($scope, customerService,
Listing 10. The incoming services, viewModelHelper and viewModelHelper) {
customerService are given $scope assignments so that
their contents can be used in bindings by the view. $scope.viewModelHelper = viewModelHelper;
$scope.customerService = customerService;
$scope.viewModelHelper = viewModelHelper;
$scope.customerService = customerService;
var initialize = function () {
Also, remember that the rootViewModel’s $scope con-
tents are accessible by any view-models bound to views }
that get placed in the ng-view placeholder. I described
this nested view-model pattern earlier when I discussed initialize();
traditional SPAs. I’m not going to get into the imple- });
mentation details of what each of my view-models shows
or does, as it’s all standard Angular stuff that was a pre- The initialize pattern that you see is my standard for do-
requisite for this article. I will, however, bring attention ing things in all of my view-models. The view to which
to an example of how I’m using the viewModelHelper this view-model gets bound is very simple, as it doesn’t
service by calling the navigateTo method in order to contain anything special and neither does its view-model.
route me to another view/view-model within this SPA
Silo. <div>
<h3>Select an option using one of the
viewModelHelper.navigateTo(‘customer/list’); Customer buttons above</h3>
</div>
This method encapsulates a common way I call upon An-
gular’s $location.path command to perform the loading It’s very important to point out that, unlike the Custom-
of a new view. er.cshtml root view, you don’t see any data-ng-control-
ler directive here. This is because the connection between
self.navigateTo = function (path, params) { the view and the view-model is done by the routing table
if (params == null) entry itself.
$location.path(MyApp.rootPath + path);
else $routeProvider.when(‘/customer’, {
$location.path(MyApp.rootPath + path). templateUrl: ‘/App/Customer/Views/
search(params); CustomerHomeView.html’,
} controller: ‘customerHomeViewModel’
});
This is how all methods or variables are declared in the view-
ModelHelper service, or any other shared service for that mat- An alternative is to add a data-ng-controller directive to the
ter. If that service is injected into a view-model, as it in the div tag at the top of the CustomerHomeView.html view, but
case of rootViewModel, all of these members can be accessed. I need to completely omit it from the routing definition. If I
have both, the view-model loads twice and any code that’s
When the Customer.cshtml root view is rendered, it loads up immediately executed, such as the initialize function, will
the customer module and the rootViewModel view-model, be executed twice. Going forward, any functions called by
bootstraps the module to the view, and binds the view-model HTML elements in the view will also be called twice, and,
to the div tag with the data-ng-controller directive. When depending on what that function does, this can be danger-
the customer module is declared and its routing table con- ous for the application. It’s also very bad practice to simply
figured, Angular recalls the original URL that got it here to “let it go.” Although I can choose either of the two methods
begin with. Remember, sticking to the standard ASP MVC of attaching the view-model to the view, I prefer to omit the

codemag.com Integrating ASP.NET MVC and AngularJS 57


directive from the view and declare it in the routing defini- functions further in the future. However, the link to display
tion so it can be seen by the developer immediately. the customer list could have been handled entirely by the
<a> tag instead of leveraging an ng-click directive.
This now becomes the view and view-model combina-
tion that gets placed into the ng-view placeholder of the The result of each navigation attempt is another view/
Customer.cshtml root view upon first rendering this SPA view-model combination placed in the ng-view place-
Silo. A byproduct of this route shuffle is that the URL in holder of the Customer.cshtml root view. If such an at-
the browser bar now changes to {host}/customer. This tempt fails because the route isn’t found, the otherwise
can be a little misleading because the link that got me clause is invoked and the /customer route is handled.
to the Customer.cshtml view to begin with was {host}/
home/customer. I’ll show you how I plan to remedy this It’s important to understand the distinction of which
and more later, when I cover routing specifics. routing engine handles what. The routing I’ve just de-
scribed is handled by the Angular routing table, and each
SPA Silo (in this case, the Customer SPA Silo) is in charge
of defining and handling its own set of routes. The pro-
Contained views inside an cedural way of performing this kind of routing is through
ng-view should either bind the path method of the $location Angular service, which
their view-model through I wrapped in my viewModelHelper shared service. An an-
data-ng-controller or in the chor tag with a target=”_self” attribute on it will hit the
routing definition, but not both. server. If the server is hit, ASP.NET handles the request
first and the MVC routing engine is engaged first. This
brings me back to the link in the Customer.cshtml root
view that contained the route “/product”.
From this point on, it’s all about adding views and view-
models and providing navigation to them though links or <a href=”/product” target=”_self”>Products</a>
view-model functions. If you look back at the code for
Customer.cshtml, you’ll see that I declared two buttons. This link hits the server and thus invokes the ASP MVC
One was to show the customer list and the other was a routing engine. Remember so far, I’ve only been using the
specific customer, based on a bound value to a textbox. default route entry of {controller}/{action}/{id}, mean-
ing that the route should say /Home/Product/ or it will
<div class=”col-md-4”> fail. Also, what if I wanted to cross from this SPA Silo, not
<button class=”btn btn-primary” to the root view of the Product SPA Silo, but directly to
ng-click=”customerList()”> the list of products. Ideally this should be handled by a
Customer List link that jumps to the URL “/product/list”.
</button>
</div> <a href=”/product/list” target=”_self”>Product List</a>
<div class=”col-md-4”>
<button class=”btn btn-primary” In my current configuration, not only would the “/product”
ng-click=”showCustomer()”> link fail if I’m in the Customer SPA Silo, but so will the “/
Customer product/list” route. Both of these routes are defined in the
</button>&nbsp; product module of the App.js located in the /App/Product
<input type=”text” folder. Making the ASP.NET MVC routing engine and Angu-
ng-model=”customerService. lar routing engine play nicely together isn’t difficult but it
customerId” /> requires some adjustment on my part—or yours.
</div>
Dual Routing Engines
The two functions in the rootViewModel view-model navi- No website is production quality without proper route va-
gate to one of the other routes declared by the routing lidity and integrity. This means that once a route is visibly
configuration of the customer module in the SPA Silo’s made available to a user, it should be available from any
App.js file. part of the site. Today, you must consider the fact that us-
ers write URLs down to use later, or even more frequently,
$scope.customerList = function () { bookmark things. They also email and text URLs to others,
viewModelHelper.navigateTo(‘customer/list’); so it’s up to us as developers to ensure that any route they
} learn works with direct navigation as well as with a browser
refresh. Take, for example, the route “/product/list”. From
$scope.showCustomer = function () { what you’ve learned so far, this is a route handled by the
if (customerService.customerId != 0) { Angular routing configuration assigned in the product
$scope.flags.shownFromList = false; module of the Product.cshtml root view. But the problem
viewModelHelper.navigateTo( is that the “/product/list” route means nothing to ASP.
‘customer/show/’ + NET MVC. Again, from what you’ve seen so far, in order to
customerService.customerId); get to the Product SPA Silo, you need to route to “home/
} product” so you can hit the Home MVC controller and
} Product action. As it stands right now, a link in a customer
view that looks like this:
I chose to perform both navigations procedurally in the in-
terest of consistency and the possibility of enhancing the <a href=”/product/list” target=”_self”>Product List</a>

58 Integrating ASP.NET MVC and AngularJS codemag.com


will error out for two reasons. First, this route is not de- ration, and eventually finding the route and rendering the
fined in the Angular route definition of the customer mod- ProductListView.html template as well as binding it to
ule. And it cannot be added because the view and, more the productListViewModel view-model. Just don’t forget
specifically, the view-model that it needs, don’t belong that if a link like this is outside of the Product SPA Silo, it
to the customer module and haven’t even been script- must include the target=”_self” attribute. If it’s within
loaded. Secondly, the route isn’t specifically defined in the Product SPA Silo, it shouldn’t have that attribute. In
the MVC routing table either. In fact, it would have been fact, placing this attribute on a link in a view in the very
interpreted as needing to hit a controller class called Pro- SPA Silo to where you want the link to route causes an un-
ductController and an action method called List; neither necessary server trip. Not only that, by initiating a server
of which exist. trip, any state you were holding in a shared service such
as a productService Angular service will be lost because
Fixing this is easy and is done in the RouteConfig class in the HTTP request-response process starts from the top
the Web application’s App_Start folder. This is where the again.
default MVC route is declared.
Of course, it’s up to you to account for any page-order
routes.MapRoute( that you need to enforce in your application. This means
name: “Default”, that if a route gets a user to a specific view but there was
url: “{controller}/{action}/{id}”, a business prerequisite before that view is properly used,
defaults: new { you need to place logic in the view-model to either route-
controller = “Home”, away or signal other instructions to the user.
action = “Index”, Accompanying Download
id = UrlParameter.Optional }
); Conclusion You can download the complete
set of projects for this article at
So there you have it, the worlds of ASP.NET MVC and Angu-
www.melvicorp.com/uploads/...
This is where I need to make an addition for each SPA Silo. larJS working together, not only in harmony but benefiting
If you recall, the Home controller contains two actions in from each other’s strengths. You see no jamming square Although all are Visual Studio
addition to the Index action, Customer and Product. I’m pegs into round holes in this scenario. Each technology projects, the first three solution
going to add a route that looks like this: is used in the manner for which it was designed and in an folders have absolutely no
elegant fashion. The two technologies coexist nicely and dependency on .NET in any way.
routes.MapRoute( aren’t fighting each other in any way. It’s truly a match VS was used as the editor and
name: “customer”, made in heaven. to group the files together into
url: “customer/{*catch-all}”, projects for ease of transport.
defaults: new { The techniques I’ve used for integrating the two technol-
controller = “Home”, ogies don’t necessarily have to apply to Angular only. I’ve
action = “Customer” }); used the same design with ASP.NET MVC and Knockout,
and I have no reason to believe that it wouldn’t work with
This route will be used by any URL that starts with custom- Ember, Backbone, or any other JavaScript framework.
er, and routes it to the Customer action in the HomeCon-
troller controller class, just as if the route had said Home/ Make sure that you download the code that accompanies
Customer. The term catch-all can be anything you want, as this article from the information provided in the sidebar.
long as it has the asterisk (*) in front of it. This route allows It contains quite a bit more than what I was able to cover
me to call the URL customer/list right from the browser in this article, although it’s all extras that aren’t key to
bar. The result is the Customer.cshtml root view, which is the integration techniques I’ve illustrated.
what’s called from the HomeController class’ Customer ac-
tion. But, as I’ve stated several times, Angular remembers Miguel Castro
the original route called. Because getting to the Customer
root view loads up the Angular module and Customer SPA
Silo’s routing configuration, it then takes this original URL
of customer/list and routes it through the Angular routing
engine. When it does this, it finds the route and renders the
proper view and view-model in the ng-view placeholder of
the Customer.cshtml root view.

Each SPA Silo needs a similar MVC route entered into the
routing table.

routes.MapRoute(
name: “product”,
url: “product/{*catch-all}”,
defaults: new {
controller = “Home”,
action = “Product” });

Now, the /product/list link that I showed you earlier will


work just fine and route to the Product.cshtml root view
first, loading the product module and its routing configu-

codemag.com Integrating ASP.NET MVC and AngularJS 59


ONLINE QUICK ID 1605091

Implementing Lean Controllers


in iOS Applications
The Model View Controller (MVC) design pattern is no stranger to iOS developers. Every iOS application uses the MVC pattern
to distribute the responsibilities of the application flow. Unfortunately, most of the time, this distribution ends up with a
lot of code in the controllers of the application. These bloated controllers are responsible for creating technical debt and

also create maintenance nightmares for the future. In this details. The properties associated with the cell are as-
article, you will learn how to tame these monsters. I’ll signed inside the function. In the future, you might be
start with an app that consists of a massive controller and interested in displaying some additional properties on
work my way toward a leaner implementation. the user interface. This means that you’ll assign more
cell properties inside the cellForRowAtIndexPath func-
The basic principle behind lean controllers is the single tion, hence polluting it with unnecessary code, as indi-
responsibility principle. This means that every component cated in Listing 2.
of the application should have a single job and purpose.
By isolating each component to perform a single task, you
Mohammad Azam make sure that the code remains lean and easy to maintain.
The concepts and techniques
azamsharp@gmail.com
www.azamsharp.com learned in this article can be
@azamsharp Scenario applied to any iOS application
Mohammad Azam works as a
The iOS application under discussion is a simple user regardless of the data access
Senior Mobile Developer at task-management app. The application consists of a sin- layer used.
Blinds.com. He’s been develop- gle screen where the user can add tasks to a list. Users
ing iOS applications since can delete the tasks by swiping right to left on the row
2010 and has worked on more and then pressing the delete button. The user can mark
applications than he can the tasks as complete by selecting the cell using a single The best way to deal with this problem is to refactor the
remember. Azam’s current app, tap gesture. All of the tasks are persisted in the SQLITE configuration of the cell into a separate function. Luckily,
Vegetable Tree - Gardening database using the FMDB wrapper. The screenshots of the the TaskTableViewCell is a perfect candidate to define such
Guide, is considered the best app running in action is shown in Figure 1 and Figure 2. a function. The implementation of the configureCell func-
vegetable gardening app on the tion is shown here:
app store and was featured by In the first section, you’ll inspect the TasksTableViewCon-
Apple in 2013. He’s a frequent troller implementation, which orchestrates the complete func configure(task :Task) {
speaker at Houston Tech Fest flow of the application. You’ll quickly realize that the im-
and Houston iPhone Meetup. plemented code is not reusable and is hard to maintain. self.titleLabel.text = task.title
When not programming, Azam You’ll take the whole application apart and create reus- self.shortTitle.text = task.shortTitle
likes to spend his time with his able, single-responsibility components that protect the self.imageURL = task.imageURL
beautiful family and planning application for future changes. }
for his next trip to the unknown
corners of the world.
The configure function accepts a Task model object and
Implementing a Lean View Controller then populates the cell properties based on the prop-
The best place to start is the viewDidLoad event of the erties of the model. The next snippet shows the call to
TasksTableViewController. The viewDidLoad event is in- the configure function inside the cellForRowAtIndexPath
voked each time the app runs. Inside the viewDidLoad event.
event, you trigger the initializeDatabase function. The
initializeDatabase function is responsible for copying the override func tableView(tableView:
database from the application bundle to the documents UITableView, cellForRowAtIndexPath
directory of the application. Because this procedure indexPath: NSIndexPath)
needs to be performed only once for each app, there’s no -> UITableViewCell {
need to call it from the viewDidLoad event. You’re going
to move the initializeDatabase function into AppDelegate guard let cell = tableView.
where it can be called from within the didFinishLaunch- dequeueReusableCellWithIdentifier
ingWithOptions event. By moving the initializeDatabase (“TaskTableViewCell”, forIndexPath: indexPath)
call inside the didFinishLaunchingWithOptions, you’ve as? TaskTableViewCell else {
made sure that initializeDatabase is called only once dur- fatalError(“TaskCell not found”)
ing the lifecycle of the application. Listing 1 shows the }
implementation of the initializeDatabase function.
let task = self.tasks[indexPath.row]
Next, move to the cellForRowAtIndexPath function. At cell.configure(task)
first glance, the cellForRowAtIndexPath implementation return cell
doesn’t show any warning signs, but the devil’s in the }

60 Implementing Lean Controllers in iOS Applications codemag.com


Implementing TasksDatasource
In the current implementation, the data source is tied to
the TasksTableViewController. This means that if you have
to use the same data in a different controller, you have to
manually copy and paste the code into a new controller.
As a developer, you realize that copy/pasting is the root
of all evil and that it contributes to the technical debt.
Instead, you will refactor the data source into a separate
TasksDataSource class.

The TasksDataSource class implements the UITableView-


DataSource protocol. The TasksDataSource initializer con-
sists of the following parameters:

• cellIdentifier: A string instance representing the


UITableViewCell unique identifier
• items: An array of task instances
• tableView: The UITableView instance

The TasksDataSource class also provides the implementa-


tions for the cellForRowAtIndexPath and numberOfRow-
sInSection functions. Now, the TasksTableViewController
can call the setupTableView function from inside the view-
DidLoad event to initialize the TasksDataSource, as shown
in Listing 3.

Apart from eliminating the unnecessary code implement-


ed in TasksTableViewController, TasksDataSource also Figure 1: TODO app in action Figure 2: Entering new tasks in the TODO app

Listing 1: InitializeDatabase function to setup the database


func application(application: UIApplication, didFinishLaunchingWithOptions
launchOptions: let fileManager = NSFileManager.defaultManager()
[NSObject: AnyObject]?) -> Bool {
let success = fileManager.fileExistsAtPath(self.databasePath)
initializeDatabase()
guard let databasePathFromApp = NSBundle
return true .mainBundle().resourcePath?
} .stringByAppendingPathComponent
(self.databaseName) else {
return
private func initializeDatabase() { }

let documentPaths = print(self.databasePath)


NSSearchPathForDirectoriesInDomains
(NSSearchPathDirectory.DocumentDi if success {
rectory, NSSearchPathDomainMask.UserDomainMask, true) return
}
guard let documentDirectory = documentPaths.first else {
return } try! fileManager.copyItemAtPath(databasePathFromApp,
toPath: self.databasePath)
self.databasePath = documentDirectory
.stringByAppendingPathComponent }
(self.databaseName)

Listing 2: Cell properties assigned inside the cellForRowAtIndexPath function


override func tableView(tableView: UITableView, cellForRowAtIndexPath let task = self.tasks[indexPath.row]
indexPath: NSIndexPath) cell.titleLabel.text = task.title;
-> UITableViewCell { cell.subTitleLabel.text = task.subTitle;
// Future properties polluting code
guard let cell = tableView.dequeueReusableCellWithIdentifier cell.imageURL = task.imageURL
(“TaskTableViewCell”, forIndexPath: indexPath) // Future properties polluting code
as? TaskTableViewCell else {
fatalError(“TaskCell not found”) return cell
} }

codemag.com Implementing Lean Controllers in iOS Applications 61


helps to create a reusable data source that can be unit init() {
tested and used in different parts of the application.
var token :dispatch_once_t = 0
The setupTableView also exposes another problem related dispatch_once(&token) {
to data access. Currently, the data access code is littered let appDelegate = UIApplication.
throughout the TasksTableViewController, which not only sharedApplication().delegate
makes it harder to test but also harder to reuse and main- as! AppDelegate
tain. In the next section, you’ll refactor the data source into let databasePath = appDelegate
a separate service, which allows more flexibility in the future. .databasePath
self.db = FMDatabase(path: databasePath)
}
}
At first glance,
the cellForRowAtIndexPath Next, you’ll implement the GetAll function that will be
implementation doesn’t show responsible for retrieving all the tasks from the database.
any warning signs, but the The GetAll implementation is shown in Listing 4.
devil is in the details
The congested setupTableView function can be replaced
with the new leaner implementation, as shown in List-
ing 5.
Xcode Swift Refactoring Implementing TasksDataService
Support TasksDataService will be responsible for all of the CRUD You can apply the same approach to the save and delete
Unfortunately, at the time of this
(Create, Read, Update, Delete) operations related to the operations and move the implementations in the Tasks-
writing Xcode still doesn’t provide application. TasksDataService maintains the communica- DataService class. This eliminates a lot of code from the
any refactoring support for the tion bridge between the view controller and the persis- TasksTableViewController and moves you one step closer
Swift language. I’m sure that the tent storage system, which, in this case, is SQLite3. The toward Lean Controller implementation. In the next sec-
Xcode team is hard at work, but first step is to initialize the TasksDataService, which also tion, you’re going to look at the tableView delegate events
currently, refactoring tools are sets up the FMDatabase instance, as shown in the next and how they can be refactored into their own classes.
limited to Objective-C language. snippet.
One solution is to use AppCode Extending TasksTableViewController
from Jetbrains, which does provide var db :FMDatabase! Swift 2.0 introduced the concept of Protocol Extensions,
advanced refactoring tools. which allowed developers to provide default implementa-

Listing 3: Setting up UITableViewDataSource


func setupTableView() { }

// get the data from the database // close the connection


let db = FMDatabase(path: self.databasePath) defer {
db.close()
db.open() }

let result = db.executeQuery(“select * from tasks”, // initialize the data source


withArgumentsInArray: []) self.dataSource = TasksDataSource
(cellIdentifier: “TaskTableViewCell”, items:
while(result.next()) { self.tasks,tableView: self.tableView)
self.tableView.dataSource = self.dataSource
let task = Task(title: result.
stringForColumn(“title”)) self.tableView.reloadData()
// add to the collection }
self.tasks.append(task)

Listing 4: GetAll function to retrieve all tasks


func getAll() -> [Task] { // add to the collection
tasks.append(task)
var tasks = [Task]() }

db.open()
defer {
let result = db.executeQuery(“select * from tasks”, db.close()
withArgumentsInArray: []) }

while(result.next()) { return tasks

let task = Task(title: result.stringForColumn(“title”)) }

62 Implementing Lean Controllers in iOS Applications codemag.com


Listing 5: The setupTableView function utilizing the TasksDataService
func setupTableView() { “TaskTableViewCell”, items: self.tasks,
tableView: self.tableView)
self.tasksDataService = TasksDataService() self.tableView.dataSource = self.dataSource
self.tasks = self.tasksDataService.getAll()
self.tableView.reloadData()
// initialize the data source }
self.dataSource = TasksDataSource(cellIdentifier:

Listing 6: The didSelectRowAtIndexPath implementation inside the TasksTableViewController extension


override func tableView(tableView:
UITableView, didSelectRowAtIndexPath if(!task.isCompleted) {
indexPath: NSIndexPath) { cell.titleLabel.attributedText = task.title.strikeThrough()
task.isCompleted = true
let task = self.tasks[indexPath.row] } else {
cell.titleLabel.attributedText = task.title.removeStrikeThrough()
guard let cell = self.tableView. task.isCompleted = false
cellForRowAtIndexPath(indexPath) as? TaskTableViewCell else { }
fatalError(“Cell does not exist”)
} }

tions to protocol functions. Currently, the TasksTableView- completed and uncompleted tasks. The implementation is
Controller contains a lot of code that deals with the look shown in the following snippet. SPONSORED SIDEBAR:
and feel of the UITableView control. This includes the
Need Help?
implementations for didSelectRowAtIndexPath and com- func configure(task :Task) {
mitEditingStyle events. By providing an extension to the self.titleLabel.text = task.title Looking for help optimizing
TasksTableViewController, you can move a lot of clutter if(task.isCompleted) { your application architecture
from the TasksTableViewController class to the extension. self.titleLabel and design application? The
.attributedText = task.title.strikeThrough() experts at CODE Consulting
} else { are here to help with your
self.titleLabel project needs! CODE has a
FMDB is a thin Objective-C .attributedText = task.title.removeStrikeThrough() 20-Hour Introductory Service.
open source wrapper on } Get full access to a CODE
top of the SQLite database } team member for 20 hours
that provides a lot of helper to have them help you on
methods for performing Run the app again and now you’ll notice that the strike your project. Use this time for
through rows persists while scrolling the UITableView one-on-one mentoring, give
database operations from your project the push it needs
control!
within your applications. to get started, or anything in
between! Hours can be used
Conclusion consecutively or divided up
as needed.
The great thing about extending the TasksTableViewCon- Implementing lean controllers takes more effort than Email info@codemag.com
troller using protocol extensions is that it will have access writing massive controllers. It might be tempting to put to set up your time with a
to all of the properties defined in the TasksTableViewCon- all the code into one controller, but keep in mind that CODE specialist!
troller implementation. The implementation of the did- although you might move fast initially, you’ll quickly hit
SelectRowAtIndexPath defined inside the TasksTableView- a wall. It’s always better to refactor and move toward a
Controller extension is shown in Listing 6. more solid design initially when things are in motion,
rather than waiting until the components have been fixed
You’ll also notice that I’ve used an extension method for into place.
String type to create the strikeThrough effect. This allows
you to reuse the strikeThrough function in other parts of Mohammad Azam
the application.

Run the application. On the surface, everything looks


fine, but as you strikeThrough the top rows and scroll to
the UITableView to the bottom, you’ll notice that that
your strikeThrough rows are reverted to the default style.
The reason is pretty simple: UITableView reuses the cells
that it displays. This helps to increase the performance
dramatically, as new cells are never created.

In order to fix this issue, you need to edit the configure


function of the TaskTableViewCell to include the logic for

codemag.com Implementing Lean Controllers in iOS Applications 63


ONLINE QUICK ID 1605111

SQL Server Reporting Services:


Eight Power Tips
SQL Server Reporting Services (SSRS) has come a long way since the initial release of SSRS in SQL Server 2000. Early on,
many developers and technology managers viewed SSRS as an average report writer that lacked functionality and scalability
compared to other established reporting solutions. Fortunately, Microsoft greatly enhanced the SSRS feature set over

the last eight years (from SSRS 2008 to the present)- been writing articles as test or interview questions, and
thereby empowering SSRS advocates to make a stronger this article will also diverge in that I’m only covering the
and more compelling case that SSRS is indeed a prime- following eight items:
time player in the world of business reporting. In this ar-
ticle, I’ll demonstrate some tips and reusable approaches 1. Implementing column level security in reports
in different areas of report authoring/generation that 2. Implementing drilldown functionality with options
help make that case. to set initial drilldown
3. Creating cross-chart filter refresh effects
4. Repeating column headings across multiple pages
Kevin S. Goff SQL Server Reporting Services: 5. Dealing with page margins and blank extra pages
kgoff@kevinsgoff.net The Ultimate Bread and Butter 6. Relating multiple tables in a report
http://www.KevinSGoff.net of Reporting Tools 7. Implementing a nested “Page X of Y” on a report
@KevinSGoff Recently, I heard someone say, “Third-party report and 8. Implementing Running Aggregations in a report
charting tools might have many bells and whistles, but
Kevin S. Goff is a Microsoft SQL
Server MVP. He is a database SQL Server Reporting Services is still the bread and butter I’ll present many of these tips by saying, “You want to im-
architect/developer/speaker/ for many developers.” plement functionality/behavior ABC, but you’re running
author, and has been writing into a limitation. Is there a solution or workaround?” This
for CODE Magazine since 2004. From the late 1990s to 2007, I was a die-hard Crystal reflects many scenarios that I encounter in my consulting
He’s a frequent speaker at Reports fanatic and published a book on Crystal Reports practice.
community events in the mid- development with .NET. Toward the end of that period, I
Atlantic region and also speaks took a serious look at SQL Server Reporting Services 2005 Tip #1: Implementing Column-Level Security in Reports
regularly for the VS Live/Live (I’ll use the acronym SSRS for the rest of this article). I Suppose you build a report that both regular users and
360 Conference brand. He cre- concluded that SSRS 2005 was a good but not outstand- executives will view. In addition to other data, the report
ates custom webcasts on SQL/ ing product, and lacked functionality compared to Crystal contains cost and profitability measures that only execu-
BI topics on his website. Reports. That changed in SSRS 2008. Microsoft didn’t try tives should see. The regular users should only see speci-
to match every single bell and whistle of Crystal Reports fied data and the space for the cost columns shouldn’t
in SSRS 2008; instead, they expanded their existing re- appear. Users should see the report as if the cost and
porting (and charting) functionality on their own terms, financial measures never existed. Does SSRS provide secu-
and greatly improved the scalability and performance of rity features to hide columns based on domain accounts/
the reporting engine. groups?

So instead of adding the bells and whistles, Microsoft The answer is that SSRS doesn’t provide any built-in func-
fortified their bread and butter. Although Crystal Reports tionality to address column-level security. However, just
still had an edge on the total number of features, SSRS like many developer products, SSRS doesn’t stand in your
2008 became a truly viable option for internal business way from manually implementing such functionality.
reporting. Microsoft continued to expand SSRS in SSRS
2008R2, and has given certain UI areas of the product
a much-needed make-over in the upcoming SQL Server
2016 release. Just like many developer
products, SSRS doesn’t stand
Still, SSRS suffers from a bit of a perception issue. To in your way from manually
many, SSRS remains merely adequate, but lacks some of implementing column-level
the power found in third-party tools, competing products, security functionality.
and even the quasi-reporting capabilities in Excel. One of
my roles as a consultant is to show developers and manag-
ers the full power of SSRS and how experienced developers
can extend it. Several of the tips in this article reflect those I’ll keep the example very simple and will focus on the
exercises to demonstrate the power of the product. mechanics. Figure 1 shows a very basic report, with a
column (“Modified Date”) that you want to configure for
visibility based on the current user.
What’s on the Menu?
For over a decade, I’ve been using the Baker’s Dozen You can implement this in five steps. Essentially, you’ll
theme of giving you 13 tips. In the last year, I’ve even create a SQL Server table to define user/column visibility,

64 SQL Server Reporting Services: Eight Power Tips codemag.com


and a stored procedure to return that information for the the engine shows the report as if the ModifiedDate col-
current authenticated user. In the SSRS report, you’ll read umn never existed. This makes the output appear clean
this information into a hidden/internal SSRS parameter, for either scenario.
and tap into the SSRS column visibility feature to show/
hide the column based on the SSRS parameter.

Step 1: Create a database table in SQL Server called dbo.


RightsToColumns. For simplicity, add a single row for the
user domain account name and a flag for whether to see
the Modified Date column (Figure 2).

Step 2: Create a basic stored procedure to return the


table information for a specific User ID based on a param-
eter that the report will ultimately supply.

CREATE PROCEDURE [dbo].[GetRightstocolumns]


@UserID varchar(100)
as
select * from RightsToColumns
where UserID = @UserID

Step 3: In the report, create a dataset that reads the


stored procedure based on the current authenticated user Figure 1: An SSRS report with a column that you only want certain users to see
that SSRS recognizes. Figure 3 shows mapping the SSRS
Globals variable called User!UserID to the SSRS stored
procedure parameter of the same core name (@UserID).
When the report executes, SSRS calls the procedure and
pass in the current authenticated user as the parameter.
Figure 2: A basic SQL Server table that holds each user
Step 4: Here is where you bring it all together. You need name and column visibility information
to collect the results of the procedure (in this case,
whether SSRS allows the user to see the column). You can
implement a common SSRS pattern: Create a hidden/in-
ternal SSRS parameter and map the results of this dataset
to the parameter. In Figure 4, I’ve added an SSRS param-
eter called ShowModifiedDate (as an internal parameter,
so that SSRS never prompts for it), and I’ve mapped the
results of the ColumnVisible column from the dataset to
the default value. In the next step, I’ll use the value of
this parameter to determine column visibility.

You might find that


you’ll need to greatly
enhance this to work
for your scenario. Figure 3: An SSRS DataSet that calls the stored procedure and passes the current user as a parameter

Step 5: Finally, in the SSRS designer, right-click on the


column separator for the column you want to configure
(the “ModifiedDate” column in this example), and select
Column Visibility. In the Column Visibility dialog, enter
an expression to define whether you should hide the col-
umn based on the value of the ShowModifiedDate report
parameter. Note that the expression must return a Bool-
ean value based on whether you want to hide the column,
so in this case, you’re returning the reverse (“not”) of the
ShowModifiedDate parameter.

One final note-that I didn’t demonstrate here: Suppose


the ModifiedDate column had another column to the
right. If the user running the report doesn’t have the
rights to view the column, the SSRS engine won’t even
bother showing an empty space for the column. Instead, Figure 4: An internal SSRS parameter that holds the value for the column visibility

codemag.com SQL Server Reporting Services: Eight Power Tips 65


I’ve presented an overall approach, a pattern, for solving one example: Users want to show an aggregation at a
this problem. You might find that you’ll need to greatly high level (such as Sales by State) and then expand a
enhance this to work for your scenario. But hopefully I’ve state to show more detailed information (such as Sales
provided a major start on the mechanics. by City for the selected state). Most people refer to this
functionality as drill-down, although in practice, you’re
Tip #2: Implementing Drill-Down Functionality with initially suppressing the display of lower levels of detail
Options to Set Initial Drill-Down (like the city), and toggling the display of that lower level
Sometimes users ask for the same type of functionality based on how a user clicks on a higher level (like the
that’s found in end-user tools like Microsoft Excel. Here’s state).

I’m on a Mission.
I admit it.-I’m on a mission. That
mission is to show developers
and managers what SSRS can do.
Although no tool can accomplish
every imaginable task, SSRS
remains a powerful “bread and
butter tool” that you can often
extend. It might require some
elbow grease and the end
result might not win any beauty
awards-but often the result will
be good enough. Figure 5: An internal SSRS parameter that will hold the value for the column visibility

Figure 6: SSRS drill-down with options for whether to expand or collapse

66 SQL Server Reporting Services: Eight Power Tips codemag.com


Figure 6 shows an example of SSRS drilldown. Using the (so that the user can expand or collapse the grand total
Microsoft AdventureWorks demo database, I’ve built a re- to show or suppress the ship methods). In Figure 8, I
port that initially collapses sales by Shipper and Vendor. right-clicked on the row group for ShipMethodName and
I need to create a report with two row groups that sum- loaded the Group Properties dialog.
marize by Ship Method and Vendor, and I need to create
a grand total row (by summarizing all shippers). The user To complete the example, you’d need to follow the same
can expand the initial grand total to see the summarized pattern for the Vendor row group, using the ExpandVen-
ship methods, and then expand any ship method to see dors parameter and setting the display toggle to the par-
the summarized vendors for that ship method. And, al- ent vendor textbox.
though I haven’t displayed it, if the user expands any
vendor, the report will show individual purchase orders. Tip #3: Creating Cross-Chart Filtering Refresh Effects
In the last few years, software vendors have released
You can implement this in two major steps. self-service Business Intelligence tools that allow us-
ers to create attractive and interactive dashboards and
Step 1: In the SSRS Report, I’ve created two Boolean pa- charts. These tools also boast the ability to create pow-
rameters (Figure 7) that allow the user to determine if erful visualizations without always needing a developer.
SSRS should initially expand or collapse the Ship Meth- Examples of these products include Microsoft Power BI,
ods group and the Vendors group. Although this first step Tableau, QlikView, Domo, SpotFire, and others. Vendors
isn’t necessary for implementing basic drill-down, it does of these tools often demonstrate (and even promote as
give the user the ability to define whether SSRS will ini- a selling point) the ability to create a dashboard page
tially expand or collapse a group (i.e., set each group’s with multiple charts, where the user can click on one data
ToggleState). point of one chart within the page, and the tool instantly
refreshes other charts to reflect the initial selection.
Step 2: To implement drill-down at the Ship Method lev-
el, you need to define the initial visibility (based on the Here’s the question: Does SSRS contain built-in function-
value from the ExpandShipMethods parameters in Step ality for this type of cross-chart filtering? Similar to Tip
1). You also need to allow the user to toggle the display #1, the answer is no. SSRS doesn’t provide this ability
of the ship methods by the textbox for the Grand Total straight out of the box. However (and this becomes a fa-

codemag.com SQL Server Reporting Services: Eight Power Tips 67


miliar theme), SSRS provides enough open capabilities that the user selected. In the reload, you’ll set a Fill Color
and hooks to allow you to create a functional workaround. expression to dynamically color the current series in yel-
low if the current year/country matches the value of the
For example, look at the two charts in Figure 9. The first hidden parameter.
chart on the left plots sales as a vertical stacked bar chart by
country and year. The second chart on the right plots sales I must warn readers that because you’re essentially re-
by country and month. Suppose you wanted to click on a launching the same report, this won’t perform as instant-
specific series of data in the first chart (sales in the United ly as tools that provide this feature out of the box. So use
Kingdom in 2013) and force all charts on the page to high- and implement with caution.
light everything associated with U.K./2013 (Figure 10).

I’ll throw in a pop-culture reference here. Do you remem- Let’s stop and reflect that
ber the old TV show, “Name that Tune?” The signature you’ve used hidden/internal
response in that show was: “I can name that tune in (N)
parameters as a means to
notes.” Well, I can sing the “cross-chart filter visualiza-
tion” in three steps. Essentially, you’ll tap into the SSRS drive different SSRS behaviors.
Report Action feature for a plotted data series point, and
re-launch the report. As you do that, you’ll pass forward
to the report a hidden parameter for the year/country Having said all of that, here are the three steps:

Reporting is More Than Step 1: Create a hidden/internal SSRS parameter called


the Report HotSelect. You don’t need to provide any special prompts
for the parameter, as the user will never see it.
I wrote a book on reporting
functionality in 2006. In the book,
I stressed that the report writer Step 2: For each chart on the report page, go to the Se-
is but one part of reporting. You ries properties and then the Actions tab (Figure 10). Set
wind up spending more effort on the action to Go to report and specify the same report
defining the data requirements, name (to relaunch the report). In the parameters area at
the parameters, automated report the bottom of the dialog box shown in Figure 11, map the
generation, etc. That’s as true HotSelect Parameter based on the current tear and coun-
today was it was 10 years ago. try. If you haven’t realized it already, this works because
Figure 7: Two SSRS parameters to define the initial SSRS allows you to hook into the Actions area when the
ToggleState for the Ship Method and Vendor Groups user clicks on a chart data point. It also works because

Figure 8: Using the SSRS Group Properties to define the visibility and the report element that toggles the display of
that group

68 SQL Server Reporting Services: Eight Power Tips codemag.com


Figure 9: The initial report page with two charts.

Figure 10: The report page after the user clicks on U.K. Sales in 2013 on the left

SSRS keeps track of the current country/year series when that you’re implementing some SSRS design patterns
you click on a specific series. here, ones that could be used for other report functions.

Step 3: For each chart, go to the Series Properties dialog Tip #4: Repeating Column Headings Across Multiple Pages
box and the Fill tab (Figure 12). Set the Color Expression to Even the best tools in the world have an Achilles heel,
yellow if the current year and country that SSRS is plotting and this topic represents a very strange issue and even
happens to be the same value in the HotSelect parameter. stranger workaround in SSRS.

Before you go any further, let’s stop and reflect that Suppose you implement a standard tabular report (i.e., a
you’ve used hidden/internal parameters as a means to fixed number of columns) that spans many pages. When
drive different SSRS behavior. It’s not a stretch to say the user views the report in a browser and navigates be-

codemag.com SQL Server Reporting Services: Eight Power Tips 69


yond page one, the SSRS viewer doesn’t show the column The truth is that the “Repeat header columns on each
headings. Although SSRS provides an option in the SSRS page” option in the Table/Tablix properties only works
table properties to repeat column headings across each for matrix reports. The option has no effect on tabular
page, that option has no affect. So what’s going on? reports. In order to repeat column headings, you need to
tap into the Advanced Mode section at the bottom of the
report designer. In Figure 13, I’ve clicked the down arrow
on the far right of the report column groups. Once you go
into advanced mode, you’ll notice that the Row Groups
area now shows several static sections (Figure 14). You’ll
want to click the F4 key to bring up the full property sheet
for each static group above the first non-static group and
set the RepeatOnNewPage property to TRUE (Figure 15).

This might go down


in history as one of the more
obscure workarounds.

This might go down in history as one of the more ob-


scure workarounds. Even more interesting, this problem
didn’t exist prior to SSRS 2008. However, an obscure
workaround trumps no workaround in any poker game
I’ve ever played!

Tip #5: Dealing with Extra Blank Pages


When Exporting Reports
When printing reports or exporting reports to PDF, some-
times the SSRS report engine produces an extra page at
the end of the report, or (worse), inserts a blank page
between each regular page. The former scenario might
not anger users, but the latter scenario definitely requires
immediate attention. The question is, why is SSRS doing
Figure 11: Setting the Report Actions this and how can you prevent it?

Let’s take the latter scenario. This usually occurs because


the width of the content body exceeds the allowable
width. You can calculate the allowable content body width
as the page width (based on the report property orienta-
tion: portrait or landscape), less the left/right margins.
In Figure 16, the full content body is roughly 10.5 inches,
whereas the total page width is 8.5 inches and the left/
right margins are one inch each. So the maximum allow-
able content body is 6.5 inches. (In practice I’d never go
beyond 6.3 inches to allow a margin of error).

Some people might address the issue in Figure 16 by sim-


ply stretching the report table inward to stay with the
allowable width, but they might leave the outer design
area at the original width (10.5 inches). As I’ve shown
in Figure 17, you need to also stretch that outer edge of
the design area inward to stay within the range, or SSRS
generates a blank page at the end.

Figure 12: Setting the Report Series fill color based on whether the current plotted country/
year matches the hidden parameter

Figure 13: Click the drop-down to the right of Column Groups to enter Advanced Mode Figure 14: SSRS Advanced Mode with Static Row Groups

70 SQL Server Reporting Services: Eight Power Tips codemag.com


you to specify one primary dataset to drive the content. Is
there any way for the report to show related information
from the second dataset?

Before I continue, someone might respond with a sug-


gestion to modify the database code that returns the first
result set, and add additional columns so that you don’t
need the second result set. For this example, assume you
can’t modify the database code and that you’re stuck with
two procedures/two datasets. Although this constraint
isn’t very common, it’s certainly not unheard of either.

Prior to SQL Server 2008 R2, this was a very difficult


challenge. Fortunately, Microsoft implemented three new
functions in SSRS 2008R2 (released in spring 2010). They
are Lookup, LookupSet, and MultiLookUp. These func-
tions allow SSRS developers to return information from a
secondary SSRS DataSet, so long as the secondary Data-
Figure 15: Set the RepeatOnNewPage property to TRUE Set contains a column that you can relate from the pri-
for each Static Group above the first actual group mary dataset.

SSRS 2016 Gets Some Love!


As I type this, Microsoft is close
to releasing SQL Server 2016.
SSRS will receive a much-needed
Figure 16: Produces blank pages because the total ruler widthmakeover,
(10.5 inches) exceedsinallowable
particularly the end-
width less margins (6.5 inches) user experience.

Tip #6: Relating Multiple Tables in a Report


Suppose you create an SSRS report that contains two da-
tasets. The first dataset contains the primary report data
and the second dataset contains lookup information.
You’d like the SSRS designer to relate the two datasets
based on some common field/key. Unfortunately, the
SSRS designer doesn’t contain any such feature. Further-
more, the SSRS table (Tablix) report control only allows Figure 17: Also produces a blank page at the end because of the extra white space.

codemag.com SQL Server Reporting Services: Eight Power Tips 71


You can use Lookup to search a second dataset based on
a specific common value and return a single column from
the second dataset. You can use LookupSet when you
want to return multiple columns from the second dataset.
Finally, you can use MultiLookUp to lookup in a second
dataset based on multiple values.

Here is an excellent blog entry that covers these three


functions: http://www.sql-datatools.com/2015/07/look-
up-functions-in-ssrs.html

Tip #7: Implementing a Nested “Page X of Y” on a Report


Nearly every report writer provides sufficient pagination fea-
tures to show “Page X of Y” on reports. However, users might
want a nested “Page X of Y”. For example, suppose you’re
generating a long report (160 pages) of detailed transac-
tions by customer. You want to define overall pagination
(Page 1 of 160, Page 2 of 160, etc.), but you also want to
define pagination scoped to the customer (Page 1 of 2, if the
current customer has two pages of transactions).
Figure 18: Report that shows an Overall Page X of Y and a nested Page X of Y for a business
context (the vendor) Similar to Tip #6, prior to SQL Server 2008R2, developers
struggled to implement this. You needed to manually cal-
culate page definitions as part of the result set. This meant
determining exactly where page breaks would occur, which
might become error-prone if someone changes any aspect
of the report layout (report margins, orientation, etc.).

Fortunately, Microsoft implemented a new feature in


SSRS 2008R2. Specifically, they redesigned the pagi-
nation to implement two sets of page numbering
global variables: Globals!OverallPageNumber and
Globals!OverallTotalPages, as well as Globals!PageNumber
and Globals!TotalPages.

In Figure 18, I’ve created two textboxes in the page


header to use both sets of pagination values. However,
that in itself does nothing. SSRS still generates “Page 1 of
166,” “Page 2 of 166,” etc., for both sets of page counts.
So what else do you have to do?

SSRS did exactly what you told it to do instead of what you


wanted it do to. Even though the report contains a vendor
grouping, the report could theoretically contain multiple
groups, and SSRS doesn’t know which group to use for the
nested pagination. You need to provide that information!

In Figure 19, I’ve pulled up the full-blown property sheet


Figure 19: To set nested pagination, pull up the full property sheet for the Tablix control and for the Tablix control, and I’ve set the PageBreak prop-
set the Page Break properties. erties (the dataset column that represents the grouping
as the PageName property, and a value of TRUE for the
ResetPageNumber property).

Tip #8: Implementing Running Aggregations


Even SSRS novices are aware that SSRS allows you to cre-
ate report subtotals and grand totals very easily. How-
ever, does SSRS allow you to show running totals and
running aggregations?

Fortunately, the answer is “yes.” Not only that, but SSRS


provides some very nice functionality to make this task
easy. Figure 20 shows a sample report with three sets
of running averages for chronological months in a year.

Figure 20: An example report that shows running totals, running averages, and running At first glance, you might think that SSRS provides three
maximum values (highest month to date) separate functions for the three columns. As it turns out,

72 SQL Server Reporting Services: Eight Power Tips codemag.com


CODE COMPILERS

May/June 2016
Volume 17 Issue 3

Group Publisher
Markus Egger
Associate Publisher
Rick Strahl
Figure 21: RunningValue function with parameters
Editor-in-Chief
Rod Paddock
Managing Editor
SSRS provides just one function, called Run- Final thoughts: Ellen Whitney
ningValue. You provide the aggregation method I hope I’ve provided some information to help
Content Editor
as a parameter to the RunningValue function. you in building SSRS reports. In future articles, Melanie Spiller
Figure 21 shows an example. I’ll continue to show different SSRS power tips.
Writers In This Issue
As a SQL Server/Business Intelligence contrac- Mohammad Azam Jason Bender
You pass three parameters to RunningValue: tor/consultant, I’ve always found that working Miguel Castro Kevin Goff
near the report layer helps me to understand the Sahil Malik Ted Neward
John Petersen Rachel Reese
• The column value you wish to aggregate breadth and depth of the client’s business appli- Walter Ritscher Paul Sheriff
(the Monthly sales amount) cation. Users will always want functionality that Technical Reviewers
• The aggregation method (Sum, Avg, Max, the product doesn’t provide out of the box, so Markus Egger
etc.). Note that SSRS color-codes the ag- the value of SSRS depends on whether the tool Rod Paddock
gregation method in blue, indicating that provides enough hooks or open architecture for Art & Layout
SSRS treats it as a keyword. developers to extend it. Overall, SSRS does a very King Laurin GmbH
info@raffeiner.bz.it
• The scope of the aggregation (the name of good job here.
the group). In this instance, you’re aggre- Production
Franz Wimmer
gating months within a year. Every running Kevin S. Goff King Laurin GmbH
aggregation contains a scope, so you need 39057 St. Michael/Eppan, Italy
to provide the actual SSRS group name. Printing
Fry Communications, Inc.
800 West Church Rd.
Mechanicsburg, PA 17055
Advertising Sales

(Continued from 74) Summary Tammy Ferguson


832-717-4445 ext 026
Regardless of where you fall on this question, tammy@codemag.com
of the other driver. This ensures that I can’t use it’s not going away any time soon. In fact, as Circulation & Distribution
your speeding as an excuse to get out of my drunk software becomes more ubiquitous (is that even General Circulation: EPS Software Corp.
International Bonded Couriers (IBC)
driving, or vice versa; instead, it remains entirely possible?), it stands to reason that software will, Newsstand: Ingram Periodicals, Inc.
focused on the exact moment of the crash. before too long, be directly responsible for more Media Solutions
and more aspects of our lives. It already directs Subscriptions
And this makes a certain amount of sense, except when we begin our day (alarm clocks), when we Subscription Manager
that it’s too hard, in most scenarios, to determine engage with others (schedulers), and for many, Colleen Cade
832-717-4445 ext 028
where that last responsible moment was. The code when we go to sleep (personal health monitors ccade@codemag.com
crashed because of a NULL reference on which an like the Fitbit or Band). And, if the reports from
object was invoked—certainly, this is the fault of Google are any indication, before too long it will US subscriptions are US $29.99 for one year. Subscriptions
outside the US are US $44.99. Payments should be made
the developer who wrote that method call, right? be driving our cars. in US dollars drawn on a US bank. American Express,
Unless, of course, that object reference is an ar- MasterCard, Visa, and Discover credit cards accepted.
gument into this function, and it’s clearly docu- Which, of course, brings this question all the way Bill me option is available only for US subscriptions. Back
issues are available. For subscription information, email
mented that it cannot be NULL; then it’s the fault back to a much more practical, real question: if subscriptions@codemag.com
of the individual who wrote the code that passed it two self-driving cars get into an accident, with or contact customer service at
in, right? Unless, of course, that reference is actu- whom, exactly, does the fault lie for insurance 832-717-4445 ext 028.
ally set by the object/relational mapper when pull- purposes? If a self-driving car drives off the road
ing data out of the database, and that relationship for some reason, and there is a provable soft- Subscribe online at
www.codemag.com
is supposed to have at least one member and it ware bug that caused it, are the developers who
doesn’t, in which case it’s the fault of whomever worked on that code now liable for the damages CODE Developer Magazine
wrote last to that table…and so on. And even if you to the car, the surrounding terrain, or even the 6605 Cypresswood Drive, Ste 300, Spring, Texas 77379
Phone: 832-717-4445
believe in the most paranoid “defensive program- families of those who were injured or killed? Fax: 832-717-4460
ming,” as soon as you move into multithreaded/
parallel programming, references can change even Because—and let’s get this clear right from the
in the small amount of time between the null-refer- start—if we don’t think about this, it’s certain
ence check and its usage. We could do this for days. that others will when the time comes. And we may
not like their answers.
This all presumes, of course, that developers can
even find the bug in question—in some cases, Ted Neward
that’s assuming a lot.

codemag.com Managed Coder 73


MANAGED CODER

On Responsibility
For an industry that prides itself on its analytical ability and abstract mental processing, we often don’t
do a great job applying that mental skill to the most important element of the programmer’s tool
chest—ourselves.

Over the last year or so, I’ve been writing a lot Relational databases have been doing this for “Just Following Orders”
about management and related topics. But two years: A number of different benchmark tools, Programmers must build what they are told to
incidents in the last several months have finally called the TPC-A (through -E) benchmarks, are build. We are, after all, performing “work for
pushed me over the edge into getting back to a routinely run against the various RDBMS ven- hire,” most of us, and in the same vein that we
topic that is closer to the individual developer dors’ products to determine relative performance garner no benefit (in the form of profits, royal-
again. The first is the (as of this writing) ongo- numbers. And, as the story goes, database ven- ties, license payments, or some other money)
ing saga around the San Bernardino shooter’s dors cheat outrageously inside their databases in from having written the software, neither can we
iPhone, and the US court order demanding that order to optimize specifically to those use cases, therefore be held responsible for its effects.
Apple comply with the FBI request for assistance thereby distorting the actual numbers in order to
in breaking into the device to retrieve informa- return faster (and therefore presumably better) In many ways, this is the same argument used at
tion from it that the FBI deems useful and/or numbers against their competitors. the Nuremburg Trials against the various members
necessary to the investigation. The second is the of the German Army and SS for their crimes against
ongoing saga around the Volkswagen emissions This raises an interesting ethical question: If a humanity. In a military hierarchy, if a superior of-
benchmark “hack” that changed the engine’s software developer is asked to implement a fea- ficer gives you an order, you’re compelled to obey
performance characteristics. This was based on ture that either leads to, or is, or is itself di- it or face court-martial. That means, of course, the
information fed to the emissions benchmark from rectly unethical, immoral, or illegal behavior, is officer who gave that order holds the responsibility
the sensors elsewhere in the car so that when the that software developer liable for the damages for its effects, but as the individual who carried it
vehicle was being tested for noxious emissions, caused? out, you are immune from its effects.
it operated in a less-performant but eco-friendly
way, and otherwise pumped out much higher tox-
ins than allowed by various national environmen- Ethics, Not Legalities The Last Responsible Moment
tal standards (including both Germany’s and the Just to be clear, the argument I want to have But the “following orders” argument holds signifi-
US’s). here is based around the morals and/or ethics of cant flaws: One is that, except for those program-
the issue, not its legalities. The reason for this is mers who are a part of the armed forces, we aren’t
In each of these cases, software lies at the heart manifold: To start, the classic IANAL (I am not a in a strict hierarchy, and there are no legal conse-
of the story. But my concern is this: To what de- lawyer) disclaimer is in full force here, and I de- quences from disobeying a superior. If instructed
gree are software developers responsible for their fer any and all questions of the law to my friend to implement a feature that you find unethical,
actions in each case; to what degree will we be and colleague, John V. Petersen, who also writes immoral, or illegal, you are certainly capable of
held responsible by the legal framework in which in this publication and may be so moved as to refusing to do so, and many in the industry would
we live (be that in the US or elsewhere); and to take up this question in a future issue. Secondly, applaud you for it. You’d be unemployed, granted,
what degree should we hold ourselves respon- though, is the simple fact that laws change with but you wouldn’t be the one responsible—legally or
sible? the times—the question of slavery in the US being otherwise—for said feature. Somebody else might,
just but one extreme example—and so what holds who can’t really afford to be unemployed for any
as legal today, may not be so tomorrow or vice length of time, but that’s their problem, not yours.
Background versa. It is fully safe, I believe, to assume that
Although it would be easier to debate or discuss the laws around software and liability will change Perhaps the right way to think about this is in the
if readers have a relatively basic understanding of as the role, nature, and responsibility of software same way we think about technical decisions—
each situation, each one can be abstracted away increases in our daily lives. that the individual who has the last responsible
from the details pretty easily. moment before an incident occurs is the one to
This is not without precedent—in the earliest days whom we assign responsibility. Thus, since you
In the VW case, software engineers were instruct- of the Industrial Revolution, no laws around ma- are the one who wrote the code, you are the one
ed by management—and as of right now, it’s not chine safety, even for food production, were in responsible for it, irrespective of what your boss
clear exactly from where those orders came, but place. As the impact of industrial processing grew, or management chain demanded.
popular perception holds that it definitely “came however, and abuses grew (particularly against
from above,” rather than originating with one of those who worked the machines—read Upton This is not without precedent—in the US, many
the engineers themselves—to deliberately change Sinclair for more graphic details), legal frame- states have a similar concept in place around the
the operation of the vehicle under particular con- works were established and liabilities enforced. application of fault in a driving accident. If one
ditions. Whether the engineers understood that One might argue that the pendulum has swung driver had an opportunity to avoid the accident
those conditions were the ones that would more too much the other way by this point, and an- and didn’t take it (for whatever reason), that driv-
than likely identify the vehicle as being tested for other might argue the reverse and that still more er is at fault regardless of the actions or behavior
emissions standards is not entirely clear to me, protections are necessary, but either way, the fact
but this is not new ground for us as an industry. remains that laws change. (Continued on page 73)

74 Managed Coder codemag.com

You might also like