| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
This branch contains the tutorial steps and processes used to implement the start-app shown below:
Above is a snapshot of the Starter-App with a Master-Detail layout: showing a list of users (left) and a user detail view (right).
Also shown is the user experience that will be displayed for smaller device sizes. The responsive layout reveals the menu button that can be used to hide the user list. And the share button can be used to show the Share bottom sheet view.
This Starter app demonstrates how:
This sample application is purposed as both a learning tool and a skeleton application for a typical AngularJS Material web app, comprised of a side navigation area and a content area. You can use it to quickly bootstrap your angular webapp projects and dev environment for these projects.
Here are some generalized steps that may be used to conceptualize the application implementation process:
Plan your layout and the components you want to use
Use hard-coded HTML and mock content to make sure the components appear as desired
Wire components to your application logic
Use the seamless integration possible with AngularJS directives and controllers.
This integration assumes that you have unit tested your application logic.
Add Responsive breakpoints
Add Theming support
Confirm ARIA compliance
Write End-to-end (e2e) Tests
It is important to validate your application logic with AngularJS Material UI components.
The illustration below shows how we planned the layout and identified the primary components that will be used in the Starter app:
Note: The container #2 (above) is a simple <div> container and not an AngularJS Material component.
This tutorial uses jspm.io, a package manager for SystemJS which is built on top of the dynamic ES6 module loader. This allows developers to load any module format (ES6, CommonJS, AMD, and globals).
This tutorial assumes that you have already cloned the repository and executed the following commands:
Note: Open the dev console to see any warnings and browse the elements.
You will notice a few files/directories within this tutorial:
Note: You should not need to edit anything in the app/src/users and app/assets directories or the AppController.js file until Steps #9 & #10 where we will refactor the code into more discrete components.
These folders and files will be used to guide you through the development process. By following these tutorial steps, you will be very quickly introduced to the powerful features of AngularJS Material.
We encourage you to walk through each step yourself and build the application from the ground up. However, if you get stuck or want to start from a clean slate, each step has an associated Git tag that you can checkout to reset your code to match the start of the associated step in the tutorial.
For instance, to start on Step 3, run git checkout step-3. Also note that step-1 is the same as the es6-tutorial branch.
Note: In some of the Steps in this README, we have abbreviated some of the HTML or JavaScript in order to show what is being added or changed, so you may not be able copy & paste every example into your code. If you wish to start fresh, use the Git tags as described above.
The available step tags (in order) are:
Now let's review our initial setup:
app/index.html
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>AngularJS Material - Starter App</title>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Roboto:400,700'>
<link rel="stylesheet" href="./assets/app.css"/>
</head>
<body ng-cloak>
<!--
No content yet!
-->
<script src="./jspm_packages/system.js" type="text/javascript"></script>
<script src="config.js" type="text/javascript"></script>
<script type="text/javascript">
System
.import('src/boot/boot')
.catch( console.error.bind(console) ); // make sure any errors print to console
</script>
</body>app/src/boot/boot.js
import angular from 'angular';
/**
* Manually bootstrap the application when AngularJS and
* the application classes have been loaded.
*/
angular
.element( document )
.ready( function() {
angular
.module( 'starter-app-bootstrap', [ ] )
.run(()=>{
console.log(`Running the 'starter-app-bootstrap' module for ES6 Material-Start Tutorial`);
});
let body = document.getElementsByTagName("body")[0];
angular.bootstrap( body, [ 'starter-app-bootstrap' ]);
});These files contain the basic building blocks of, and bootstrapping for, our application. The index.html file is the main entry point and it uses System.js to import our boot script which in turn imports all of our other files and loads them dynamically.
Note: The config.js file simply configures how System.js loads all of the files/libraries.
Here you will modify the application to use AngularJS Material.
app/index.html
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>AngularJS Material - Starter App</title>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Roboto:400,700'>
<link rel="stylesheet" href="./jspm_packages/github/angular/bower-material@master/angular-material.css"/>
<link rel="stylesheet" href="./assets/app.css"/>
</head>Note: The NPM and JSPM configurations already installed the AngularJS Material libraries. Re-installs are easily done using jspm install angular-material@master.
Note: Note that we have manually included the Material CSS. This is because JSPM does not guarantee the order in which CSS files are loaded, and we want to ensure that our app.css file is loaded after the Material CSS so that it can properly override certain selectors.
app/src/app.js
// Load libraries
import angular from 'angular';
import 'angular-animate';
import 'angular-aria';
import 'angular-material';
export default angular.module( 'starter-app', [ 'ngMaterial' ] )
.run(() => {
console.log(`Starting the 'starter-app' module`);
});app/src/boot/boot.js
import angular from 'angular';
import App from 'src/app';
/**
* Manually bootstrap the application when AngularJS and
* the application classes have been loaded.
*/
angular
.element( document )
.ready( function() {
angular
.module( 'starter-app-bootstrap', [ App.name ] )
.run(()=>{
console.log(`Running the 'starter-app-bootstrap' module for ES6 Material-Start Tutorial`);
});
let body = document.getElementsByTagName("body")[0];
angular.bootstrap( body, [ 'starter-app-bootstrap' ]);
});Note: This version of the boot.js file imports our new app.js file as well so that it will be run and can setup our application module.
Here we will use the wireframe planning and layout to identify the components and attributes needed.
Add the <md-toolbar>, <md-sidenav>, and <md-content> containers
Note: The <md-sidenav> is the container for the Users master list view, and the <md-content> is the container for the User detail view.
Add the layout and flex attributes to configure the container layouts and sizing aspects
Use md-is-locked-open to lock the sidenav open on the left
Use the md-whiteframe-4dp class to add a shadow the sidenav
app/index.html
<body ng-cloak layout="column">
<!-- Container #1 (see wireframe) -->
<md-toolbar layout="row" class="md-toolbar-tools">
<h1>AngularJS Material - Starter App</h1>
</md-toolbar>
<!-- Container #2 -->
<div flex layout="row">
<!-- Container #3 -->
<md-sidenav md-is-locked-open="true" class="md-whiteframe-4dp">
Sidenav
</md-sidenav>
<!-- Container #4 -->
<md-content flex id="content">
Content
</md-content>
</div>
</body>Here you will use hard-coded elements to confirm rendering and layout of the container child elements and AngularJS Material components.
app/index.html
<body layout="column">
<!-- Container #1 (see wireframe) -->
<md-toolbar layout="row" class="md-toolbar-tools">
<h1>AngularJS Material - Starter App</h1>
</md-toolbar>
<!-- Container #2 -->
<div flex layout="row">
<!-- Container #3 -->
<md-sidenav md-is-locked-open="true" class="md-whiteframe-4dp">
<md-list>
<!-- List item #1 -->
<md-list-item>
<md-button>
<md-icon md-svg-src="./assets/svg/avatar-1.svg" class="avatar"></md-icon>
Lia Luogo
</md-button>
</md-list-item>
<!-- List item #2 -->
<md-list-item>
<md-button>
<md-icon md-svg-src="./assets/svg/avatar-4.svg" class="avatar"></md-icon>
Lawrence Ray
</md-button>
</md-list-item>
</md-list>
</md-sidenav>
<!-- Container #4 -->
<md-content flex id="content">
<!-- User details sample -->
<md-icon md-svg-src="./assets/svg/avatar-1.svg" class="avatar"></md-icon>
<h2>Lia Luogo</h2>
<p>
I love cheese...
</p>
</md-content>
</div>
</body>Here you integrate your custom, application logic.
app/src/app.js
// Load libraries
import angular from 'angular';
import 'angular-animate';
import 'angular-aria';
import 'angular-material';
import AppController from 'src/AppController';
import Users from 'src/users/Users';
export default angular.module( "starter-app", [ 'ngMaterial', Users.name ] )
.run(() => {
// ...
})
.controller('AppController', AppController);Here you will replace the hardcoded HTML with dynamic markup using AngularJS directives (eg ng-repeat) and {{ }} interpolation markup to utilize the User and App functionality we just imported in Step #4.
app/index.html
<body ng-cloak layout="column" ng-controller="AppController as app">
<!-- Container #1 (see wireframe) -->
<md-toolbar layout="row" class="md-toolbar-tools">
<md-button class="menu md-icon-button">
<md-icon md-svg-icon="menu"></md-icon>
</md-button>
<h1>AngularJS Material - Starter App</h1>
</md-toolbar>
<!-- Container #2 -->
<div flex layout="row">
<!-- Container #3 -->
<md-sidenav md-is-locked-open="true" class="md-whiteframe-4dp">
<md-list>
<md-list-item ng-repeat="user in app.users">
<md-button ng-click="app.selectUser(user)" ng-class="{'selected' : user === app.selected }">
<md-icon md-svg-icon="{{user.avatar}}" class="avatar"></md-icon>
{{user.name}}
</md-button>
</md-list-item>
</md-list>
</md-sidenav>
<!-- Container #4 -->
<md-content flex id="content">
<md-icon md-svg-icon="{{app.selected.avatar}}" class="avatar"></md-icon>
<h2>{{app.selected.name}}</h2>
<p>{{app.selected.content}}</p>
<md-button class="md-fab md-fab-bottom-right">
<md-icon md-svg-icon="share"></md-icon>
</md-button>
</md-content>
</div>
</body>in src/app.js
// Load libraries
import angular from 'angular';
import 'angular-animate';
import 'angular-aria';
import 'angular-material';
import AppController from 'src/AppController';
import Users from 'src/users/Users';
export default angular.module( "starter-app", [ 'ngMaterial', Users.name ] )
.config(($mdIconProvider) => {
// Register the user `avatar` icons
$mdIconProvider
.defaultIconSet("./assets/svg/avatars.svg", 128)
.icon("menu", "./assets/svg/menu.svg", 24)
.icon("share", "./assets/svg/share.svg", 24);
})
.controller('AppController', AppController);Here you will add responsive breakpoints so the application layout will adapt to different device display sizes.
app/index.html
<body ng-cloak layout="column" ng-controller="AppController as app">
<!-- Container #1 (see wireframe) -->
<md-toolbar layout="row" class="md-toolbar-tools">
<md-button class="menu md-icon-button" hide-gt-sm ng-click="app.toggleList()">
<md-icon md-svg-icon="menu" ></md-icon>
</md-button>
<h1>AngularJS Material - Starter App</h1>
</md-toolbar>
<!-- Container #2 -->
<div flex layout="row">
<!-- Container #3 -->
<md-sidenav class="md-whiteframe-4dp" md-is-locked-open="$mdMedia('gt-sm')"
md-component-id="left" ng-click="app.toggleList()">
<md-list>
<md-list-item ng-repeat="user in app.users">
<md-button ng-click="app.selectUser(user)" ng-class="{'selected' : user === app.selected }">
<md-icon md-svg-icon="{{user.avatar}}" class="avatar"></md-icon>
{{user.name}}
</md-button>
</md-list-item>
</md-list>
</md-sidenav>
<!-- Container #4 -->
<md-content flex id="content">
<md-icon md-svg-icon="{{app.selected.avatar}}" class="avatar"></md-icon>
<h2>{{app.selected.name}}</h2>
<p>{{app.selected.content}}</p>
<md-button class="md-fab md-fab-bottom-right" ng-click="app.share($event)">
<md-icon md-svg-icon="share"></md-icon>
</md-button>
</md-content>
</div>
</body>In app.js register the share icons displayed in the detail view's bottomsheet:
app/src/app.js
// Load libraries
import angular from 'angular';
import 'angular-animate';
import 'angular-aria';
import 'angular-material';
import AppController from 'src/AppController';
import Users from 'src/users/Users';
export default angular
.module( "starter-app", [ 'ngMaterial', Users.name ] )
.config(($mdIconProvider) => {
$mdIconProvider
.defaultIconSet("./assets/svg/avatars.svg", 128)
.icon("menu", "./assets/svg/menu.svg", 24)
.icon("share", "./assets/svg/share.svg", 24)
.icon("google_plus", "./assets/svg/google_plus.svg", 24)
.icon("hangouts", "./assets/svg/hangouts.svg", 24)
.icon("twitter", "./assets/svg/twitter.svg", 24)
.icon("phone", "./assets/svg/phone.svg", 24);
})
.controller('AppController', AppController);Here you will configure a different, darker theme to be used.
app/src/app.js
// Load libraries
import angular from 'angular';
import 'angular-animate';
import 'angular-aria';
import 'angular-material';
import AppController from 'src/AppController';
import Users from 'src/users/Users';
export default angular
.module( "starter-app", [ 'ngMaterial', Users.name ] )
.config(($mdIconProvider, $mdThemingProvider) => {
$mdIconProvider
.defaultIconSet("./assets/svg/avatars.svg", 128)
.icon("menu", "./assets/svg/menu.svg", 24)
.icon("share", "./assets/svg/share.svg", 24)
.icon("google_plus", "./assets/svg/google_plus.svg", 24)
.icon("hangouts", "./assets/svg/hangouts.svg", 24)
.icon("twitter", "./assets/svg/twitter.svg", 24)
.icon("phone", "./assets/svg/phone.svg", 24);
$mdThemingProvider.theme('default')
.primaryPalette('brown')
.accentPalette('red');
})
.controller('AppController', AppController);Here you will fix any ARIA warnings that AngularJS Material may display in the Dev console.
app/index.html
<body>
<!-- Wireframe Container #1 -->
<md-toolbar layout="row">
<md-button ... aria-label="Show User List"></md-button>
</md-toolbar>
<!-- Wireframe Container #2 -->
<div flex layout="row">
<!-- Wireframe Container #3 -->
<md-sidenav>...</md-sidenav>
<!-- Wireframe Container #4 -->
<md-content flex id="content">
<md-button ... aria-label="Share"></md-button>
</md-content>
</div>
</body>Congratulations! You now have a fully functional AngularJS Material application!
In the next two steps, we'll refactor our code into separate AngularJS 1.4-style components, and then once again refactor using the new AngularJS 1.5 component() API.
Here you will refactor your HTML and code to create the <users-list> and <user-details> components. For the sake of the tutorial, we have provided the following files in the step-9 tag to show you how we recommend extracting the components and give you a jump start.
All you need to edit is the index.html, and Users.js files to properly utilize these new components.
If you would like to follow along yourself without checking out the tag, here are the basic steps that we took to extract the components:
Create the proper file/folder structure recommended above
Create templates based on your HTML in index.html
Define your UsersList and UserDetails directives following the AngularJS 1 Style Guide
Note: Contrary to the style guide, we set controllerAs: '$ctrl' to better align with the upcoming Angular naming conventions.
Create your directive controllers and extract the "share" logic from src/AppController.js into the UserDetailsController.js
Finally, update the src/users/Users.js module to register the new directives
Note: The UsersListController.js file is practically empty and could be removed if desired, but we show it here for completeness.
Note: In order to stay with the ES6 paradigm of classes, the UsersList and UserDetails have been written as full classes rather than plain functions. This means that we must first instantiate the class before we pass it to AngularJS's .directive() method as you can see below. We'll change this in Step #10 below to export a simple config object that is more consistent with the .component() API.
app/src/users/Users.js
// Load the custom app ES6 modules
import UsersDataService from 'src/users/services/UsersDataService';
import UsersList from 'src/users/components/list/UsersList';
import UserDetails from 'src/users/components/details/UserDetails';
// Define the AngularJS 'users' module
export default angular
.module("users", ['ngMaterial'])
.directive("usersList", () => new UsersList)
.directive("userDetails", () => new UserDetails)
.service("UsersDataService", UsersDataService);app/index.html
<!-- Container #2 -->
<div flex layout="row">
<!-- Container #3 -->
<md-sidenav ...>
<!-- Custom UsersList component -->
<users-list
users="app.users"
selected="app.selected"
on-selected="app.selectUser(user)">
</users-list>
</md-sidenav>
<!-- Container #4 -->
<md-content ...>
<!-- Custom UserDetails component -->
<user-details
selected="app.selected" >
</user-details>
</md-content>
</div>Here you will refactor your directives and controllers to use the AngularJS 1.5 Component API.
Note: If you want to copy/paste the code from the step-10 directory, you will also need to delete the app/src/users/components/list/UsersListController.js as it is not used.
app/src/users/components/details/UserDetails.js
class UserDetailsController {
// previous code here...
}
export default {
name : 'userDetails',
config : {
bindings : { selected: '<' },
templateUrl : 'src/users/components/details/UserDetails.html',
controller : [ '$mdBottomSheet', '$log', UserDetailsController]
}
};app/src/users/components/list/UsersList.js
export default {
name : 'usersList',
config : {
bindings : { users: '<', selected : '<', showDetails : '&onSelected' },
templateUrl : 'src/users/components/list/UsersList.html'
}
};app/src/users/Users.js
// Load the custom app ES6 modules
import UsersService from 'src/users/services/UsersDataService';
import UsersList from 'src/users/components/list/UsersList';
import UserDetails from 'src/users/components/details/UserDetails';
// Define the AngularJS 'users' module
export default angular
.module("users", ['ngMaterial'])
.component( UsersList.name, UsersList.config )
.component( UserDetails.name, UserDetails.config )
.service("usersService", UsersService);With only ten (10) Tutorial Steps and a few minutes of work, we have quickly created a functional AngularJS Material application that is beautiful, responsive, theme'ed, accessible, component-based, and easily maintained.
| Back | FazBrowse Home | New Git URL |