Super-Easy Angular Image Gallery

This entry is part 9 of 9 in the series: AngularJS Learning Series

Check it out!

Learning Angular has been a fantastic experience so far. I’ve been consistently surprised at the results I can get from a screenful of code. This week’s Image Gallery experiment was no different. Before I get into the particulars, let’s take a look at the finished product:

[iframe src=”″ height=”565″ width=”675″]

If you check out the source app.js on that example you’ll notice that the JavaScript adds up to about 25 lines of code, half of which are dedicated to loading and setting the data source. Yes, there’s some CSS3 transition coolness thrown in, but even that is minimal.

So How Does It Work?

The gallery is made up of three sections: the main image, the caption, and the thumbnails. If you compare the main image section and the thumbnail section you’ll see that they’re very similar. The main difference being the size of the image how many of the image you can see:

<div class="mainimageshell">
    <div class="viewwindow">
        <ul id="fullscroller" class="fullsizelist" ng-style="listposition" >
            <li ng-repeat="image in galleryData">
                <img id="fullsize" class="large" ng-src="{{image.image}}" />

<div class="captionshell">
    <p class="caption">{{selected.desc}}</p>

<div class="thumbsshell">
    <div class="thumbswrapper">
            <li ng-repeat="image in galleryData">
                <div class="thumbwrapper">
                    <a ng-href="" ng-click="scrollTo(image,$index)">
                        <img class="thumbnail" ng-src="{{image.image}}" />

If you were to comment out the overflow line of the viewwindow class you would see all of the images lined up side by side, just like the thumbnails.

When iterating over the data using ng-repeat, $index will reflect the zero-based index of each item. Since we’re looping over the same data, the index for both the large image and the thumbnail will be the same. This allows me to multiply the index by the width of the images to arrive at the new positioning for the large image list. Once I specify the new positioning, my CSS handles the transition, something like this:

    transition:  left .8s ease;

Thanks to Angular, notifying the DOM element of its new position is ultra-simple. If you take a look at the fullscroller UL inside the template you’ll see that it contains the Angular ng-style directive and that it’s bound to the listposition property. Listposition is updated in the scrollTo function every time a thumbnail is clicked and any change is immediately reflected in the view:

// Scroll to appropriate position based on image index and width
$scope.scrollTo = function(image,ind) {
    $scope.listposition = {left:(IMAGE_WIDTH * ind * -1) + "px"};
    $scope.selected = image;

In addition to modifying the viewwindow position, the scrollTo function also assigns the currently selected item to $scope.selected. If you look at the template you’ll see that caption is rendering “{{selected.desc}}”. When $scope.selected is changed, the caption will automatically change with it.

Full Disclosure

My original idea was to fade out the old image and fade in the new image when a thumbnail was clicked. This worked great on Chrome, but Firefox would flash the image on screen once loaded and wouldn’t transition in properly. It also required transition end listeners, which at the moment are not standard across browsers. That meant separate listeners for each browser engine.

The whole thing was becoming a hassle and the code was getting unruly. That’s when I made the decision to switch to a slider and it worked out great. Point being, don’t be afraid to experiment or refactor. Oftentimes the best coding decisions are born out of a change in approach.

Responsive Form Validation with AngularJS and HTML5

This entry is part 6 of 9 in the series: AngularJS Learning Series

This AngularJS example demonstrates how HTML5 and AngularJS can work together to provide a modern approach to form submission and validation without lengthy JavaScript validation algorithms, cumbersome CSS, or page refreshes.

Note that there are multiple ways to present and submit a form using HTML5 and AngularJS. Your implementation should depend on the needs of your application. The method I use here does not perform an actual submit. Instead, when the Submit button is clicked it calls a function that updates a visitorInfo object. Any action can be performed when the visitorInfo object is updated by modifying the update function in VisitorFormController in app.js.

The example provides immediate feedback based on the data entered into the input fields. Every input field has been flagged as “required” and you can watch the debugging info to see the status change dynamically as each input field is populated.

[iajsfiddle fiddle=”CUzbs” height=”400px” width=”100%” show=”result,html,js,css,resources” skin=”default”]

Let’s take a closer look at the email section to see how this is done:

<span class="label">Email:</span>
<input type="email" name="email" placeholder="Email" required="" />
<span class="valid">?</span>

The first line is simply the label that is show before the input field. The “label” class lets me apply some styling to keep it on the same line as the input field, make it bold, etc. No magic there.

The input field has several attributes. Name gives us a means of referring to that specific field. Type defaults to “text” but we’ve given it the HTML5 type of “email”. Doing so implements validation rules, such as requiring an & and a domain type (like .COM). It also causes responsive mobile devices to present different UI. For example, assigning a type of email will cause “.COM” to appear on keyboards of many mobile devices.

The ngModel directive links the input field to a scope property, in this case visitorInfo is an object that holds all of the form properties. Notice that each input field model includes visitorInfo before the property name. You can watch visitorInfo populate in the debugging info as you fill in the form.

Placeholder is a new input attribute that allows you to define a short data entry hint that will appear inside the input field. The hint disappears when the user starts entering text but will reappear if the text is deleted. Placeholder text does not get submitted as form data.

Finally, there is the required attribute that defines the field as one that must be filled in for the form to be considered valid.

The span below the input field contains a checkmark that is not visible when the page first loads. The AngularJS ngShow directive has an evaluation in it that will only allow the span to be visible when the field passes email field passes validation rules.

Negative feedback is provided courtesy of CSS and AngularJS. Enter a value in the First Name field and then delete it. The field background will change to red. If you look in style.css you’ll see the following section: {

ng-invalid and ng-dirty automatically get assigned as classes based on the input field state. If the field contents are invalid then the input field will be dynamically assigned the ng-invalid class. We can use that class to style the field in certain circumstances as I did above. Pretty slick! See the AngularJS API for more information on these class assignments.

Finally, check out the Submit and Restore buttons. The Submit button’s job is to update the visitorInfo object. The restore button restores all of the field data to the last submitted value.

Both buttons react to the state of the form. The submit button will enable and turn green when the entire form has been filled out with valid information. The restore button enables when the form data differs from the stored visitorInfo object data.

This functionality is done using a combination of AngularJS’s ngClick and ngDisabled directives:

<button ng-click="reset()" ng-disabled="isUnchanged(visitorInfo)">RESTORE</button>
<button class="submitbtn" ng-click="update(visitorInfo)" ng-disabled="valForm.$invalid || isUnchanged(visitorInfo)">SUBMIT</button>

ngDisabled contains an evaluation. If the evaluation is true then ngDisabled will also be set to true, making the buttons un-clickable. If they evaluate to false then the buttons will become enabled. Once they are enable, they can be clicked and the clicks will be handled by the functions that are referenced in the ngClick directives.

All in all it was very easy. The code itself is MUCH shorter than this post, which is a testament to the simplicity of AngularJS and HTML5 (or it could be just an indication that I’m too wordy.) In either case, I’m using that line as an opportunity to wrap this post up.

As always, check out the code on Plunkr. Fork it, edit it, experiment with it. It’s the best way to learn.