<?xml version="1.0" encoding="UTF-8" ?>

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
   
    <title>thebhwgroup.com</title>
   
   <link>https://thebhwgroup.com</link>
   <description>We build web and mobile applications for businesses of all sizes.
</description>
   <language>en-us</language>
   <managingEditor>bhwinfo@thebhwgroup.com</managingEditor>
   <atom:link href="rss" rel="self" type="application/rss+xml" />
   
    
	  <item>
        <title>AngularJS - ngInfiniteScroll Example</title>
        <link>https://thebhwgroup.com/blog/nginfinitescroll</link>
		<author>Jason Gray</author>
		<pubDate>2016-08-08T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/nginfinitescroll</guid>
		<description><![CDATA[
		   #ngInfiniteScroll: Converting a home-grown “Show More” function to a more elegant AngularJS solution



I can think of numerous times in the past where I had some list of data on a webpage that would frequently require the ability for users to crawl deeper into the results in search of something.  In many of the more complex web and mobile applications that we build for clients, there is simply too much data to present in a confined space. We frequently come across the requirement for a data list control that allows for paging or scrolling.  This requirement has frequently materialized into a data grid or a sorted list with a custom function to go back to the server and request the next set(s) of records.  The goals are usually to gather the most essential subset of data, present that to the user on first load, and then allow the user to easily get to the rest of the data as needed.  I have recently started using the ngInfiniteScroll directive in our Angular projects for this type of feature, after seeing one of my teammates, Taylor Smith, implement it successfully.



In this article, I will review moving from a button to load more data to using the ngInfiniteScroll directive to load data as the user scrolls the list. Months ago, I had created a function to load an additional 30 days of patient data with a “Show More” button. As the application matured and we had greater amounts of older data that was only reviewed occassionally, I switched that to use this infinite scroll directive for a more elegant user experience.



## The Old (Custom):



In order to display 30 days of the patient’s data on the page load, there is an Angular service call to an api controller method.  The initial call passes in a patient’s id and parameters to get the most recent 30 days’ worth of data.



### The Angular service:



```javascript

function DocumentationService($resource, $q) {

    this.getByPatientIdForDays = function (id, daystart, dayend) {

        var deferred = $q.defer();

        var resource = $resource('api/Documentation/GetByPatientIdForDays', { Id: id, DayStart: daystart, DayEnd: dayend }, { 'query': { method: 'Get', isArray: true } });

        resource.query(function (response) {

            deferred.resolve(response);

        }, function (response) {

            deferred.reject(response);

        });

        return deferred.promise;

    };

}



module.service('Documentation', ['$resource', '$q', DocumentationService]);

```



### The MVC API Controller method



```C#

[Route("GetByPatientIdForDays")]

public IList<DocumentationDTO> GetByPatientIdForDays(int Id, int DayStart, int DayEnd)

{

    List<DocumentationDTO> docDTOs = new List<DocumentationDTO>();

    DateTime limitStart = DateTime.Now.AddDays(-DayStart);

    //If the start date was passed in as 0, find the most recent date for documentation

    if (DayStart == 0) { limitStart = DateTime.Now.AddDays(-(CalculateMostRecentDaysAgo(Id) + 30)); }

    DateTime limitEnd = DateTime.Now.AddDays(-DayEnd);



    IQueryable<Document> docs = _docRepository.AsQueryable().Where(x => x.PatientId == Id && x.CreatedDate > limitStart && x.CreatedDate <= limitEnd).OrderByDescending(x => x.CreatedDate);

    //The code then maps the query results to the DTO objects and returns that.

}

```





### The original load of the page sends in 0 for the date parameters and returns the array of results to a scope parameter named $scope.Documents



```javascript

return Documentation.getByPatientIdForDays(id, 0, 0);

```



In order for this feature to work, I needed to know a few things about the document data for the patient:



1. An integer value for the number of days from today to the earliest date of a patient’s documents.

    1. I added this as `$scope.mostDaysAgo`

    2. This value is set by an api call (GET) to a controller method called GetMostDaysAgo, which returns an integer.

2. An integer value for the number of days from today to the latest date of a patient document.

    1. I added this as `$scope.leastDaysAgo`

    2. This value is set by an api call (GET) to a controller method called GetLeastDaysAgo, which returns an integer.





```javascript

//Allow the user to move back until they reach the oldest records...  30 days at a time

//Get most recent data's date

$scope.getLeastDaysAgo = function () {

    $http({

        method: 'get',

        url: 'api/Documentation/GetLeastDaysAgoByPatientId?id=' + patient.Id

    }).success(function (data) {

        $scope.leastDaysAgo = data + 30; //start with 30 days back from first available data

    });

};

//Get oldest data's date

$scope.getMostDaysAgo = function () {

    $http({

        method: 'get',

        url: 'api/Documentation/GetMostDaysAgoByPatientId?id=' + patient.Id

    }).success(function (data) {

        $scope.mostDaysAgo = data;

    });

};

```



On the html page, we have Angular displaying the list of documents and the document properties that are important to the users.



```html

<div class="documentation-box">

    <div class="document-item" ng-repeat="doc in Documents">

    <h2>{{doc.Title}}</h2>

    ...



```



At the bottom of the results, we have a button to “Show More”, if applicable.  If the `$scope.mostDaysAgo` is less than 30 days ago, then this button and section will not be displayed at all.  The section and button will continue to be displayed until the user browses back in time to the oldest document data for this patient.



```html
<div class="document-item" ng-show="mostDaysAgo > 60">

    <h4>Currently showing results from {{ leastDaysAgoFmt }} through today.</h4>

    <h4>The oldest results for this patient are from {{ mostDaysAgoFmt }}.</h4>

    <button class="show-more btn" ng-click="showMore()" ng-show="mostDaysAgo > 30 && leastDaysAgo < mostDaysAgo">

        Show 30 Days More

    </button>

</div>
```



*The `leastDaysAgoFmt` and `mostDaysAgoFmt` scope variables are a formatted version of the start and end date.  They are used for display only.*



The Angular ng-click of the button (when enabled) makes a new call to a function that:



1.  Increments the days back in time you are viewing.

2.  Calls the controller method GetByPatientIdForDays(int Id, int DayStart, int DayEnd) to get a new set of data for the new parameters.

3.  Appends the resulting documents to what we are already displaying on the page so that the user can continue to scroll downward.  The document data already loaded remains on the page and the new data appears beneath it.



```javascript

$scope.showMore = function () {

    $scope.leastDaysAgo += 30;

    Documentation.getByPatientIdForDays(patient.Id, $scope.leastDaysAgo, $scope.leastDaysAgo - 30).then(function (response) {

        _.each(response, function (item) {

            $scope.Documents.push(item);

        });

    });

}

```



This process repeats until the user reaches the oldest documents for the patient and then the button will disappear.



**Currently showing results from 2/4/2016 through today. The oldest results for this patient are from 5/20/2015.**



<img src="/sites/default/images/blogs/2016-04-28-nginfinitescroll/showmorebtn.png" alt="Show More Button"/>



The user:

*Clicks button… (scrolls to bottom)…. Clicks button… (scrolls to bottom)…*



**Currently showing results from 5/20/2015 through today.**



##The New (ngInfiniteScroll):



There weren’t a ton of changes that needed to happen to implement an infinite scroll on the document data list.  We first needed to add ngInfiniteScroll to our application.  We used the instructions from the github site:



[GitHub - Infinite Scroll](https://github.com/sroze/ngInfiniteScroll)



We then added it to our Angular bundle and made it a new dependency in our main application module:



```javascript

var module = angular.module('{OUR_APPLICATION_NAME}', ['ngRoute', ..., 'infinite-scroll']);

```



Once the infinite scroll package was included in our application we made the necessary changes to the JavaScript functions on the document list page along with setting some new attributes on the corresponding elements in the html page:



```html

<div infinite-scroll='showMore()' infinite-scroll-disabled='loadingDocuments || mostDaysAgo <= 30 || leastDaysAgo >= mostDaysAgo' infinite-scroll-distance='1'>

```



* The infinite-scroll attribute defines the script function to call when triggered.

* The infinite-scroll-disabled attribute defines when the scrolling function is off.  In our case, scrolling will be disabled while the showMore() JavaScript function is in progress (waiting for results from the api call).  It will also be disabled when there are no more data points more than 30 days ago.

* The infinite-scroll-distance represents how close the bottom of the control (div) is to the bottom of the browser window and it defines when to trigger the infinite-scroll.  It is multiplier based on the height of the browser window.  The default value is 0, which would cause the event to trigger only when the bottom of the control came into view in the browser window.  If you set it at 2, for example, and your browser window was 1000 pixels in height, the event would fire when the bottom of the control was within 2000 pixels.  I played around with this value until it worked for our needs (set at 1).  Each document in our data takes up several hundred pixels in height, but if you are working with more row-oriented data that takes up little vertical space, then leave the attribute out altogether or set it to the default of 0.



I removed the “SHOW 30 DAYS MORE” button from the bottom, added a loading spinner, and kept the rest the same so that the user could still see the additional information about where they were in the history of the documents.



```html

<div class="document-item" ng-show="mostDaysAgo > 30">

    <h4>Currently showing results from {{ leastDaysAgoFmt }} through today. <span ng-show="loadingDocuments">Loading next 30 days...</span> <i ng-show="loadingDocuments" class="fa fa-spinner fa-pulse fa-4x loading-spinner"></i></h4>

    <h4>The oldest results for this patient are from {{ mostDaysAgoFmt }}.</h4>

</div>

```



I needed to add one additional `$scope` item (`loadingDocuments` to keep track of when the retrieval of more data was in process) and set it to false by default.  I then modified the `showMore` function to set that value to true while the script was waiting for the next set of documents and false afterwards.  This is also what triggers the loading spinner to show.



```javascript

$scope.showMore = function () {

    if ($scope.loadingDocuments) return;

    $scope.loadingDocuments = true;

    $scope.leastDaysAgo += 30;

    Documentation.getByPatientIdForDays(patient.Id, $scope.leastDaysAgo, $scope.leastDaysAgo - 30).then(function (response) {

        _.each(response, function (item) {

            $scope.Documents.push(item);

        });

        $scope.loadingDocuments = false;

    });

}

```



With the new changes, the page initially loads with the past 30 days of documentation like it did before.  If the user scrolls to the bottom of the list of documents, a new message saying “Loading next 30 days…”, the loading spinner graphic appear.  When the api call returns, the results show while the loading message and spinner hide.  The same will continue to happen when the user again scrolls to the bottom of the page until there are no longer any older results.  In our example, the end of the line would be 5/20/2015.



<img src="/sites/default/images/blogs/2016-04-28-nginfinitescroll/infinitescrollloading.png" alt="Currently showing - infinite scroll loading"/>



##Conclusion



Like most of you out there, I look for ways to improve my development work in order to make applications run more smoothly and to make them easier for the user.  This article explored a place where I had previously built a feature to allow users to explore older data, but users found this feature frustrating as the application matured and there was more archived data to browse through.  The ngInfiniteScroll directive provided an easier and more intuitive solution for users and I used this practical example to introduce you to this great tool.
		]]></description>

    
        <category>angularjs</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>What Goes into a SXSW Interactive Finalist</title>
        <link>https://thebhwgroup.com/blog/what-goes-sxsw-interactive-finalist</link>
		<author>Paul Francis</author>
		<pubDate>2015-03-04T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/what-goes-sxsw-interactive-finalist</guid>
		<description><![CDATA[
		   We are thrilled to announce that CareCycle Navigator, a <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">web application</a> we developed, is a SXSW Interactive Innovation Award finalist. This article will explore the technologies we used to build CareCycle Navigator, why we chose them, and what made them successful.

##About CareCycle Navigator
{% include full-blog-image.html src="2015-sxswi-award.jpg" alt="2015 SXSW Interactive Award logo" class="left" %}

The application predicts which chronically ill patients in a population are at the greatest risk for impending health problems and gives remote clinicians a structured way to intervene and prevent costly health events. The application makes “connected patient” management a scalable reality and functions as an early warning system for chronic illness exacerbations. For a further overview of the project, check out our <a href="https://thebhwgroup.com/projects" target="_blank">project page</a>. And now on to the tech talk.

##AngularJS
{% include full-blog-image.html src="angularJS.png" alt="AngularJS logo" %}

CareCycle Navigator’s front end is built with <a href="https://angularjs.org/" target="_blank">AngularJS</a> - which includes routing, templating, and API access. More than any other technology we used, AngularJS enabled and shaped the structure of the application. 

The main feature of AngularJS is two way data-binding. Historically, we’ve relied heavily on <a href="http://jquery.com/" target="_blank">jQuery</a> for client-side functionality. While an awesome project, it alone does not provide the structure a large application like CareCycle Navigator needs. There are pages with dozens of computed fields that all update as the user makes changes. AngularJS saved an incalculable amount of time in crafting these pages by guaranteeing that the DOM stayed in sync with the application state. Anyone on the team could tell you how often we joked about the time it would have taken to develop a given component without AngularJS’s data-binding.

After we made the decision to go with AngularJS, we got a ton of useful features almost for free. <a href="https://thebhwgroup.com/blog/2014/08/designing-html-forms-angularjs-part-1" target="_blank">Easy form validation</a>, simple REST API integration, client-side routing, testability, and maintainability.

As an example of what AngularJS provided, on one particular page, any single user action can propagate up to 10 additional UI changes. Any given entry can alter the validation rules of numerous other fields. This complex and interwoven behavior would have been a nightmare without AngularJS. In many ways, this page is the crux of the application, and as such, went through a number of design iterations. In several cases, major design changes only required HTML edits, while our javascript (specifically our AngularJS controllers) remained the same.

Many wonder about the scalability of single page applications in general, and AngularJS specifically. CareCycle Navigator has been a huge success and at this point contains hundreds of AngularJS templates, directives, and controllers. 

We’ve written at length about our adoption of AngularJS, if interested feel free to check out our other <a href="https://thebhwgroup.com/tags/angularjs" target="_blank">blogs</a> on the topic.

##Node.js
{% include full-blog-image.html src="nodejs-green.png" alt="nodeJS logo" %}

A major component of the Navigator application is the scoring and assessment of patients. The system uses a complex, patent-pending algorithm to determine these values. This algorithm can utilize hundreds of data items from over a dozen data sets to calculate a single patient’s risk. Additionally, this process needs to occur in near real-time for thousands of patients each day. Because of the intense performance demands and irregular and inconsistent data provided, we chose to write the risk analysis in <a href="http://nodejs.org/" target="_blank">Node.js</a>.

Additionally, the assessment engine needed to be able to respond to changing rules at runtime. This was particularly important during the tuning process of the system. By treating code as data, we were able to allow clinical experts to fine-tune the existing rules or create new rules altogether. Since Node.js is interpreted, each change can be tested immediately. This would have been much more difficult to achieve in a compiled language and would have required frequent recompiling of the project. Before committing to this approach, we tried both a C# (Web API) approach and a SQL approach. Both would have taken considerably longer to complete, were less performant, less flexible, and would have been significantly more difficult to maintain. Although, we only used Node.js for this component, it had a major impact on the application.

If you are interested in reading more about our thoughts on Node.js, please check out our other <a href="https://thebhwgroup.com/tags/nodejs" target="_blank">blogs</a> on the topic.

##Web API
{% include full-blog-image.html src="web_api_logo.png" alt="web API logo" %}

There are hundreds of other API calls that are unrelated to the risk calculator, which were all written using Microsoft’s <a href="http://www.asp.net/web-api" target="_blank">Web API</a>. The project had a hard requirement of SQL Server and we wanted to have as thin of a server-side component as possible, so this was a pretty obvious choice. It also didn’t hurt that we all really love C#.

WebAPI allowed us to quickly and easily write the API endpoints we needed, provide role-based authentication, and data checking. Although we sought to do everything possible client-side, there are some things that should always remain the server’s responsibility. Web API provided the ability to do those things and then let us handle anything else where we saw fit.

There are a few other server-side libraries that were a big help on this project, which includes:
<ul>
<li><a href="http://automapper.org/" target="_blank">AutoMapper</a></li>
<li><a href="https://github.com/StackExchange/dapper-dot-net" target="_blank">Dapper</a></li>
<li><a href="http://www.asp.net/entity-framework" target="_blank">Entity Framework</a></li>
<li><a href="https://www.nuget.org/packages/elmah/" target="_blank">Elmah</a></li>
<li><a href="https://github.com/webgio/Rotativa" target="_blank">Rotativa</a></li>
<li><a href="https://github.com/zxing/zxing" target="_blank">ZXing</a></li>
<li>And the next item on our list...</li>
</ul>

##SignalR
When dealing with highly sensitive information, such as Navigator does, real time information is crucial. Having to rely on users refreshing their browsers or coordinate usage can literally be life-threatening. In this system, it is crucial that the most severe cases are handled immediately. To achieve these goals, we used <a href="http://signalr.net/" target="_blank">SignalR</a> to transmit fresh data to users and update their views accordingly, so that they will never have to refresh their browsers. SignalR utilizes <a href="http://en.wikipedia.org/wiki/WebSocket" target="_blank">web sockets</a> (where possible) to push information from the server to the client, or vice versa. The browser is effectively listening for certain events to happen and responds to those events accordingly.

The following image is from the CareCycle Navigator dashboard:

{% include full-blog-image.html src="signalR_demo_-_Nav_dashboard.png" alt="SignalR Demo - Dashboard screenshot" %}

This page is used as a triage system, with the requirement that the information on display must be kept in sync between all users and the server. This is where SignalR comes in. The highest risk patients are at the top and the clinicians work their way down each day. Watching this page in production is a real joy. Every few seconds, a new set of patient vitals will be posted, causing that patient to be sorted into the queue. Meanwhile, as clinicians open patient pages, the dashboard updates to indicate who is viewing the record. Once a patient has been assessed and cleared, they then drop off the list until they post another score. In this manner, the list starts at 0 each day, grows and shrinks throughout the day, and falls back down to 0 each night. It's challenging to coordinate so many moving parts, but SignalR enabled us to provide rich collaboration, coordination, and timeliness, reminiscent of a desktop application.

##D3
One of Navigator’s needs was for custom charts that both perfectly match our designer’s vision, but also deliver information as clearly as possible, while allowing for functionality changes. We spent a while researching existing charting libraries, but ultimately decided that the only way to get exactly what we wanted was to build it ourselves - but with a little help!

Enter <a href="http://d3js.org/" target="_blank">D3</a>. D3 is a DOM-manipulation library that specializes in creating and transforming visualizations of changing data sets. It’s particularly useful for working with <a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank">SVG</a>. 

The image below shows one of Navigator’s charts:

{% include full-blog-image.html src="D3_Navigator_Chart.png" alt="D3 Demo - chart screenshot" %}

This chart shows a patient’s vitals over time, their expected healthy range of vitals, the times when those ranges were changed, and expands or contracts as the window of time changes. Without D3 we either would have had to compromise on functionality and appearance by using an existing charting library, or spend a significant amount of time writing DOM code ourselves. D3 made it easy to define what our chart should look like based upon the behind-the-scenes values, and smoothly transition as values are added and removed.

##Conclusion
Award winning projects require more than just knowledge of how to use the tools at hand. They require the <strong>right</strong> tools. CareCycle Navigator would not have been possible without the time we spent, before writing any code, surveying our options. 

At The BHW Group, we pride ourselves on our research and vetting of new technologies. We do not rely on a cookie-cutter list of technologies, but instead we draw from our experience to choose what is right for each unique challenge. If you are looking for a web or mobile development firm to tackle your latest project, <a href="https://thebhwgroup.com/contact" target="_blank">contact BHW</a> today. Let’s create award winning software together. 
		]]></description>

    
        <category>SXSW</category>
    
        <category>Award</category>
    
        <category>angularjs</category>
    
        <category>NodeJS</category>
    
        <category>WebAPI</category>
    
        <category>D3</category>
    
        <category>SignalR</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>Translation and Localization with AngularJS Part 2</title>
        <link>https://thebhwgroup.com/blog/2015/01/translation-localization-angularjs-part-2</link>
		<author>Taylor Smith</author>
		<pubDate>2015-01-20T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/2015/01/translation-localization-angularjs-part-2</guid>
		<description><![CDATA[
		   ## Welcome Back!

This is part 2 of my article about i18n and l10n. If you don't know what these are, go see [part 1](https://thebhwgroup.com/blog/2015/01/translation-localization-angularjs/) of my article. Otherwise let's dive right in and cover some of the big problems and steps to take while implementing angular-translate.

{% include full-blog-image.html src="language-books.jpg" alt="AngularJS Translation books" %}

## String Organization
An important feature of angular translate is that it provides a way to organize strings that you use for translation. There are many ways you can do this so I will only look at a few of the features and show examples of how I organized my app. Depending on the scope of your application you can use these or mix in other ways of organizing from the [guide](http://angular-translate.github.io/docs/#/guide/07_multi-language).

To organize my application I made a directory specifically for translation related js files. This was nested in the js folder for the application and contained one file for behavior and other files for translated strings. The string files were in the following format and there was one file for each language that the app was translated in. You could separate these by page, sub-domain, or however you choose. I personally found that, since it behaves like a dictionary, having the same strings on the same lines across different languages was extremely helpful. The following snippet is an example of how I set up the individual documents for each language. Line three specifies the language that this particular file is for and the translated strings begin at line 4. The strings are nested into pages, but again, these nestings are completely arbitrary.

```javascript
var app = angular.module('sample_app');
app.config(['$translateProvider', function ($translateProvider) {
	$translateProvider.translations('en', {
		"HOME": {
			'SIGNUP_TEXT' : 'Looks like you need to <a href="/register" class="register-link">Sign Up!</a>.',
			'WELCOME' : 'Welcome to the site!',
			//Default interpolation
			'HELLO' : 'Hello {{userName}}.',
		},
		"ABOUT": {
			'ABOUT'     : 'This is some info about our site',
			//Example of pluralized interpolation
			'VISITORS' : 'We {NUM_VISITORS, plural,
					zero  {haven\'t had visitors yet}
					one   { had a single visitor}
					other { had # visitors}}.',
			//If this version of interpolation is used ALL strings must conform to this type of interpolation.
			//Meaning the string above HOME.HELLO would be invalid syntax.
			//It would need to match the following ABOUT.HELLO string.
			'HELLO'     : 'Hello {userName}.',
		}
	});
}]);
```

As I said, this example only nests once based on what page the string appears on. You can choose to do a deeper nesting if it is required. To access nested strings you simply request by nested name `<div translate="HOME.WELCOME"></div>`. If strings appeared more than once I grouped them either in a general category or within a category that was shared for the pages that displayed that translated string. In the example above, I also included another example of using pluralized interpolation (covered in part 1). Again, this assumes that you have included the message format interpolator as explained before. More information about syntax for this format can be found [here](https://github.com/SlexAxton/messageformat.js) and [how to include it](http://angular-translate.github.io/docs/#/guide/14_pluralization).

## Alerts, Pop-Ups, and Drop-downs
In our application, the majority of the alerts and drop-downs were in controllers and services. Angular-translate provides a number of features to assist in this process allowing you to translate text at any level of the application. Passing a key, or a key and the correct values, to the translate module returns the string associated with that key. You can also get information about the current language if you use the $translate.use() function. This allows you to make queries or select information in your database based on the current language.

```javascript
angular.module('sample_app').controller('randomCtrl', 
			['$translate', 'notification',
			function ($translate, notification) {
	'use strict';
	function successCallback (response) {
		$translate('ALERTS_AND_POPUPS.SAVED').then(function (translatedSavedMessage){
			notification.alert(translatedSavedMessage);
		});
	}

	function failureCallback (response) {
		$translate('ALERTS_AND_POPUPS.FAILED', 
		{response.number_of_reasons, response.list_of_reasons}).then(function(translatedFailedMessage){
			notification.error(translatedFailedMessage);
		});
	}
}]);
```

In this example there are no data values passed in the successCallback function, but there are a few passed to the failureCallback. This would assume that these values, and the pluralization rules for the string, are handled in the file of strings. This is not the only way to do alerts as javascript provides many ways to accomplish the same thing, however this is generally how to access the translation features within js code.

Drop-downs are a similar issue; there are several ways this could be accomplished. In the case of the following example, this instance of such a problem only had a few values that could easily be stored in the strings file and so we chose to simply make the lookup return the string's key that could be used to look up the correct value based on the current language.

```javascript
angular.module('sample_app').controller('SignupController',
				['$scope', '$translate', function ($scope, $translate) {
	'use strict';
	var sizes = [{id: 1, translationTag: "SETTINGS_PAGE.EXTRA_SMALL"},
		         {id: 2, translationTag: "SETTINGS_PAGE.SMALL"},
		         {id: 3, translationTag: "SETTINGS_PAGE.MEDIUM"},
		         {id: 4, translationTag: "SETTINGS_PAGE.LARGE"},
		         {id: 4, translationTag: "SETTINGS_PAGE.EXTRA_LARGE"}]
	...
```
		
```html
<div class="input">
	<select name="size_id" ng-model="editor.tshirt.size_id" ng-options="size.id as (size.translationTag | translate) for size in editor.tshirt_sizes" required>
		<option style="display: none;" value=""></option>
	</select>
</div>
```

## Language Selection and User Preference
Most of the language selection can be handled by angular-translate. There are extension packages that handle [cookies or local storage](http://angular-translate.github.io/docs/#/guide/10_storages). It can also determine the preferred language from their browser, redirect certain language keys to keys that you have defined and translated, and provides a way to quickly switch between languages by letting you specify a language key.

```javascript
//Gets the preferred language from the user's browser
var langKey = $translateProvider.determinePreferredLanguage();
//$translateProvider.preferredLanguage('en');

//redirects some language keys to other language keys.
$translateProvider.registerAvailableLanguageKeys(['en', 'es'], {
	'en_US': 'en',
	'en-us': 'en',
	'en_UK': 'en',
	'en-gb': 'en',
	'en-uk': 'en',
	'es-mx': 'es',
	'es-gt': 'es',
	'es-cr': 'es',
});

//changing the current language.
$translate.use("es");
```

This function makes it incredibly easy to save a user’s preferred language key and retrieve it on sign in. It also allows you to quickly toggle the language with input from the user.

## Changes in CSS caused by Translation
{% include full-blog-image.html src="log_in_english.png" alt="AngularJS Translation English" %}

{% include full-blog-image.html src="log_in_spanish.png" alt="AngularJS Translation Spanish" %}

When designing an app that is going to be translated into multiple languages, make sure that you account for changes in css. Phrases in one language may be much longer than another and you need to account for this in the design of your app. Sometimes, you may need to change an element in a specific language and this can be accomplished in css with the html language attribute. At the top of your html file there should be an attribute for the language of the document. This attribute can be placed on other elements as well, but it is typically on the starting html element.

```html
<html lang="en" ng-app="sample_app">
```

This attribute can be updated using the following syntax. This should be updated each time you change the language using the $translate.use() function you should also update this attribute.

```javascript
$translate.use('en');
document.documentElement.lang = $translate.use();
```

Once this works properly you can select elements based on the current language attribute. There are a few css selectors that need to be used for this to work in certain browsers so you may want to include both and test to ensure that it works in your targeted browser. Here I select the elements with some class only if the current language is ‘es’.

```css
.some-class {
	width: 25px;
}

html:lang(es) .some-class
html[lang="es"] .some-class {
	width: 50px;
}
```

## Conclusion
Hopefully this article has helped explain and give examples for some of the features of angular-translate. As you go and translate your app don't forget to check and make sure all strings are being translated properly and that the design after translation looks correct. It can be a tedious process but angular-translate helps to keep it organized and functional. Just a reminder, there are many ways to go about translation and this is not a definitive guide on how to use angular-translate. Do your research and remember to ask the correct questions early so you can ensure that you have the best solution for your app.

<p align="center"><em>Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">The BHW Group</a> is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.</em></p>
		]]></description>

    
        <category>angularjs</category>
    
        <category>localization</category>
    
        <category>translation</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>Translation and Localization with AngularJS</title>
        <link>https://thebhwgroup.com/blog/2015/01/translation-localization-angularjs</link>
		<author>Taylor Smith</author>
		<pubDate>2015-01-05T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/2015/01/translation-localization-angularjs</guid>
		<description><![CDATA[
		   As the world grows closer through the internet, more companies need websites that are translated into other languages. Businesses that target other cultures, nationalities, and languages need a way to provide this feature in a way that is responsive and maintainable. There are many guides and blogs online that refer to this as [i18n (internationalization) and l10n (localization)](http://en.wikipedia.org/wiki/Internationalization_and_localization). This article is the first of two posts and will look at common javascript libraries and tools that can be used for translation services. It will also cover some of the features provided by angular-translate, the library that we chose for one of our apps.

{% include full-blog-image.html src="welcome-translated-map.jpg" alt="AngularJS Translation - Welcome" %}

When deciding how to tackle translation and localization there are many questions that need to be addressed:

- Are you starting from scratch and will this be integrated from the start?
- Are you translating an existing app?
- Will there be language strings stored and used server-side i.e. recurring emails, password reset emails, static dropdown lists stored in a database?
- Are there pieces of data or formatting that need to be entered in the middle of text?
- If there is concatenated data, does the position of the data change when translated into different languages i.e. "You have 7 unread messages"?
- Do users need to be able to quickly switch between languages?
- How is language preference stored?

Being able to answer these questions is important when selecting a library or package. There are many tools for translating and many ways to go about it. You can do it server-side, client-side, or have a mix of both. These questions can help you to think about what you need and how you want to implement i18n and l10n. When deciding which framework to use I researched a few js based libraries. Since I wanted something that worked well with AngularJS we chose angular-translate, but the following is a little bit about other possibilities. Remember that as you look at these and other possibilities you want to find something that includes the proper tools for your situation.

## What's out there?
AngularJS provides some functionality for [i18n](https://docs.angularjs.org/guide/i18n) by allowing different pluralization rules through filters and by allowing users to quickly build custom solutions for string replacement. Custom solutions can be a good way to ensure that everything behaves in the way that you want it to. Obviously, if you build it, you understand what is going on behind the scenes. However, there are also drawbacks to this approach. If you build a custom solution you have to invest time building it. You have to test it to make sure it works. And you have to maintain it. If for example, AngularJS were to change, you would have to make changes accordingly. Also, every feature that you want to add means more time in development and testing. For us it made more sense to use a third party library so that we could focus on our app instead of a translation library.
One promising 3rd party library is the AngularJS localization module [angular-l10n](https://github.com/4vanger/angular-l10n). It provides translations in directives or through filters. It uses interpolations, which allow you to insert values in strings. And it even has a locale switching feature. These are fairly standard features for any translation library and this seems to be a strong contender for an AngularJS compatible library.

Another popular 3rd party library is [angular-translate](https://github.com/angular-translate/angular-translate). We chose this library for a recent conversion of an existing English application into Spanish for a few reasons. This library has a great organization mechanism and easily integrates into an existing AngularJS application. It too has the ability to interpolate values in strings. It has locale switching, asynchronous loading for string files, and allows you to translate through directives, filters, and their $translate service. It also currently has a larger user base and therefore has more guides and questions answered. We chose this over other libraries because there was a lack of functionality with other libraries and building a custom solution would have required a lot of time to test and develop.

There are also many other libraries that are not AngularJS specific including:

- [i18next](http://i18next.com/) a generic javascript library. It provides many of the basic features through data tags and jQuery selectors in place of the AngularJS methods mentioned above.
- [polyglot.js](http://airbnb.github.io/polyglot.js/) a lightweight library targeted toward backbone and node (has no other dependencies). This was designed by the airBnB team and has some promising features for pluralization and interpolation.
- [fnando](https://github.com/fnando/i18n-js) a library that has date and number localization, which are awesome features. But, works with rails applications specifically.
- L20N another generic library with support for pluralization and variable replacement. It seems promising but the syntax is slightly more complicated and it uses element renaming, in the same way that AngularJS does, which might cause confusion with AngularJS directives.

This is not an exhaustive list and there are certainly other options out there that are targeted to other situations or frameworks. However, most of these can be used with AngularJS on the client side of the application, meaning that for the most part, the back end of your service remains unchanged. There are exceptions to this if you want to save language preferences with user data, which I will discuss in part 2.

## How to use angular-translate?
{% include full-blog-image.html src="chalk-translations.jpg" alt="AngularJS Translate chalk" %}

The [introduction](http://angular-translate.github.io/docs/#/guide) provided is fantastic. It is very straightforward despite the English translation being a little funny. If you just want to test it out, follow the directions on the getting started section and you can quickly set up a simple translated site. Once you get a feel for the basics there are a few things that helped me to organize our application and take advantage of the library to the fullest. I will introduce a few of these features in this article and will continue part 2 with more features later.

## String Concatenation/Interpolation
Generally it is not a good practice to divide strings up into sections to be concatenated dynamically. Consider a dynamic number in this string:

 > "You have 3 messages"
 
If you were to concatenate it in javascript it would be in this format:

```javascript
"You have " + number_of_messages +" messages"
```
The problem with this format is that first, the plurality of the sentence would be wrong. Second, when you send this to a translator they may not understand that this is all one phrase. Translation is tricky and words that can mean different things in different contexts can be misunderstood if the phrase is translated piece by piece.
Angular-translate allows you to use variable replacement within strings in the following format:

{% raw  %}
```javascript
"You have {{number_of_messages}} messages"
```
{% endraw  %}

Now the string can be sent to the translator with the entire context. Also, this format can easily be organized into a file of strings. As for the pluralization we need another step. In order to provide pluralization you need to add the [interpolation-messageformat library](http://angular-translate.github.io/docs/#/guide/14_pluralization) (watch out when including this because the default interpolation syntax may change slightly from double curly braces to single curly braces). This changes the interpolation engine that angular-translate uses and the format becomes:

{% raw %}
```javascript
{
	'MESSAGES_TEXT': 'You have {{number_of_messages, plural, one{one message} other{# messages}}.'
}
//With the results of setting the number of messages:
var number_of_messages = 1;
//"You have one message."
number_of_messages = 3;
//"You have 3 messages."
```
{% endraw %}

And for reference if you wanted to use this in context it would be used like so:

As a filter
{% raw %}
```javascript
{{ 'MESSAGES_TEXT' | translate:"{ number_of_messages: '3' }" }}
```
{% endraw %}
With the $translate service

```javascript
$translate('MESSAGES_TEXT', { number_of_messages: '3' });
```
Using the translate directive. Keep in mind that any element could be used in place of span.

```html
<span translate="MESSAGES_TEXT" translate-values="{ number_of_messages: '3' }"></span>
```


## Embedded HTML and AngularJS within strings
Another issue that was solved using this library was using html within strings. For example, if you have a link to some site and you would rather display some text, you would typically use an a tag with text inside.

```html
<div>Looks like you need to <a href="/register" class="register-link">Sign Up!</a>.</div>
```
With angular-translate, using the translate directive we can simply define a string:

```javascript
{
	'SIGNUP_TEXT': 'Looks like you need to <a href="/register" class="register-link">Sign Up!</a>.'
}
```

```html
<div translate="SIGNUP_TEXT"></div>
```

The html will be loaded correctly on translation and will display with the sign up text as the link. This is great because it allows us to send it to the translator and explain that the sentence needs to be translated as a whole, but the link is the only part contained within the `<a>` tags. Or, we could just send the sentence without the tags and decide where to place the tags later based on the spacing or layout of the app.

Another issue I faced a few times was dealing with strings that had AngularJS elements or behavior placed around or within them. Luckily this is also solved with the translate-compile directive. Simply include the AngularJS as it was previously on the page and tag the element accordingly:

```html
<div translate="SIGNUP_TEXT" translate-compile></div>
```
Any AngularJS directives embedded as html in the string will now compile on load of the translation.

## Wrap Up
This has been a quick look at what libraries exist for javascript, with a focus on AngularJS, and an overview of a few features of angular-translate. Look for my next article to learn more about angular-translate in particular and remember that translation can be addressed in almost any language or framework. I encourage you to research and find the best option for your application. If you choose to use the angular-translate library look for part 2 to learn more about string organization, alerts, drop-downs, language selection, and css changes.

<p align="center"><em>Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">The BHW Group</a> is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.</em></p>
		]]></description>

    
        <category>angularjs</category>
    
        <category>localization</category>
    
        <category>translation</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>React, AngularJS, and Om for Single Page Applications</title>
        <link>https://thebhwgroup.com/blog/2014/09/react-angularjs-om-spa</link>
		<author>Brett Burnett</author>
		<pubDate>2014-09-30T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/2014/09/react-angularjs-om-spa</guid>
		<description><![CDATA[
		   ##Overview
In our [first article](https://thebhwgroup.com/blog/2014/08/single-page-applications-clojure-couchdb) on [Single Page Applications](http://en.wikipedia.org/wiki/Single-page_application) we presented a REST JSON API running on Clojure with CouchDB.  In this article we build on the previous article by introducing our client-side application.

##React versus AngularJS
[AngularJS](https://angularjs.org) is a popular Javascript MVC framework.  It's one of our favorite approaches for building web and mobile applications.  

{% include full-blog-image.html src="react_angular.png" alt="AngularJS React Om" %}

Recently one of our clients needed a web application for monitoring data in real-time.  Using AngularJS and [WebSockets](http://en.wikipedia.org/wiki/WebSocket) we built a web application that would update its client-side models as new information was available.  AngularJS was perfect for this problem; however, we were concerned about the performance as the amount of data being monitored increased.  AngularJS uses a digest loop to watch Javascript objects bound to the view so that it can make updates to the HTML DOM when the Javascript variables change, thereby keeping the UI synchronized.  We knew the [digest loop](https://docs.angularjs.org/guide/scope) would slow and our testing showed that we began to see and feel the slowness when we reached around one hundred elements.  Our view contains a large number of model bound fields with additional logic for row coloring, sorting, etc.  A future version of AngularJS will address this performance issue by using [Object.observe()](http://www.html5rocks.com/en/tutorials/es7/observe/), a new JavaScript API that browsers will use to notify subscribers of data changes, allowing the UI state to stay synchronized much more efficiently than current dirty checking methods allow.  Until browsers support this new API an alternative approach is needed for large lists or grids of elements in AngularJS.

Lately there's been a lot of discussion about [Facebook's](http://facebook.github.io/react) React, a Javascript view engine that renders an HTML UI based on a Javascript model.  React is the *V*iew in Javascript MVC and only addresses rendering, unlike AngularJS which includes routing, dependency injection, two-way data-binding, etc.  React is getting a lot of attention because it offers some significant performance gains for view rendering in single page applications (SPA) specifically because it doesn't use a digest like loop to keep the UI and Javascript in sync.  A second benefit for our application is that React only performs view rendering.  It's possible to integrate with AngularJS so that React is used as an alternative to the AngularJS data-bound view module.  This is a great hybrid approach that gives the application the best features of both frameworks.

##ClojureScript and Om
In a recent article we wrote about how we are using Clojure with CouchDB to build a SPA.  Here we continue our original article using [ClojureScript](https://github.com/clojure/clojurescript) for our client-side SPA programming.  ClojureScript is a Clojure compiler that produces Javascript.  Using ClojureScript feels really intuitive, but it would be intimidating to try to use ClojureScript to work with an expressive framework like React.  Luckily the [Om project](https://github.com/swannodette/om) has creted an interface for React.  Using Om we can now build our client-side SPA.  We started this article discussing slow performance of AngularJS rendering with large datasets.  Now let's use ClojureScript and Om to see how our performance changes.

##Setup
First we need a new API call from our original article.  Our new REST API will return all of our records in our first article, instead of returning just one at a time.  We'll add this to our handler.clj file.

```clojure
  (GET "/"
       []
       (load-all))
```

Now to implement our load-all method and return all our CouchDB objects to our client.  The snippet of clojure code below will use sequence to load all the CouchDB entities from our dataset.  Each entity is a pair with the first item being the CouchDB key and the second being our object.  We only want the object data so we use ```second with map to pluck the second element of the pair into a list and return to the client in the body of the get request.

```clojure
(defn load-all
  []
  {:body
   (map #(second %)
        (seq (db)))
   })
```

##Om Client Code
With our server changes above we're now ready to code our Om and ClojureScript client to consume our new REST API.  We'll explain this code snippet after the break.

```clojure
(ns spa-example.cs
  (:require-macros [cljs.core.async.macros :refer [go]])
  (:require [om.core :as om :include-macros true]
            [om.dom :as dom :include-macros true]
            [cljs.core.async :refer [put! chan <!]]
            [ajax.core :refer [GET json-response-format]]))

(def app-state
  (atom
   {:teams nil}))

(defn teams-view [app owner]
  (reify
    om/IRender
    (render [this]
            (apply dom/tbody nil
                   (map-indexed (fn [idx t]
                                  (let [{:keys [team goals_for goals_against win loss draw points goal_diff games]} t]
                                    (let [cols [(+ idx 1) team win loss draw goals_for goals_against goal_diff games points]]
                                      (apply dom/tr nil
                                             (for [r cols]
                                               (dom/td nil r))))))
                                (sort-by :points #(compare %2 %1) (:teams app)))))))

(defn app-state-error [response]
  (.error js/console (:message response)))

(defn app-state-handler [response]
  (swap! app-state assoc :teams response)
  (om/root teams-view app-state
           {:target (. js/document (getElementById "content"))}))

(GET "/" {:handler app-state-handler :error-handler: app-state-error
              :response-format (json-response-format {:keywords? true})})
```

Starting from the top, we declare our namespace in our client just like we would in a server-side clojure program.  Here we are requiring Om and parts of ClojureScript to make our lives a little easier.  

Next up we create our app-state.  This atom stores our client-side application state, compared to angular this would be similar to an AngularJS scope.

After the app-state comes our function that defines a React component teams-view .  Our teams-view function creates a new React component.  Here our component creates a table body and the uses map to build the individual rows and columns of our table based on the data in the teams element of our app-state.

app-state-error and app-state-handler are the failure and success callback from the GET function that hits our server-side Clojure REST API.  When GET is called it returns data to the app-state-handler.  This data is swapped into our app-state, completely replacing whatever is there.  The app-state-handler also calls om/root which renders our React component into the element named "content".

##Om HTML File
Below is our Om HTML file.  This file sets up the target for our React component when it is rendered.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"></meta>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>React Tutorial Rewritten in OM</title>
  </head>
  <body>
    <!-- entry point for components -->

    <table>
  	<thead>
  		<tr>
  			<th>Rank</th>
  			<th>Nation</th>
  			<th>W</th>
  			<th>L</th>
  			<th>D</th>
  			<th>GF</th>
  			<th>GA</th>
  			<th>GD</th>
  			<th>GP</th>
  			<th>Points</th>
  		</tr>
  	</thead>
  	<tbody id="content">
    </tbody>
    </table>
    <!--<script type="text/javascript">
        var CLOSURE_NO_DEPS = true;
    </script> -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.1/react.js"></script>
    <script src="js/client.js" type="text/javascript"></script>
  </body>
</html>
```

##AngularJS
Now that we've explained the React and Om approach, let's show this same solution using AngularJS.  First we'll start with our AngularJS HTML file with our declarative markup.

```html
<!DOCTYPE html>
<html ng-app="worldCupApp">
<head>
	<title>AngularJS Performance Test</title>
</head>
<body ng-controller="ScoreController">

{% raw %}
<table>
	<thead>
		<tr>
			<th>Rank</th>
			<th>Nation</th>
			<th>W</th>
			<th>L</th>
			<th>D</th>
			<th>GF</th>
			<th>GA</th>
			<th>GD</th>
			<th>GP</th>
			<th>Points</th>
		</tr>
	</thead>
	<tbody>
		<tr ng-repeat="(index,team) in teams | orderBy:points:true">
			<td>{{index + 1}}</td>
			<td>{{team.team}}</td>	
			<td>{{team.win}}</td>
			<td>{{team.loss}}</td>
			<td>{{team.draw}}</td>
			<td>{{team.goals_for}}</td>
			<td>{{team.goals_against}}</td>
			<td>{{team.goal_diff}}</td>
			<td>{{team.games}}</td>
			<td>{{team.points}}</td>
		</tr>
		<tr>
			<td colspan="9">&nbsp;</td>
			<td>{{total()}}</td>
		</tr>
	</tbody>	
</table>
{% endraw %}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<script type="text/javascript" src="client/app.js"></script>
</body>
</html>
```

Now for our AngularJS controller

```javascript
(function() {
	'use strict';

	var worldcupApp = angular.module('worldCupApp', []);
	worldcupApp.controller('ScoreController', function($scope, $q, $http, $filter ){

		$scope.teams = [];

		$scope.init = function(){
			$http.get('http://localhost:3000/').then(function(result){
				$scope.teams = result.data;
			}, function(error){
				console.log(error);
			});
		};

		$scope.points = function(team){
			return team.points;
		};

		$scope.sortedTeams = function(){
			return $filter('orderby')($scope.teams, $scope.points, true);
		};

		$scope.total = function(){
			var total = 0.0;
			angular.forEach($scope.teams, function(t){
				total += t.points;
			});
			return total;
		};

		$scope.init();
	});
}());
```

Just like React, Angular makes an AJAX call to the Clojure REST API to load the dataset.  It renders the results using a declarative approach in the HTML and only uses a few Javascript helper functions to do some aggregate calculations.

##Conclusion
In this article we've shown just how simple it is to build a React view using Om with ClojureScript.  We've also set the stage for our final article which discusses the performance difference between the two approaches, AngularJS vs Om.  AngularJS is known for having a difficult learning curve, and Om is no different.  In addition to being comfortable with React you also require knowledge of Clojure and ClojureScript, both large topics on their own.  For teams considering an investment in Clojure, this is an easy trade and will help build your Clojure competency faster.  In the next article we'll also expand on our Om example and bring in channels which will allow our UI to respond to changes in the data structures we are displaying.

<p align="center"><em>Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">The BHW Group</a> is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.</em></p>
		]]></description>

    
        <category>angularjs</category>
    
        <category>couchdb</category>
    
        <category>clojure</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>AngularJS and HTML Form Design - Part 2</title>
        <link>https://thebhwgroup.com/blog/2014/08/angularjs-html-form-design-part-2</link>
		<author>Clayton Anderson</author>
		<pubDate>2014-08-27T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/2014/08/angularjs-html-form-design-part-2</guid>
		<description><![CDATA[
		   ## Introduction

Welcome back! In this series, we are exploring how to design HTML forms with AngularJS, with the best user experience in mind. If you missed part 1, you can find that [here](https://thebhwgroup.com/blog/2014/08/designing-html-forms-angularjs-part-1/). In part 2, we will take a deeper look at a couple more complicated validation scenarios.

## A Quick Note about Submitted CSS

Forms in AngularJS 1.3 are getting a built-in feature very similar to the way we set up our `submitted` boolean and CSS in part 1. You can take a look at the [github commit](https://github.com/angular/angular.js/commit/108a69be17df5884d026c57b2be3235c576250fe) if you're interested in seeing how they integrated it with the framework. 1.3 is still in beta, so I'm going to stick with 1.2 for part 2, but I have changed the **submitted** class name to **ng-submitted** to match how AngularJS 1.3 will work.

```html
...
<form class="form-demo" ng-submit="submit()" ng-class="{ 'ng-submitted': submitted }" name="contactForm" novalidate>
...
</form>
...
```

```css
...
.ng-submitted input.ng-invalid {
    border: 1px solid #f00;
    background-color: #fee;
}
...
```

I also got a great comment [on reddit](http://www.reddit.com/r/angularjs/comments/2d8o1q/an_introduction_angularjs_and_html_form_design/) after part 1 went up about not repeating the submitted check in each of the validation messages. I made a small CSS change to factor out the submitted check in each of the validation messages.

```css
...
.form-demo:not(.ng-submitted) .validation-message {
    display: none;
}
...
```

On to the article!

## Step 1. Conditional Validation

At the end of part 1, this is what our contact object looked like.

```javascript
{
    firstName: '',
    lastName: '',
    email: ''
}
```

The firstName and lastName fields were required, with a max length of 20 characters. The only rule on the email field was that it had to be a valid email address.

Let's repurpose our contact form a bit by making it a newsletter sign-up form. After adding a boolean to track whether the contact wants to receive emails, our object looks like this.

```javascript
{
    firstName: '',
    lastName: '',
    receiveEmails: false,
    email: ''
}
```

All of our inputs so far have been text (or email, which is very similar to text) fields. Adding a checkbox to track the new `receiveEmails` boolean is as easy as adding an input element with the **type** attribute set to "checkbox".

```html
...
<div>
    <label>
        <input type="checkbox" name="receiveEmails" ng-model="newContact.receiveEmails" />
        I want to receive emails
    </label>
</div>
...
```

Here's what that looks like.

{% include full-blog-image.html src="checkbox.png" alt="AngularJS form" %}

Now we can require an email address, but only if the user wants to receive emails. They should still be able to enter an address either way though, and the email validation should still apply. AngularJS makes this easy to do. Remember how we added the **required** attribute to the firstName and lastName elements? AngularJS provides the **ng-required** directive, which you can pass an expression to. If the expression is truthy, then the field will be required.

```html
...
<div>
    <label>
        Email
        <input type="email" name="email" ng-model="newContact.email" ng-required="newContact.receiveEmails" />
        <span class="validation-message" ng-show="contactForm.email.$error.email">
            Invalid email
        </span>
        <span class="validation-message" ng-show="contactForm.email.$error.required">
            Required
        </span>
    </label>
</div>
...
```

In our case, we are passing `newContact.receiveEmails` to the **ng-required** directive. Since our checkbox is bound to that boolean, the validation will immediately recognize when it has changed and make the field required or not.

Go ahead and give it a try. Our existing email validation works as before, but now the field is conditionally required. Notice that we added another validation message for when the email is required.

{% include full-blog-image.html src="email-required.png" alt="AngularJS required" %}

## Step 2. Repetition

What if we wanted to submit multiple contacts at once? Before we get to the view, let's make a quick controller change. Instead of tracking a single `newContact` object, now we want an array of contacts.

```javascript
(function() {
    'use strict';

    var module = angular.module('form-demo');

    function ContactController($scope, $window, Contact) {
        function success() {
            $window.alert('Contacts saved successfully!');
        }

        function failure() {
            $window.alert('Oops!');
        }

        $scope.contacts = [];
        $scope.submitted = false;
        $scope.submitting = false;

        $scope.addContact = function() {
            $scope.contacts.push({});
        };

        $scope.removeContact = function(index) {
            $scope.contacts.splice(index, 1);
        };

        $scope.submit = function() {
            $scope.submitted = true;

            if ($scope.contactForm.$valid) {
                $scope.submitting = true;
                Contact.save($scope.contacts)
                    .then(success, failure)
                    .then(function() {
                        $scope.submitting = false;
                    });
            } else {
                $window.alert('Please fix any validation errors and try again.');
            }
        };
    }

    module.controller('ContactController', ['$scope', '$window', 'Contact', ContactController]);
}());
```

Not too much changed here. We've removed the `newContact` object, added a `contacts` array, and added two functions for adding and removing from the array - both published on the scope. `addContact` will add an empty contact, and `removeContact` removes the contact at the passed in `index`. We'll call both of these functions from our view.

Since our backend is just a timeout statement, we don't need to make any changes to our factory for this demo page.

Let's update our view to use an **ng-repeat**. This directive allows us to make minimal changes to our HTML, but gives our form the ability to handle any number of contacts. **ng-repeat** is one of the most important parts of AngularJS, so if you are interested in reading more about it, the [AngularJS documentation](https://docs.angularjs.org/api/ng/directive/ngRepeat) is a good starting point.

```html
...
<form class="form-demo" ng-submit="submit()" ng-class="{ 'ng-submitted': submitted }" name="contactForm" novalidate>
    <div ng-repeat="contact in contacts">
        <strong>Contact {% raw %}{{ $index }}{% endraw %}</strong>
        <button type="button" ng-click="removeContact($index)">Remove</button>

        <div>
            <label>
                First Name
                <input type="text" name="firstName" ng-model="contact.firstName" required ng-maxlength="20" />
                <span class="validation-message" ng-show="contactForm.firstName.$error.required">
                    Required
                </span>
                <span class="validation-message" ng-show="contactForm.firstName.$error.maxlength">
                    Max length 20
                </span>
            </label>
        </div>

        <div>
            <label>
                Last Name
                <input type="text" name="lastName" ng-model="contact.lastName" required ng-maxlength="20" />
                <span class="validation-message" ng-show="contactForm.lastName.$error.required">
                    Required
                </span>
                <span class="validation-message" ng-show="contactForm.lastName.$error.maxlength">
                    Max length 20
                </span>
            </label>
        </div>

        <div>
            <label>
                <input type="checkbox" name="receiveEmails" ng-model="contact.receiveEmails" />
                I want to receive emails
            </label>
        </div>

        <div>
            <label>
                Email
                <input type="email" name="email" ng-model="contact.email" ng-required="contact.receiveEmails" />
                <span class="validation-message" ng-show="contactForm.email.$error.email">
                    Invalid email
                </span>
                <span class="validation-message" ng-show="contactForm.email.$error.required">
                    Required
                </span>
            </label>
        </div>

        <br />
    </div>

    <div>
        <button type="button" ng-click="addContact()">Add contact</button>
        <button type="submit" ng-disabled="submitting" ng-switch="submitting">
            <span ng-switch-default>Submit</span>
            <span ng-switch-when="true">Submitting...</span>
        </button>
    </div>
</form>
...
```

Here's what we changed. The inputs have now been wrapped with a div with an **ng-repeat** on it. Each iteration of the `contacts` collection is aliased as `contact`, so all the places in our view that referenced `newContact` before are now `contact`. Each iteration has a button to remove that contact, and a label showing the index (Note that we use `$index` here - this is a feature of **ng-repeat**. AngularJS provides a number of other [special properties](https://docs.angularjs.org/api/ng/directive/ngRepeat).) Also, we added a button at the bottom to add a contact to the array.

For now, the page starts with no contacts in the collection. In the real world, we would probably want to have one empty contact object already added to the array.

Here's what the page should look like right now, after adding a couple contacts.

{% include full-blog-image.html src="form1.png" alt="AngularJS form" %}

Something isn't quite right though. If you play around with the validation, you'll notice that when there are multiple contacts, the validation messages show up at times they shouldn't.

{% include full-blog-image.html src="form-invalid.png" alt="AngularJS form invalid" %}

In this screenshot, the "Required" message is showing up for the first contact's first name, despite the field being filled out. What is going on here?

Take a look at one of our validation messages.

```html
...
<span class="validation-message" ng-show="contactForm.firstName.$error.required">
    Required
</span>
...
```

Our **ng-show** expression is referencing `contactForm.firstName`. Spot the issue? Now that our `firstName` input repeats, with the same name each time, our **ng-show** expression no longer references the validation of a single `firstName`, but rather the validation of *each* `firstName`. Try filling out the fields for the second contact and you'll see that the required messages appear and disappear for all contacts at once.

So what can we do here? If you come from a jQuery background, your first thought is probably to dynamically assign names to the inputs based on what iteration they are in. AngularJS provides a more idiomatic way, through the use of [**ng-form**](https://docs.angularjs.org/api/ng/directive/ngForm).

With **ng-form** we can create a separate form instance for each iteration of our **ng-repeat**.

```html
...
<form class="form-demo" ng-submit="submit()" ng-class="{ 'ng-submitted': submitted }" name="contactForm" novalidate>
    <div ng-repeat="contact in contacts" ng-form="repeatForm">
        <strong>Contact {% raw %}{{ $index }}{% endraw %}</strong>
        <button type="button" ng-click="removeContact($index)">Remove</button>

        <div>
            <label>
                First Name
                <input type="text" name="firstName" ng-model="contact.firstName" required ng-maxlength="20" />
                <span class="validation-message" ng-show="repeatForm.firstName.$error.required">
                    Required
                </span>
                <span class="validation-message" ng-show="repeatForm.firstName.$error.maxlength">
                    Max length 20
                </span>
            </label>
        </div>

        <div>
            <label>
                Last Name
                <input type="text" name="lastName" ng-model="contact.lastName" required ng-maxlength="20" />
                <span class="validation-message" ng-show="repeatForm.lastName.$error.required">
                    Required
                </span>
                <span class="validation-message" ng-show="repeatForm.lastName.$error.maxlength">
                    Max length 20
                </span>
            </label>
        </div>

        <div>
            <label>
                <input type="checkbox" name="receiveEmails" ng-model="contact.receiveEmails" />
                I want to receive emails
            </label>
        </div>

        <div>
            <label>
                Email
                <input type="email" name="email" ng-model="contact.email" ng-required="contact.receiveEmails" />
                <span class="validation-message" ng-show="repeatForm.email.$error.email">
                    Invalid email
                </span>
                <span class="validation-message" ng-show="repeatForm.email.$error.required">
                    Required
                </span>
            </label>
        </div>

        <br />
    </div>

    <div>
        <button type="button" ng-click="addContact()">Add contact</button>
        <button type="submit" ng-disabled="submitting" ng-switch="submitting">
            <span ng-switch-default>Submit</span>
            <span ng-switch-when="true">Submitting...</span>
        </button>
    </div>
</form>
...
```

Each iteration's form is now aliased as `repeatForm`. If you open up the demo page the validation should be working correctly now, for each contact. One of the awesome things about this is that when AngularJS checks form validity, it will check any nested **ng-forms**. So in our controller, when we check `$scope.contactForm.$valid`, it automatically checks the validity of each contact without us needing to make a single code change!

{% include full-blog-image.html src="form-correct.png" alt="AngularJS form " %}

## Conclusion

That wraps up our AngularJS form design series. I hope this series helped you begin or progress your AngularJS journey! It certainly doesn't have to be the end though, here's a few ideas you could explore next.

- [Learn the full set of built-in AngularJS validation attributes](https://docs.angularjs.org/api/ng/directive/input)
- [Create your own validation rules with custom directives](https://docs.angularjs.org/guide/directive)
- [Hook up a service / factory to a REST API](https://docs.angularjs.org/api/ngResource/service/$resource)

<p align="center"><em>Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">The BHW Group</a> is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.</em></p>

		]]></description>

    
        <category>angularjs</category>
    
        <category>form</category>
    
        <category>html5</category>
    
        <category>validation</category>
    
    
        <category>Development</category>
    

	  </item>
    
	  <item>
        <title>AngularJS and HTML Form Design - Part 1</title>
        <link>https://thebhwgroup.com/blog/2014/08/designing-html-forms-angularjs-part-1</link>
		<author>Clayton Anderson</author>
		<pubDate>2014-08-11T00:00:00+00:00</pubDate>
		<guid isPermaLink="true">https://thebhwgroup.com/blog/2014/08/designing-html-forms-angularjs-part-1</guid>
		<description><![CDATA[
		   ## Introduction

One of the greatest benefits we have seen when creating single page applications with AngularJS is how much faster and easier it is to design forms, even those with complex validation.

This will be a multi-part series covering all the best practices we have picked up when designing HTML forms. Part 1 will provide step by step instructions for building a simple and user-friendly contact information form with AngularJS. In part 2 we will dig deeper into some of the more complex validation and form logic. 

This series assumes some level of AngularJS familiarity, but is intended for novices and veterans alike. I will be including links to the concepts that might be unfamiliar to beginners. Let's begin!

## Step 1. The Building Blocks

I always like starting with the data when I begin coding a new feature, so let's define what our contact object will look like. 

```javascript
{
	firstName: '',
	lastName: '',
	email: ''
}
```

That's a pretty simple object. We are going to start small and add more properties in part 2.

Next, we create an AngularJS factory for saving contacts to a data store. For this article we aren't particularly concerned with a backend implementation, so our factory will just delay for a moment before resolving.

```javascript
(function() {
	'use strict';

	var module = angular.module('form-demo');

	function ContactFactory($q, $timeout) {
		return {
			save: function(contact) {
				var deferred = $q.defer();
				$timeout(deferred.resolve, 1000);
				return deferred.promise;
			}
		};
	}

	module.factory('Contact', ['$q', '$timeout', ContactFactory]);
}());
```

A couple things to note about our factory:

 - If you're more comfortable with the AngularJS service syntax, feel free to use a service instead of a factory. [They both accomplish the same thing](https://stackoverflow.com/questions/14324451/angular-service-vs-angular-factory).
 - Our save function returns a promise. If promises are new to you, or you aren't using them in your AngularJS projects, I would recommend checking out the [$q documentation](https://docs.angularjs.org/api/ng/service/$q).
 - We are using the minification-friendly form of dependency injection. If you aren't familiar with this, you can read about it [at the AngularJS documentation](https://docs.angularjs.org/tutorial/step_05). Just scroll down to the "A Note on Minification" section.

Now we can create our controller.

```javascript
(function() {
	'use strict';

	var module = angular.module('form-demo');

	function ContactController($scope, $window, Contact) {
		function success() {
			$window.alert('Contact saved successfully!');
		}

		function failure() {
			$window.alert('Oops!');
		}

		$scope.newContact = {};

		$scope.submit = function() {
			Contact.save($scope.newContact)
				.then(success, failure);
		};
	}

	module.controller('ContactController', ['$scope', '$window', 'Contact', ContactController]);
}());
```

The controller is pretty straightforward. We publish our `newContact` object to the scope, along with a submit function that will pass along the contact to our factory. For after the factory save resolves, we define callbacks for success or failure.

On to the HTML!

```html
<!DOCTYPE html>
<html lang="en" ng-app="form-demo">
	<head>
		<title>Form Demo</title>
	</head>
	<body ng-controller="ContactController">
		<form ng-submit="submit()">
			<div>
				<label>
					First Name
					<input type="text" ng-model="newContact.firstName" />
				</label>
			</div>

			<div>
				<label>
					Last Name
					<input type="text" ng-model="newContact.lastName" />
				</label>
			</div>

			<div>
				<label>
					Email
					<input type="email" ng-model="newContact.email" />
				</label>
			</div>

			<div>
				<button type="submit">Submit</button>
			</div>
		</form>

		<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.js"></script>
		<script>
			angular.module('form-demo', []);
		</script>
		<script src="contact-service.js"></script>
		<script src="contact-controller.js"></script>
	</body>
</html>
```

The HTML is mostly AngularJS boilerplate, but do notice the `ng-submit` attribute on the form element. If we had put an `ng-click` on the submit button instead, the form wouldn't submit if the user pressed the enter key while focusing an input. With `ng-submit` on the form you provide a nicer user experience.

If you're following along, you should be able to pull up the demo page and try it out. 

{% include full-blog-image.html src="form.png" alt="AngularJS form" %}

Submitting the form will trigger a success message, after a one second delay. 

{% include full-blog-image.html src="success.png" alt="AngularJS submit" %}

Progress! There is a lot missing though. We haven't provided any validation yet, there is no indication that the form is submitting, and it doesn't prevent the user from submitting multiple times in quick succession. Fortunately, AngularJS will make adding each piece easy.

## Step 2. AngularJS Validation

Depending on your browser and what you entered in the form, you may see something like this when you submit.

{% include full-blog-image.html src="invalid-email.png" alt="AngularJS invalid" %}

Some browsers include built-in form validation. In my screenshot, I entered an invalid email address so Chrome prevented the submit from firing. We want to use our own validation logic through AngularJS, so that the user experience is consistent across all browsers. HTML5 makes disabling the browser validation easy.

```html
...
<form ng-submit="submit()" novalidate>
	...
</form>
...
```

Adding the `novalidate` attribute to the form will prevent the browser from using built-in validation. 

Before validation will work, we need to make another HTML change. In AngularJS, if you add a name to a form, that instance of [FormController](https://docs.angularjs.org/api/ng/type/form.FormController) will be published on the scope. Once the form instance is on the scope, we can check for validity in our submit handler before sending the contact to the data store.

```html
...
<form ng-submit="submit()" name="contactForm" novalidate>
	...
</form>
...
```

The form can now be accessed inside the controller through `$scope.contactForm`.

```javascript
...
$scope.submit = function() {
	if ($scope.contactForm.$valid) {
		Contact.save($scope.newContact)
			.then(success, failure);
	} else {
		$window.alert('Please fix any validation errors and try again.');
	}
};
...
```

If you try submitting the form now with an invalid email, you should see an alert asking you to fix any validation errors and submit again. You might be wondering how AngularJS knows the form is invalid when we haven't added any validation rules yet. It turns out AngularJS looks at the types of your inputs and includes some rules automatically, so just from specifying `type="email"` we already have some working validation.

{% include full-blog-image.html src="error-popup.png" alt="AngularJS error popup" %}

Let's add a few more validation rules to the form.

```html
...
<div>
	<label>
		First Name
		<input type="text" ng-model="newContact.firstName" required ng-maxlength="20" />
	</label>
</div>

<div>
	<label>
		Last Name
		<input type="text" ng-model="newContact.lastName" required ng-maxlength="20" />
	</label>
</div>
...
```

We've made the first and last name fields required, with a maximum length of 20. The `$scope.contactForm.$valid` property that we used earlier will automatically reflect the state of all validation rules in the form, even as we add new rules. Submitting with an invalid first or last name will result in the same message as for the email address. 

Our form is coming along nicely, but the user experience could still be greatly improved. Right now, the user has no way of knowing what fields are invalid, and doesn't receive any feedback until they submit the form.

## Step 3. Validation Messages and Styling

As a user, one of the most frustrating experiences with a form is when the page says there is a validation error, but won't say what fields have errors. It has become common practice to highlight invalid fields, usually in red. AngularJS makes this really easy, by automatically applying classes to an input based on their validity. The two most important are **ng-valid** and **ng-invalid**. With a little bit of CSS, our form is suddenly much friendlier!

```css
input.ng-invalid {
	border: 1px solid #f00;
	background-color: #fee;
}
```

{% include full-blog-image.html src="invalid-highlight.png" alt="AngularJS validation highlighting" %}

Let's add some messages now to tell the user exactly what their validation errors are, so they don't have to guess what's wrong. 

Recall that after we put a name on the form element, the form instance was published on the scope. Similarly, if we add names to the inputs, we'll be able to check the validity of each rule for each input. 

First, add the names.

```html
...
<input type="text" name="firstName" ng-model="newContact.firstName" required ng-maxlength="20" />
...
<input type="text" name="lastName" ng-model="newContact.lastName" required ng-maxlength="20" />
...
<input type="email" name="email" ng-model="newContact.email" />
...
```

We can now check the validity of each rule with `$scope.contactForm.inputName.$error`. For example, if we want to check the errors on the firstName field we use this statement.

```javascript
$scope.contactForm.firstName.$error
```

Which will reference an object similar to this one.

```javascript
{
	required: true,
	maxlength: false
}
```

This is an example of what is so great about AngularJS. These fields are automatically updated by the framework, so we just have to watch them in our view. We can be far more declarative with our validation code than with something like jQuery Validate. Here's how to add error messages to the form. No code changes needed!

```html
...
<div>
	<label>
		First Name
		<input type="text" name="firstName" ng-model="newContact.firstName" required ng-maxlength="20" />
		<span class="validation-message" ng-show="contactForm.firstName.$error.required">Required</span>
		<span class="validation-message" ng-show="contactForm.firstName.$error.maxlength">Max length 20</span>
	</label>
</div>

<div>
	<label>
		Last Name
		<input type="text" name="lastName" ng-model="newContact.lastName" required ng-maxlength="20" />
		<span class="validation-message" ng-show="contactForm.lastName.$error.required">Required</span>
		<span class="validation-message" ng-show="contactForm.lastName.$error.maxlength">Max length 20</span>
	</label>
</div>

<div>
	<label>
		Email
		<input type="email" name="email" ng-model="newContact.email" />
		<span class="validation-message" ng-show="contactForm.email.$error.email">Invalid email</span>
	</label>
</div>
...
```

And a quick style addition to go with it.

```css
...
.validation-message {
	color: #f00;
}
```

{% include full-blog-image.html src="messages.png" alt="AngularJS validation message" %}

We're getting close! In the next section we'll make some more usability improvements.

## Step 4. Form Submission Tracking

Although our form does a good job of informing the user of errors, it looks a little scary for a new user to open a form for the first time and see error messages before even typing anything. It is a common practice to wait to show validation error messages and styles until after the user has attempted to submit the form. 

Let's add a `submitted` boolean to our controller to track whether the user has attempted to submit the form.

```javascript
...
$scope.submitted = false;

$scope.submit = function() {
	$scope.submitted = true;
	
	if ($scope.contactForm.$valid) {
		Contact.save($scope.newContact)
			.then(success, failure);
	} else {
		$window.alert('Please fix any validation errors and try again.');
	}
};
...
```

Now we can conditionally apply a **submitted** class to our form with the `ng-class` directive.


```html
...
<form ng-submit="submit()" ng-class="{ submitted: submitted }" name="contactForm" novalidate>
   ...
</form>
...
```


There are a few different ways to use `ng-class`, but here we are using it with an object. The way that `ng-class` works with an object is that for each key-value pair in the object, if the value is truthy, then the key is added as a class to the element. So on our form, if the `submitted` boolean that we just added to the controller is true, then the form will have a **submitted** class added to it. If the `submitted` boolean is false, then the class will be removed.

If you're interested in reading more about the different ways to use `ng-class`, [you can find that at the AngularJS documentation](https://docs.angularjs.org/api/ng/directive/ngClass).

Next, we add a check for the `submitted` boolean in our validation message `ng-show` conditions.

```html
...
<span class="validation-message" ng-show="submitted && contactForm.firstName.$error.required">Required</span>
<span class="validation-message" ng-show="submitted && contactForm.firstName.$error.maxlength">Max length 20</span>
...
<span class="validation-message" ng-show="submitted && contactForm.lastName.$error.required">Required</span>
<span class="validation-message" ng-show="submitted && contactForm.lastName.$error.maxlength">Max length 20</span>
...
<span class="validation-message" ng-show="submitted && contactForm.email.$error.email">Invalid email</span>
...
```

And with a quick style change, our form now waits to show errors until after the user has attempted to submit.

```css
.submitted input.ng-invalid {
	border: 1px solid #f00;
	background-color: #fee;
}
```

There's one major piece of good form design we haven't gotten to yet. Right now, our form doesn't provide any indication that it is submitting, and it doesn't prevent multiple submits. 

Let's add another boolean to our controller, this time to track whether the form is currently submitting. We'll call it `submitting`.

```javascript
...
$scope.submitted = false;
$scope.submitting = false;

$scope.submit = function() {
	$scope.submitted = true;

	if ($scope.contactForm.$valid) {
		$scope.submitting = true;
		Contact.save($scope.newContact)
			.then(success, failure)
			.then(function() {
				$scope.submitting = false;
			});
	} else {
		$window.alert('Please fix any validation errors and try again.');
	}
};
...
```

Nothing too complicated here, we just set the `submitting` boolean to true when we hand things off to our save function. After the save promise resolves, we then set it back to false. 

(As an aside, if you haven't used promise chains before and are interested in learning more, be sure to watch this [excellent egghead.io video](https://egghead.io/lessons/angularjs-chained-promises).)

With a small change to our button, we have our desired functionality!

```html
...
<button type="submit" ng-disabled="submitting" ng-switch="submitting">
	<span ng-switch-default>Submit</span>
	<span ng-switch-when="true">Submitting...</span>
</button>
...
```

{% include full-blog-image.html src="submitting.png" alt="AngularJS submitting" %}

Our button is now disabled while the form submits thanks to `ng-disabled`, and it changes text thanks to `ng-switch`. Feel free to use a spinner instead of text while submitting.

## Conclusion

It's simple, but I think our form is working pretty nicely. If you want to keep working on it you could add some more styles or hook up the factory to a real data store. 

This wraps up part 1 - keep an eye out for part 2, where we will delve into some more complicated form logic!

<p align="center"><em>Do you need an expert in web development? With a team of web development specialists covering a wide range of skill sets and backgrounds, <a href="https://thebhwgroup.com/services/web-application-development-company-austin-texas" target="_blank">The BHW Group</a> is prepared to help your company make the transformations needed to remain competitive in today’s high-tech marketplace.</em></p>
		]]></description>

    
        <category>angularjs</category>
    
        <category>form</category>
    
        <category>html5</category>
    
        <category>validation</category>
    
    
        <category>Development</category>
    

	  </item>
    
  </channel>
</rss>
