How To Use Flat UI Pro and Angular.js to Build a Web App
Almost anyone can build a single-page web applications using Angular.js and Flat UI Pro. All it takes is a little background in Angular.js to complete this tutorial.
Angular.js is a powerful, modern and popular framework for development single-page web applications. (Get up to speed on using this framework from the website of the project.)
No matter how wonderful the framework is, you need a basis for your UI. Usually programmers use CSS frameworks such as Twitter Bootstrap, Zurb Foundation and others.
Twitter Bootstrap is a great framework for building UI, but it is very simple and usually requires extra effort for customization. Fortunately, Designmodo has developed an advanced framework, Flat UI Pro, where you get the best from Bootstrap and the power of the flat design!
If you decide to use Flat UI Pro in your web application, you will most likely encounter such difficulties as the use of jQuery widgets when dynamically adding them to the page. Unfortunately, widgets in Flat UI Pro are built on the basis of jQuery plugins. (This is due to the huge popularity of the jQuery library and number of existing plug-ins.)
But there is no reason to worry because angular.js provides includes the powerful tool, Directive. Using directives will solve all our problems and our angular.js the application will live in complete harmony with Flat UI Pro.
With Postcards you can create and edit email templates online without any coding skills! Includes more than 100 components to help you create custom emails templates faster than ever before.
Try FreeOther ProductsLet’s begin. Make sure you already have a license for Flat UI Pro and you have downloaded the latest version of angular.js.
Flat UI Pro Template
First, we need a template for the main page of the application. The Flat UI Pro folder contains the default template. The template contains links to stylesheets and scripts, as well as the basic layout of our main page.
Below is the layout of the page index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Flat UI</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Loading Bootstrap --> <link href="bootstrap/css/bootstrap.css" rel="stylesheet"> <!-- Loading Flat UI --> <link href="css/flat-ui.css" rel="stylesheet"> <link rel="shortcut icon" href="images/favicon.ico"> <!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. --> <!--[if lt IE 9]> <script src="js/html5shiv.js"></script> <script src="js/respond.min.js"></script> <![endif]--> </head> <body> <div class="container-fluid"> Start doing your next awesomeness here. </div><!-- /.container --> <!-- Load JS here for greater good =============================--> <script src="js/jquery-1.8.3.min.js"></script> <script src="js/jquery-ui-1.10.3.custom.min.js"></script> <script src="js/jquery.ui.touch-punch.min.js"></script> <script src="js/bootstrap.min.js"></script> <script src="js/bootstrap-select.js"></script> <script src="js/bootstrap-switch.js"></script> <script src="js/flatui-checkbox.js"></script> <script src="js/flatui-radio.js"></script> <script src="js/jquery.tagsinput.js"></script> <script src="js/jquery.placeholder.js"></script> </body> </html>
As you can see here everything is very simple. The title, links to scripts and styles in this template contain only one element:
<div class="container-fluid"> Start doing your next awesomeness here. </div><!-- /.container-->
In it we’re going to deploy elements of our application. And start to build our application UI.
To develop this application, I’ll use the IDE from JetBrains – Webshtorm. But you can use any IDE or text editor, such as my favorite sublimetext.
Here’s how to look structure of our application:
With Startup App and Slides App you can build unlimited websites using the online website editor which includes ready-made designed and coded elements, templates and themes.
Try Startup App Try Slides AppOther ProductsOpen a page index.html in your browser you will see the following text:
“Start doing your next awesomeness here.”
Building UI with Flat UI Pro
Let’s define what will be our application. On the main page we will have the top menu and menu to navigate through the sections on the left.
Add the front of the container (div element with a class ‘content’) the following html markup
<nav class="navbar navbar-default" role="navigation"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-01"> <span class="sr-only">Flat UI Pro & Angular.js</span> </button> <a class="navbar-brand" href="#"><span class="fui-flat"></span></a> </div> <div class="collapse navbar-collapse" id="navbar-collapse-01"> <ul class="nav navbar-nav"> <li><a href="#Products">Products</a></li> <li><a href="#Futures">Features</a></li> </ul> <form class="navbar-form navbar-right" action="#" role="search"> <div class="form-group"> <div class="input-group"> <input class="form-control" id="navbarInput-01" type="search" placeholder="Search"/> <span class="input-group-btn"> <button type="submit" class="btn"><span class="fui-search"></span></button> </span> </div> </div> </form> </div> <!-- /.navbar-collapse --> </nav>
Pay attention to the following code. He is responsible for the navigation:
<li><a href="#Products">Products</a></li> <li><a href="#Futures">Features</a></li>
This is a typical pattern in the main menu, taken from the documentation for Flat UI Pro.
Click on the link for Products or Futures and are we going to move on to the relevant sections of our application.
Let’s prepare some pages, on which we will go when we choose one or another section on the top menu of our application.
Add in the project root folder “templates” and create two html files: products.html and futures.html.
Now we can begin writing the markup.
Install angular.js
It’s time to revive our application and add dynamics. Let’s set angular.js.
You can download angular.js from the official website. I install using the utility Bower. Bower is the package manager, designed specifically for client applications. It is very suitable for our project.
If you are using Linux to install angular.js you need to open a terminal, go to the root of the project and execute the following command: bower install — save angular
If you did everything correctly, then in the project root folder appears bower_components in which is installed package angular.
In order we could use angular.js in your application, we need to add to the index.html page for a link to the angular.js.
<!-- Load JS here for greater good =============================--> <script src="js/jquery-1.8.3.min.js"></script> <script src="bower_components/angular/angular.js"></script> .....
Angular.js Application
To turn our html page in angular application you want to add to the html tag attribute ng-app=”angular-article” where angular-article – this is the name of our module.
<!DOCTYPE html> <html lang="en" ng-app="angular-article"> …
Add the root of the project file app.js and the controllers folder and create it two files products_controller.js and futures_controller.js
Before we start programming, you need to install another package, which we will need to build navigation. Unfortunately the standard navigation system in the current version of angular.js does not provide all of the capabilities that we need namely navigation of nested routes without reloading the main container. Further we will use route-segment. You can get it from the website or install with bower.
bower install –save angular-route-segment
bower install –save angular-route
Do not forget to add a reference to angular-route-segment.js after angular.js reference.
<script src="bower_components/angular-route/angular-route.js"></script> <script src="bower_components/angular-route-segment/build/angular-route-segment.js"></script>
Now we need to configure routing for navigation. Add the following code to the file app.js.
var app = angular.module('angular-article', ['ngRoute', 'route-segment', 'view-segment']); app.config(function ($routeSegmentProvider) { $routeSegmentProvider.options.autoLoadTemplates = true; $routeSegmentProvider .when('/', 'products') .when('/products', 'products') .when('/futures', 'futures') .segment('products',{ default: true, templateUrl: 'templates/products.html', controller: 'ProductsController' }) .segment('futures', { templateUrl: 'templates/futures.html', controller: 'FuturesController' }) });
It’s simple. We initialize our module angular-article and config navigation. Using this service $ routeSegmentProvider we got by adding a link to the file angular-route-segment.js.
Now let’s add the following code to products_controller.js:
angular.module('angular-article').controller('ProductsController',['$scope', function($scope){}]);
We now have the controller ProductsController which still does nothing. This is a placeholder for future experiments.
Run our application, opening index.html in your browser.
If in the top menu we click on the link products you will pass on page with a table and left side menu, if you click on the link futures then move on to a blank page as a template futures.html we add nothing.
If you want the selected item in the top menu active when we click on it, it is necessary to make the following changes.
Add MenuController. Create file menu_controller in controllers forder and add to this code:
angular.module('angular-article').controller('MenuController', ['$scope', '$location', function ($scope, $location) { $scope.$location = $location; }]);
And change index.html:
<li ng-class="{active: $location.path() == '/' || $location.path() =='/products'}"><a href="#products">Products</a></li> <li ng-class="{active: $location.path() == '/futures'}"><a href="#futures">Features</a></li>
Now let’s fill our table data. To do this, open products_controller.js and add the following code in it:
$scope.products = [ { "fname": 'Gibson', "lname": 'Classic', "year": 2011, "rating": 3, "votes": 500 }, { "fname": 'Gibson', "lname": 'Custom Shop', "year": 2012, "rating": 5, "votes": 10000 } , { "fname": 'Fender', "lname": 'Stratocaster', "year": 2012, "rating": 4, "votes": 1200 }, { "fname": 'Ibanez', "lname": 'Fuzz', "year": 2012, "rating": 1, "votes": 16070 } ];
This is the model which we will complete the table. Next, open the file products.html and change the table as follows:
<table class="table"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Year</th> <th>Rating</th> <th>Votes</th> </tr> </thead> <tbody> <tr ng-repeat="product in products"> <td>{{product.fname}}</td> <td>{{product.lname}}</td> <td>{{product.year}}</td> <td>{{product.rating}}</td> <td>{{product.votes}}</td> </tr> </tbody> </table>
The design <tr ng-repeat=”product in products”> allows to fill in a table based model. Since we linked in the application settings (navigation) the controller ProductsController template products.html the template can use any model and the functions contained in the object $scope of this controller.
Now when we have an existing application, it’s time to start learning Flat UI Pro.
Flat UI Pro Widgets and angular.js Directives
Let’s similar to the previous page, add the left navigation menu and container into futures.html.
<div class="row"> <div class="col-md-2"> <ul class="nav nav-list"> <li class="nav-header">Widgets</li> <li ng-class="{active: $location.path() == '/futures/alert' || $location.path() == '/futures'}"> <a href="#futures/alert"> Alert </a> </li> <li ng-class="{active: $location.path() == '/futures/file'}"> <a href="#futures/file"> File </a> </li> <li ng-class="{active: $location.path() == '/futures/modal'}"> <a href="#futures/modal"> Modal </a> </li> <li ng-class="{active: $location.path() == '/futures/checkbox'}"> <a href="#futures/checkbox"> CheckBox </a> </li> <li ng-class="{active: $location.path() == '/futures/taginput'}"> <a href="#futures/taginput"> Tag input </a> </li> <li ng-class="{active: $location.path() == '/futures/spinner'}"> <a href="#futures/spinner"> Spinner </a> </li> <li ng-class="{active: $location.path() == '/futures/slider'}"> <a href="#futures/slider"> Slider </a> </li> </ul> </div> <div class="col-md-10" app-view-segment="1"> </div> </div>
Like on “products,” this page is divided into two columns. The first contains the left navigation menu, and the second container to display pages.
Flat UI Pro Alerts
Now open the file app.js and immediately after
.segment('futures', { templateUrl: 'templates/futures.html', controller: 'FuturesController' })
Add the following code:
.within() .segment('alert', { default: true, templateUrl: 'templates/alert.html', controller:'DirectivesController' })
And after
.when('/futures', 'futures') add .when('/futures/alert', 'futures.alert')
Now create a folder directives and add into the folder you created the file alert_directive.js.
angular.module('angular-article') .directive('alert', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/alert_template.html', replace: true, transclude: true, scope: { data: '=' }, link: function ($scope, element, attrs) { $scope.transcluded = element.find('div[ng-transclude]').contents(); $scope.$watch('data', function(value){ $scope.alert = value; }); $scope.close = function(){ $scope.alert.isShow = false; } } } });
Here we create a new Directive which is called the alert. We specify that the Directive should replace html element to have a template alert_template.html and may contain markup in your body. The Directive also associated with model data it gets from the attribute.
At the time of link of this Directive to the context we create a watcher, who will be looking for changes in the model data. This is called linking.
Now let’s add the template for alerts. Create a folder directive_templates in the templates folder, and create a file alert_template.html.
In the file alert_template.html add the following markup:
<div class="alert" ng-class="{false: 'alert-error', true:'alert-success', 'info': 'alert-info', 'warning':'alert-warning'} [alert.isSuccess]"> <button class="close fui-cross" ng-click="close()"></button> <h4>{{alert.header}}</h4> <div ng-show="transcluded.length <= 1" ng-bind-html="alert.text"> </div> <div ng-show="transcluded.length > 1" ng-transclude></div> </div>
We are almost ready to try out the newly created Directive in action. Let’s add a page alert.html in the templates folder, controlled directives_contrllert.js in the controllers folder.
directives_controller.js:
angular.module('angular-article').controller('DirectivesController', ['$scope', '$routeSegment','$sce', function ($scope, $routeSegment, $sce) { $scope.$routeSegment = $routeSegment; $scope.alerts = [ { isSuccess: true, header: 'Success message', text: $sce.trustAsHtml('Something some some some text text text') }, { isSuccess: 'info', header: 'Info message', text: $sce.trustAsHtml('Something some some some text text text') }, { isSuccess: false, header: 'Error message', text: $sce.trustAsHtml('Something some some some text text text') }, { isSuccess: 'warning', header: 'Warning message', text: $sce.trustAsHtml('Something some some some text text text') } ]; $scope.alert = { isSuccess: false, header: 'Custom body error message' } }]);
alert.html:
<alert ng-repeat="alt in alerts" data="alt"/> <alert data="alert"> <p>An error message is information displayed when an unexpected condition occurs, usually on a computer or other device. On modern operating systems with graphical user interfaces, error messages are often displayed using dialog boxes.</p> <button type="button" class="btn btn-primary btn-wide">Save</button> <button type="button" class="btn btn-danger btn-wide">Cancel</button> </alert>
In this example, we used two different approaches to the creation of the Directive. In the first, we start a cycle in which to create as many alerts as there are objects in the model. We pass the text. In the second case, we create a Directive from one object and do not share in it the text, and in place of that form the body of the alert manually using html markup.
Look at $sce.trustAsHtml this expression allows you to securely transmit the text of the html markup.
Flat UI Pro file
By analogy with flet ui alert will create a new page file.html to demonstrate the work with file input. And create the Directive file and template file_template. Do not forget to set up routing, address of the controller DirectivesController.
Add this code into file_directive.js:
angular.module('angular-article').directive('file', function(){ return { restrict: 'E', templateUrl: 'templates/directive_templates/file_template.html', replace: true, scope: { text: '@', changeText: '@', deleteText: '@', name: '@' }, link: function($scope, element, attrs){ $scope.text = attrs.text; $scope.changeText = attrs.changeText; $scope.deleteText = attrs.deleteText; $scope.name = attrs.name; element.fileinput(); } } });
Add this markup into file_directive.html:
<div class="fileinput fileinput-new" data-provides="fileinput"> <div class="input-group"> <div class="form-control uneditable-input" data-trigger="fileinput"> <span class="fui-clip fileinput-exists"></span> <span class="fileinput-filename"></span> </div> <span class="input-group-btn btn-file"> <span class="btn btn-default fileinput-new" data-role="select-file">{{text}}</span> <span class="btn btn-default fileinput-exists" data-role="change"><span class="fui-gear"></span>{{changeText}}</span> <input type="file" name="{{name}}"> <a href="#" class="btn btn-default fileinput-exists" data-dismiss="fileinput"><span class="fui-trash"></span> {{deleteText}}</a> </span> </div> </div>
In this file.html:
<file text="Add file" delete-text="Delete" change-text="Change" name="file1" /> <file text="Add file" delete-text="Delete" change-text="Change" name="file2" /> <file text="Add file" delete-text="Delete" change-text="Change" name="file3" />
Don’t forget to add a link to a file file_directive.js in index.html.
Directives control checkboxes and radio buttons. As in the previous example, we need to add the files checkbox_directive and radiobutton_directive to the folder directives.
Place into checkbox_directive.js this code:
angular.module('angular-article').directive('checkbox', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/checkbox_template.html', replace: true, scope: { value: '@', id: '@', text: '@', checked: '=' }, link: function ($scope, element, attrs) { $scope.value = attrs.value; $scope.id = attrs.id; $scope.text = attrs.text; $scope.$watch('checked', function (value) { if (value) { $scope.checked = value; element.children().checkbox('check'); } else $scope.checked = false; }); element.children().on('toggle', function () { $scope.$apply(function(){ $scope.checked = !$scope.checked; }); }); element.children().checkbox(); } } });
Place into checkbox_template.html this markup:
<label class="checkbox" for="{{'checkbox' + id}}"> <input type="checkbox" value="{{value}}" id="{{'checkbox' + id}}" data-toggle="checkbox"> {{text}} </label>
Now in the templates folder, create a file checkbox.html and add the following markup:
<div ng-init="cpp= true; java=false; python=false; qt=true;"></div> <checkbox value="0" id="cpp" text="C++" checked="cpp" /> <checkbox value="1" id="java" text="Java" checked="java" /> <checkbox value="2" id="python" text="Python" checked="python" /> <checkbox value="3" id="qt" text="Qt" checked="qt" />
In this case I did not want to create a controller to the page checkbox is why I initialized variables through ng-init. This is similar to using a controller.
It is important, you should use the variables used everywhere where “=” in the binding. If you try to pass a value through a “{{ }}” you will get the error!
Then, by analogy with the checkboxes will add a Directive to radio buttons.
Place into checkbox_directive.js this code:
angular.module('angular-article').directive('radiobutton', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/radiobutton_template.html', replace: true, scope: { value: '@', id: '@', name: '@', text: '@', checked: '=' }, link: function ($scope, element, attrs) { $scope.value = attrs.value; $scope.id = attrs.id; $scope.text = attrs.text; $scope.name = attrs.name; $scope.$watch('checked', function (value) { if (value) { $scope.checked = value; } else $scope.checked = false; }); element.children().on('toggle', function (val) { console.log(val); $scope.$apply(function(){ $scope.checked = !$scope.checked; }); }); element.children().radio(); } } });
Place into radiobutton_template.html this markup:
<label class="radio"> <input type="radio" name="{{name}}" value="{{value}}" data-toggle="radio"> {{text}} </label>
Be sure to add the correct routes in app.js and register Directive in index.html.
Flat UI Pro Modal
In this example, we will write a Directive to control Modal. This is the standard jQuery plugin that uses Twitter Bootstrap and other frameworks.
Create a file modal_directive in the folder directives and place the following code in it:
angular.module('angular-article') .directive('modal', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/modal_template.html', replace: true, transclude: true, scope: { open: '=' }, link: function ($scope, element, attrs) { $scope.header = attrs.header; $scope.content = attrs.content; $scope.$watch('open', function (value) { if (value == true) { element.modal('show'); } else if (value == false) { element.modal('hide'); } }); element.on('hidden.bs.modal', function (e) { $scope.$apply(function () { $scope.open = false; }) }); } } });
Now will create a template for this Directive. Open the folder directives/directive_templates and create a file modal_directive:
<div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content" ng-transclude> </div> </div> </div>
The template is small because we insert content inside our element. Let me remind you that this is the option transclude the Directive and the template.
Add page modal.html in the templates folder and don’t forget to register a new route and add a reference in Index.html on modal_directive.js.
<button class="btn btn-wide btn-primary" ng-click="openModal()">Open modal</button> <modal open="isModalOpen"> <div class="modal-header"> <button type="button" class="close fui-cross" data-dismiss="modal" aria-hidden="true"></button> <h4 class="modal-title">Modal header</h4> </div> <div class="modal-body"> <p>Modal content = {{2 + 2}}</p> </div> <div class="modal-footer"> <button class="btn btn-primary btn-wide" data-dismiss="modal">Ok</button> <button class="btn btn-danger btn-wide" data-dismiss="modal">Cancel</button> </div> </modal>
Now open the file directives_controller.js and add this code to hte controller:
$scope.isModalOpen = false; $scope.openModal = function(){ if (!$scope.isModalOpen){ $scope.isModalOpen = true; } }
We added a variable IsModalOpen, which determines which window is open or not. Method OpenModal sets the variable isModalOpen true for opening.
Flat UI Pro Tag Input
Tag inputs is a simple control. Let’s create a Directive that will allow us convenient to work with tags. We will share the Directive array for adding or removing items.
As in the previous paragraph will create a new file taginput.html in the templates folder, will register a new route and add the script Directive fileinput_directive.js as well as its template fileinput_template.html
Taginput_directive.js
angular.module('angular-article').directive('taginput', function(){ return { restrict: 'E', templateUrl: 'templates/directive_templates/taginput_template.html', replace: true, scope: { tags: '=', name: '@', id: '@' }, link: function($scope, element, attrs){ $scope.name = attrs.name; $scope.id = attrs.id; $scope.$watch('tags', function (value) { $scope.values = value; element.importTags(value.toString()); }); element.tagsInput({ onAddTag: function(value){ $scope.values.push(value); $scope.$apply(function(){ $scope.tags = $scope.values; }); } }); }, controller: function($scope){ } } });
As we need to catch events add a new element to an array, we subscribe to an event to add a new element and fulfilling the implementation of the values in the array values. Then pass the modified array in the application context.
I have not added a method to remove an item from the field taginput. You can do this by analogy with addition of subscribing to the event onRemoveTag.
taginput_template.html
<input name="{{name}}" class="tagsinput tagsinput-primary" ng-value="values" />
taginput.html
<p> <taginput id="tag1" name="tag1" tags="tags" /> </p> <p> {{tags}} </p>
Flat UI Pro Spinner
Flat UI Spinner is normal jQuery plugin that has been customized by designers from Designmodo. To work with this control, we will create a simple Directive as shown below.
spinner_directive.js
angular.module('angular-article').directive('spinner', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/spinner_template.html', replace: true, scope: { value: '=' }, link: function ($scope, element, attrs) { $scope.$watch('value', function (value) { $scope.value = value; }); element.on("spin", function (event, ui) { $scope.$apply(function () { $scope.value = ui.value; }) }); element.on("change", function (event, ui) { var m = element.spinner('value'); $scope.$apply(function () { $scope.value = m; }) }); element.spinner(); } } });
Here we create watchers in the event of changes to the item and click the arrows down or upward.
spinner_template.html
<input type="text" ng-value="value" class="form-control spinner" />
spinner.html
<p> <spinner value="spinnerValue"/> </p> <p> {{spinnerValue}} </p>
Flat UI Pro Slider
The slider is a jQuery plugin and similar spinner.
Below I will give a very simple Directive for slider, but you will easily be able to expand its capabilities.
slider_directive.js
angular.module('angular-article').directive('slider', function () { return { restrict: 'E', templateUrl: 'templates/directive_templates/slider_template.html', replace: true, scope: { value: '=', min: '@', max: '@', orientation: '@', range: '@' }, link: function ($scope, element, attrs) { $scope.min = attrs.min; $scope.max = attrs.max; $scope.orientation = attrs.orientation; $scope.range = attrs.range; $scope.text = attrs.text; $scope.value = attrs.value; $scope.$watch('value', function (value){ $scope.value = value; }); element.on("slide", function (event, ui) { $scope.$apply(function () { $scope.value = ui.value; }) }); element.slider({ min: $scope.min, max: $scope.max, value: 0, orientation: $scope.orientation, range: $scope.range }); } } });
slider_template.html
Contains only an empty div element. <div />
slider.html
<slider value="sliderValue" min="0" max="100" orientation="horizontal" range="min"/> {{sliderValue}}
Conclusion
As you can see to using Flat UI with angular.js simple. You can also add to the directives of the controller and use rich dependency injection to work with different services, such as http, localstorage, animate, and so on.
Good luck creating beautiful and reliable applications.
Here is source code of app (without Flat UI Pro).