OnsenUI | Working With Sliding Menu Pattern

Written by on April 9, 2015

OnsenUI | Working With Sliding Menu Pattern

Code overview

For this example, I will reuse my previous article code. We will no longer have a detail page, it’s will be replaced with sliding menu which will hold movie filtering system. Everything else stays the same.

Like AngularJS, OnsenUI is all about MVC (or to be more precise Model–View–Whatever) so let’s discuss basic application details.

The first thing we need to do is to initialize our application, unlike AngularJS, OnsenUI doesn’t require defined ng-app directive.

We only need to initialize it through JavaScript:

var module = ons.bootstrap('my-app', ['onsen']);

For OnsenUI to work properly, we need to set the [‘onsen’] dependency, framework will not work without it.

This application will have one distinct page plus sliding menu. Main page (Master) will act as a search page (home.html) while sliding menu will hold movie filtering system. Because we have only one page we will need only one controller:

module.controller('MainController', function($scope, Movies) {

…Ctrl under controller name is an Angular convention. but you can give it any name. For better future readability stick to this convention. Another important thing to remember is $scope. This is Angular model, it’s just a JavaScript object. Each $scope will hold associated page data. As you can see you don’t need to call set or get functions if you want to change something inside a $scope (like in Backbone case), just access it like any other JavaScript object:

$scope.movies = movies;

Main application page (list.html) contains only two page structures (elements), search input and an empty list holder template. This emplete system is made to mimic HandlebarsJS template engine (or older {{mustache}} engine). For example this is a list holder template we are using in our example:

<ons-list>
	<ons-list-item class="list-item-container" ng-repeat="movie in movies  | filter: greaterThan('vote_average')">

		<ons-row>
			<ons-col width="95px">
				<img ng-src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';" class="thumbnail"/>
			</ons-col>
			<ons-col>
				<div class="name">
					<strong>{{movie.original_title}}</strong>
				</div>
				<div class="desc">Release Date: <strong>{{movie.release_date}}</strong>
				</div>
				<div class="desc">Score: <strong>{{movie.vote_average}}</strong>
				</div>
			</ons-col>
			<ons-col width="40px"/>
		</ons-row> 

	</ons-list-item>
</ons-list> 

{{movie.original_title}} represents object movie -> parameter original_title.

Now let’s talk about how this application works. First we need to write something into our search input, it looks like this:

<input type="search" class="search-input search-movies-input" placeholder="Search..." style="width: 100%;height: 45px;" ng-model="selected.movieName" ng-change="searchMovieDB()">

Because this input has an AngularJS attribute ng-model=”movie.name” everything we write will be bound to the $scope object movie:

$scope.selected = {
  score : 0,
  movieName : 'Batman'
}

Another important thing about this input box is, each time we change something it will trigger change event bound to this input box (ng-change=”searchMovieDB()”). This event will trigger function searchMovieDB which is part of a Home controller:

$scope.searchMovieDB = function() {

This is where things get a little bit complicated. This function will call another function which is part of a factory service called Movies. This :

Movies.list($scope.movie.name, function(movies) {

will call this:

list: getData,

which is a part of a Movies factory service. AngularJS factory lets you create a service that you can use with AngularJS dependency injection. This is recommended way of exposing data from the server to the Angular views. In a few words, dependency injection is a software design pattern in which an object is given its dependencies, rather than the object creating them itself. It is about removing the hard-coded dependencies and making it possible to change them whenever needed. Don’t worry if you don’t understand a word I’m saying, you will learn it sooner or later.

Movies factory function list will accept two parameters, a first one is movie name and second one is an anonymous callback function we will use to acquire a list of searched movies. Function list will call another function getData:

function getData(moviename, callback) {

This function will in turn initiate a REST call to moviedb service, acquire a list of movies and returning it back to the original scope using passed callback function. It will set original scope object $scope.movies, which will in turn trigger list template population:

<ons-list>
	<ons-list-item class="list-item-container" ng-repeat="movie in movies  | filter: greaterThan('vote_average')">

		<ons-row>
			<ons-col width="95px">
				<img ng-src="https://image.tmdb.org/t/p/w92{{movie.poster_path}}" onerror="this.src = 'https://www.ginesisnatural.com/images/no_image.jpg';" class="thumbnail"/>
			</ons-col>
			<ons-col>
				<div class="name">
					<strong>{{movie.original_title}}</strong>
				</div>
				<div class="desc">Release Date: <strong>{{movie.release_date}}</strong>
				</div>
				<div class="desc">Score: <strong>{{movie.vote_average}}</strong>
				</div>
			</ons-col>
			<ons-col width="40px"/>
		</ons-row> 

	</ons-list-item>
</ons-list> 

Attribute ng-repeat=”movie in movies” will loop through the object movies and build page content using acquired JSON data and list template.

On the other side, we have a Sliding menu content which is populated directly from the Home Controller $scope.sorting object:

<ul class="list">
	<li class="list__item list__item--tappable" ng-repeat="sort in sorting">
		<label class="radio-button radio-button--list-item">
		<input type="radio" name="b" ng-model="selected.score" ng-value="{{sort.score}}" checked="checked" ng-change="setSelectedScoreRane()">
		<div class="radio-button__checkmark radio-button--list-item__checkmark"></div>
			{{sort.name}}
		</label>
	</li>
</ul> 

When you click on a radio list element application will propagate selected element to $scope parameter $scope.selected.score. This will trigger main page movie list evaluation where we will be shown only movies above selected score. For example, if we click “Score more than 7” we will be shown only movies with a score above 7.

And that’s everything you need to know about this application. I hope this example will help you as much as possible. If you have additional questions please leave them in a comment section below.

Who Am I?

Between working as a senior Java developer in one of the largest insurance companies in the world and traveling, in my free time, I work as a professional mobile development adviser. I'm also a major jQuery Mobile supporter back at StackOverflow and a forum moderator at the official Ionic Framework forum.



Categories

Leave a Reply