The default view/route/controller is named login. The login view utilizes the Firebase's Simple Login feature to authenticate users before proceeding to the rest of the application. Apart from logging into krakn, users can register a new account by entering their desired credentials. An interesting part of the login view is the use of the ng-show
directive to toggle the second password field if the user selects the register button. However, the ng-model
directive is the first step here, as it is used to pass the input text from the view to the controller and ultimately, the Firebase Simple Login. Other than the Angular magic, this view uses the ion-view
directive, grid, and buttons that are all core to Ionic.
Each view within an Ionic app is wrapped within an ion-view
directive that contains a title
attribute as follows:
The login view uses the standard input elements that contain a ng-model
attribute to bind the input's value back to the controller's $scope
as follows:
The Log In
and Register
buttons call their respective functions using the ng-click
attribute, with the value set to the function's name as follows:
The Register
and Cancel
buttons set the value of $scope.createMode
to true
or false
to show or hide the correct buttons for either action:
$scope.err
is displayed only when you want to show the feedback to the user:
The login controller is dependent on Firebase's loginService
module and Angular's core $location
module:
Ionic's directives tend to create isolated scopes, so it was useful here to wrap our controller's variables within a $scope.data
object to avoid issues within the isolated scope as follows:
The login()
function easily checks the credentials before authentication and sends feedback to the user if needed:
If the credentials are sound, we send them to Firebase for authentication, and when we receive a success callback, we route the user to the chat view using $location.path()
as follows:
The createAccount()
function works in much the same way as login()
, except that it ensures that the users don't already exist before adding them to your Firebase and logging them in:
The assertValidLoginAttempt()
function is a function used to ensure that no errors are received through the account creation and authentication flows:
Keeping vegan practices aside, the meat and potatoes of krakn's functionality lives within the chat view/controller/route. The design is similar to most SMS clients, with the input in the footer of the view and messages listed chronologically in the main content area. The ng-repeat
directive is used to display a message every time a message is added to the messages collection in Firebase. If you submit a message successfully, unsuccessfully, or without any text, feedback is provided via the placeholder attribute of the message input.
There are two filters being utilized within the chat view: orderByPriority
and timeAgo
. The orderByPriority
filter is defined within the firebase
module that uses the Firebase object IDs that ensure objects are always chronological.
The ion-view
directive is used once again to contain our chat view:
Our list of messages is composed using the ion-list
and ion-item
directives, in addition to a couple of key attributes. The ion-list
directive gives us some nice interactive controls using the option-buttons
and can-swipe
attributes. This results in each list item being swipeable to the left, revealing our option-buttons
as follows:
Our workhorse in the chat view is the trusty ng-repeat
directive, responsible for persisting our data from Firebase to our service to our controller and into our view and back again:
Then, we bind our data into vanilla HTML elements that have some custom styles applied to them:
The third-party timeago
filter converts the time into something such as, "5 min ago", similar to Instagram or Facebook:
A vanilla input element is used to accept chat messages from our users. The input data is bound to $scope.data.newMessage
for sending data to Firebase and $scope.feedback
is used to keep our users informed:
When you click on the send
/submit
button, the addMessage()
function sends the message to your Firebase, and adds it to the list of chat messages, in real time:
The ChatCtrl
controller is dependant on a few more modules other than our LoginCtrl
, including syncData
, $ionicScrollDelegate
, $ionicLoading
, and $rootScope
:
The userName
variable is derived from the authenticated user's e-mail address (saved within the application's $rootScope
) by splitting the e-mail and using everything before the @
symbol:
Avoid isolated scope issue in the same fashion, as we did in LoginCtrl
:
Our view will only contain the latest 20 messages that have been synced from Firebase:
When a new message is saved/synced, it is added to the bottom of the ng-repeated
list, so we use the $ionicScrollDeligate
variable to automatically scroll the new message into view on the display as follows:
Our default chat input placeholder text is something on your mind?
:
If we have a new message and a valid username (shortened), then we can call the $add()
function, which syncs the new message to Firebase and our view is as follows:
On a successful sync, the feedback updates say Done! What's next?
, as shown in the following code snippet:
The account view allows the logged in users to view their current name and e-mail address along with providing them with the ability to update their password and e-mail address. The input fields interact with Firebase in the same way as the chat view does using the syncData
method defined in the firebase
module:
The $scope.user
object contains our logged in user's account credentials, and we bind them into our view as follows:
The basic account management functionality is provided within this view; so users can update their e-mail address and or password if they choose to, using the following code snippet:
Both the updatePassword()
and updateEmail()
functions work in much the same fashion as our createAccount()
function within the LoginCtrl
controller. They check whether the new e-mail or password is not the same as the old, and if all is well, it syncs them to Firebase and back again:
Within krakn/app/scripts/app.js
, the menu route is defined as the only abstract state. Because of its abstract state, it can be presented in the app along with the other views by the ion-side-menus
directive provided by Ionic. You might have noticed that only two menu options are available before signing into the application and that the rest appear only after authenticating. This is achieved using the ng-show-auth
directive on the chat, account, and log out menu items. The majority of the options for Ionic's directives are available through attributes making them simple to use. For example, take a look at the animation="slide-left-right"
attribute. You will find Ionic's use of custom attributes within the directives as one of the ways that the Ionic Framework is setting itself apart from other options within this space.
The ion-side-menu
directive contains our menu list similarly to the one we previously covered, the ion-view
directive, as follows:
Our back button is displayed by including the ion-nav-back-button
directive within the ion-nav-bar
directive:
Animations within Ionic are exposed and used through the animation
attribute, which is built atop the ngAnimate
module. In this case, we are doing a simple animation that replicates the experience of a native mobile app:
A simple ion-list
directive/element is used to display our navigation items in a vertical list. The ng-show
attribute handles the display of menu items before and after a user has authenticated. Before a user logs in, they can access the navigation, but only the About
and Log In
views are available until after successful authentication.
The Log Out
navigation item is only displayed once logged in, and upon a click, it calls the logout()
function in addition to navigating to the login view:
The MenuCtrl
controller is the simplest controller in this application, as all it contains is the toggleMenu()
and logout()
functions: