Cosmic JS Blog Stay tuned for community news, company announcements and updates from the Cosmic JS team.

How to Build an Emoji Game Using AngularJS


In this tutorial I'm going to show you how to create a "Emoji" game using a little bit of Node, and Cosmic JS. For the sake of understanding how to consume Restful API’s, this tutorial will show how to make simple AJAX requests to the Cosmic JS API in order to retrieve, update, and delete data in our Cosmic JS Buckets. Let's get started.

TL;DR

Download the GitHub repo.
Check out the demo.

Getting Started:

First, let’s make a new directory to build our project in and lets also make a package.json file.

mkdir emoji-app
emoji-app$ touch package.json

Now, in your package.json, copy and paste the code below:

//emoji-app/package.json
{
  "name": "emoji-app",
  "version": "1.0.0",
  "main": "app-server.js",
  "engines": {
    "node": "4.1.2",
    "npm": "3.5.2"
  },
  "description": "",
  "dependencies": {
    "body-parser": "^1.17.2",
    "bower": "^1.7.7",
    "buffer-to-vinyl": "^1.1.0",
    "express": "^4.13.3",
    "gulp": "^3.9.1",
    "gulp-autoprefixer": "^3.1.0",
    "gulp-concat": "^2.6.0",
    "gulp-concat-css": "^2.2.0",
    "gulp-env": "^0.4.0",
    "gulp-minify-css": "^1.2.4",
    "gulp-ng-config": "^1.4.0",
    "gulp-npm-script-sync": "^1.1.0",
    "gulp-webserver": "^0.9.1",
    "http-server": "^0.9.0",
    "stripe": "^4.22.0",
    "wiredep": "^3.0.0"
  },
  "scripts": {
    "postinstall": "bower install && gulp config && gulp js",
    "start": "npm run production",
    "production": "node app-server.js",
    "gulp": "gulp"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp-npm-script-sync": "^1.1.0",
    "gulp-remote-src": "^0.4.2"
  }
}/
            

Second, let’s make a bower.json file.

emoji-app$ touch bower.json

Now, in your bower.json, copy and paste the code below:

//emoji-app/bower.json
{
  "name": "emoji-app",
  "description": "Emoji App",
  "version": "0.0.0",
  "homepage": "https://github.com/kutsaniuk/emoji-app",
  "license": "MIT",
  "private": true,
  "dependencies": {
    "angular": "~1.5.x",
    "angular-mocks": "~1.5.x",
    "angular-bootstrap": "~1.1.x",
    "angular-cookies": "~1.5.x",
    "angular-route": "~1.5.x",
    "angular-ui-router": "0.2.x",
    "angular-resource": "1.5.x",
    "angular-animate": "~1.5.x",
    "ng-dialog": "0.6.1",
    "bootstrap": "3.3.x",
    "cr-acl": "",
    "angular-chosen-localytics": "*",
    "bootstrap-chosen": "*",
    "ng-flow": "^2.7.4",
    "angular-mask": "*",
    "checklist-model": "0.9.0",
    "angular-ui-notification": "^0.2.0",
    "angular-ui-calendar": "^1.0.2",
    "angular-ui-switch": "^0.1.1",
    "ng-scrollbars": "^0.0.11",
    "jquery.scrollbar": "*",
    "angular-flash-alert": "^2.4.0",
    "components-font-awesome": "^4.7.0",
    "angular-loading-bar": "^0.9.0",
    "angular-environment": "^1.0.8",
    "angular-emoji-popup": "",
    "angular-dragdrop": "",
    "angular-sanitize": "1.5.*",
    "angular-drag-and-drop-directives": "",
    "jquery-ui-touch-punch": "",
    "angular-touch":"1.5.*",
    "textAngular":"1.5.*"
  },
  "resolutions": {
    "angular": "~1.5.x"
  },
  "devDependencies": {
    "cr-acl": "^0.5.0"
  }
}
            

Config app server:

emoji-app$ touch app-server.js
//events-app/app-server.js
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.set('port', process.env.PORT || 3000)
app.use(express.static(__dirname))
app.use(bodyParser.json())
var http = require('http').Server(app)
// Route
app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
})
http.listen(app.get('port'), () => {
  console.log('Emoji App listening on ' + app.get('port'))
})
            

What we're installing and why:

  1. We're going to use the AngularJS framework to build Single-page application
  2. We're installing angular-ui-router for create multi views.
  3. We are going to use gulp for build all js and css files into one file.

Building our app:

Now we're going to build out our file structure a bit more so that we can organize our angular modules and js files. This is what our emoji-app directory should look like:

emoji-app
|----app
|       |----auth
|                 |----auth.ctrl.js
|                 |----auth.service.js
|       |----config
|                 |----config.js
|       |----watch
|                 |----profile
|                           |----watch.profile.ctrl.js
|                           |----watch.profile.mdl.js
|                 |----watch.ctrl.js
|                 |----watch.mdl.js
|                 |----watch.service.js
|       |----admin
|                 |----authors
|                           |----add
|                                   |----admin.authors.add.ctrl.js
|                                   |----admin.authors.add.mdl.js
|                           |----edit
|                                   |----admin.authors.edit.ctrl.js
|                                   |----admin.authors.edit.mdl.js
|                           |----admin.authors.ctrl.js
|                           |----admin.authors.mdl.js
|                           |----admin.authors.service.js
|                 |----quotes
|                           |----add
|                                   |----admin.quotes.add.ctrl.js
|                                   |----admin.quotes.add.mdl.js
|                           |----edit
|                                   |----admin.quotes.edit.ctrl.js
|                                   |----admin.quotes.edit.mdl.js
|                           |----admin.quotes.ctrl.js
|                           |----admin.quotes.mdl.js
|                           |----admin.quotes.service.js
|                 |----admin.ctrl.js
|                 |----admin.mdl.js
|       |----author
|                 |----author.ctrl.js
|                 |----author.mdl.js
|       |----emoji
|                 |----emoji.ctrl.js
|                 |----emoji.mdl.js
|                 |----emoji.service.js
|       |----user
|                 |----user.service.js
|       |----main.mdl.js
|----dist
|       |----css
|       |----img
|       |----js
|----css
|----views
|----resources
|----gulpfile.js
|----app-server.js
|----bower.json
|----package.json
            

Now we we will set up our index.html. Copy and paste the following code into your index.html file:

<!DOCTYPE html>
<html lang="en" ng-app="main">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Emoji App</title>

    <!-- bower:css -->
    <!-- endbower -->

    <!-- Bootstrap Core CSS -->
    <link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- Custom CSS -->

    <link href="dist/css/main.min.css" rel="stylesheet">


    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>
<body>

<div ui-view></div>

<!-- bower:js -->
<!-- endbower -->

<script src="dist/js/main.js"></script>
</body>
</html>
            

Here, we are going to target our "root" view to place our angular modules in later. The main.js file located in our dist directory is what our gulpfile.js file will spit out after bundling all of our angular modules Now, set up our gulpfile.js file to bundle all of our js files and export that bundle file to our dist directory. Copy the following code into your gulpfile.js file:

//emoji-app/gulpfile.js
'use strict';

var gulp = require('gulp'),
    webserver = require('gulp-webserver'),
    minifyCSS = require('gulp-minify-css'),
    concat = require('gulp-concat'),
    wiredep = require('wiredep').stream,
    gulpNgConfig = require('gulp-ng-config'),
    autoprefixer = require('gulp-autoprefixer'),
    b2v = require('buffer-to-vinyl'),
    sync = require('gulp-npm-script-sync');

sync(gulp);

gulp.task('css', function () {
  return gulp.src('css/**/*.css')
    .pipe(minifyCSS())
    .pipe(concat('main.min.css'))
    .pipe(autoprefixer())
    .pipe(gulp.dest('dist/css'));
});

gulp.task('js', function() {
    return gulp.src('app/**/**/*.js')
        .pipe(concat('main.js'))
        .pipe(gulp.dest('dist/js/'));
});

gulp.task('config', function () {
    const json = JSON.stringify({
        BUCKET_SLUG: process.env.COSMIC_BUCKET,
        MEDIA_URL: 'https://api.cosmicjs.com/v1/' + process.env.COSMIC_BUCKET + '/media',
        URL: 'https://api.cosmicjs.com/v1/',
        READ_KEY: process.env.COSMIC_READ_KEY || '',
        WRITE_KEY: process.env.COSMIC_WRITE_KEY || '',
        DEFAULT_IMAGE: process.env.DEFAULT_IMAGE || ''
    });
    return b2v.stream(new Buffer(json), 'config.js')
        .pipe(gulpNgConfig('config'))
        .pipe(gulp.dest('app/config'));
});

gulp.task('default', function () {
  gulp.watch('css/**/*.css', ['css']);
  gulp.watch('app/**/**/*.js', ['js']);
  gulp.watch('bower.json', ['bower']);
});

gulp.task('bower', function () {
  gulp.src('index.html')
    .pipe(wiredep({
      directory: 'bower_components'
    }))
    .pipe(gulp.dest(''));
});

            

After that we can create main module. Copy and paste the following code into your main.mdl.js file:

(function () {
    'use strict';

    angular
        .module('main', [
            'ui.router',
            'ui.bootstrap',
            'ngMask',
            'ngCookies',
            'ngRoute',
            'ngDialog',
            'cr.acl',
            'ui-notification',
            'ngFlash',
            'ngAnimate',
            'textAngular',
            'flow',
            'angular-loading-bar',
            'ngDragDrop',
            'ngEmoticons',
            'ngSanitize',
            'ngTouch',

            'emoji',
            'admin',
            'author',

            'config'
        ])
        .config(config)
        .run(run);

    config.$inject = ['$stateProvider', '$urlRouterProvider', 'cfpLoadingBarProvider', 'NotificationProvider'];
    function config($stateProvider, $urlRouterProvider, cfpLoadingBarProvider, NotificationProvider) {
        cfpLoadingBarProvider.includeSpinner = false;

        NotificationProvider.setOptions({
            startTop: 25,
            startRight: 25,
            verticalSpacing: 20,
            horizontalSpacing: 20,
            positionX: 'right',
            positionY: 'bottom'
        });

        $urlRouterProvider.otherwise(function ($injector) {
            var $state = $injector.get("$state");
            var $location = $injector.get("$location");
            var crAcl = $injector.get("crAcl");

            var state = "";

            switch (crAcl.getRole()) {
                case 'ROLE_ADMIN':
                    state = 'admin.authors';
                    break;
                default : state = 'main.emoji';
            }

            if (state) $state.go(state);
            else $location.path('/');
        });

        $stateProvider
            .state('main', {
                url: '/',
                abstract: true,
                templateUrl: '../views/main.html',
                // controller: 'CartCtrl as cart',
                data: {
                    is_granted: ['ROLE_GUEST']
                }
            })
            .state('blog', {
                url: '/blog',
                templateUrl: '../blog.html'
            })
            .state('auth', {
                url: '/login',
                templateUrl: '../views/auth/login.html',
                controller: 'AuthCtrl as auth',
                onEnter: ['AuthService', 'crAcl', function(AuthService, crAcl) {
                    AuthService.clearCredentials();
                    crAcl.setRole();
                }],
                data: {
                    is_granted: ['ROLE_GUEST']
                }
            });
    }

    run.$inject = ['$rootScope', '$cookieStore', '$state', 'crAcl'];
    function run($rootScope, $cookieStore, $state, crAcl) {
        // keep user logged in after page refresh
        $rootScope.globals = $cookieStore.get('globals') || {};

        crAcl
            .setInheritanceRoles({
                'ROLE_ADMIN': ['ROLE_ADMIN', 'ROLE_GUEST'],
                'ROLE_GUEST': ['ROLE_GUEST']
            });

        crAcl
            .setRedirect('main.emoji');

        if ($rootScope.globals.currentUser) {
            crAcl.setRole($rootScope.globals.currentUser.metadata.role);
            // $state.go('admin.watches');
        }
        else {
            crAcl.setRole();
        }

    }
    angular.module('main')
        .directive('compile', ['$compile', function ($compile) {
            return function (scope, element, attrs) {
                scope.$watch(
                    function (scope) {
                        // watch the 'compile' expression for changes
                        return scope.$eval(attrs.compile);
                    },
                    function (value) {
                        element.html(value);

                        $compile(element.contents())(scope);
                    }
                );
            };
        }]);
})();
             

Now we we will set up our Auth Controller. Copy and paste the following code into your auth.ctrl.js file:

(function () {
    'use strict';

    angular
        .module('main')
        .controller('AuthCtrl', AuthCtrl);

    function AuthCtrl(crAcl, $state, AuthService, Flash, $log) {
        var vm = this;

        vm.login = login;

        vm.loginForm = null;

        vm.credentials = {};
        vm.user = {};

        function login(credentials) {
            function success(response) {
                function success(response) {
                    if (response.data.status !== 'empty') {
                        var currentUser = response.data.objects[0];

                        crAcl.setRole(currentUser.metadata.role);
                        AuthService.setCredentials(currentUser);
                        $state.go('admin.authors');
                    }
                    else
                        Flash.create('danger', 'Incorrect username or password');
                }

                function failed(response) {
                    $log.error(response);
                }

                if (response.data.status !== 'empty')
                    AuthService
                        .checkPassword(credentials)
                        .then(success, failed);
                else
                    Flash.create('danger', 'Incorrect username or password');

                $log.info(response);
            }

            function failed(response) {
                $log.error(response);
            }

            if (vm.loginForm.$valid)
                AuthService
                    .checkUsername(credentials)
                    .then(success, failed);
        }

    }
})();
            

Create Auth Service, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('main')
        .service('AuthService', function ($http,
                                          $cookieStore,
                                          $q,
                                          $rootScope,
                                          URL, BUCKET_SLUG, READ_KEY, WRITE_KEY) {
            var authService = this;
            $http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

            authService.checkUsername = function (credentials) {
                return $http.get(URL + BUCKET_SLUG + '/object-type/users/search', {
                    params: {
                        metafield_key: 'email',
                        metafield_value_has: credentials.email,
                        limit: 1,
                        read_key: READ_KEY
                    }
                });
            };
            authService.checkPassword = function (credentials) {
                return $http.get(URL + BUCKET_SLUG + '/object-type/users/search', {
                    ignoreLoadingBar: true,
                    params: {
                        metafield_key: 'password',
                        metafield_value: credentials.password,
                        limit: 1,
                        read_key: READ_KEY
                    }
                });
            };
            authService.setCredentials = function (user) {
                $rootScope.globals = {
                    currentUser: user
                };

                $cookieStore.put('globals', $rootScope.globals);
            };
            authService.clearCredentials = function () {
                var deferred = $q.defer();
                $cookieStore.remove('globals');

                if (!$cookieStore.get('globals')) {
                    $rootScope.globals = {};
                    deferred.resolve('Credentials clear success');
                } else {
                    deferred.reject('Can\'t clear credentials');
                }

                return deferred.promise;
            };
        });
})();
            

What's going on here:

  1. We are using the ui-router for config routes.
  2. We created Auth Service for our asynchronous calls to our Cosmic JS API.
  3. We created Auth Controller for checking credentials.

Create User Service for get and update User, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('main')
        .service('UserService', function ($http,
                                          $cookieStore,
                                          $q,
                                          $rootScope,
                                          URL, BUCKET_SLUG, READ_KEY, WRITE_KEY) {
            $http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

            this.getCurrentUser = function (ignoreLoadingBar) {
                return $http.get(URL + BUCKET_SLUG + '/object/' + $rootScope.globals.currentUser.slug, {
                    ignoreLoadingBar: ignoreLoadingBar,
                    params: {
                        read_key: READ_KEY
                    }
                });
            };
            this.getUser = function (slug, ignoreLoadingBar) {
                return $http.get(URL + BUCKET_SLUG + '/object/' + slug, {
                    ignoreLoadingBar: ignoreLoadingBar,
                    params: {
                        read_key: READ_KEY
                    }
                });
            };
            this.updateUser = function (user) {
                user.write_key = WRITE_KEY;

                return $http.put(URL + BUCKET_SLUG + '/edit-object', user, {
                    ignoreLoadingBar: false
                });
            };

        });
})();
            

Create Emoji Service for get emoji from words, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('main')
        .service('EmojiService', function ($http) {

            var that = this;

            that.Quote = function (text, author, slug) {
                this.text = text;
                this.author = author;
                this.slug = slug;
            };

            that.Emoji = function (code, position) {
                this.code = code;
                this.position = position;
            };

            that.Container = function (type, item) {
                this.type = type;
                this.item = item;
            };

            that.Random = {
                randNumOld: 0,
                getRandomInt: function (min, max) {
                    var randNum = Math.floor(Math.random() * (max - min + 1)) + min;
                    if (randNum == this.randNumOld) return this.getRandomInt(min, max);
                    this.randNumOld = randNum;

                    return randNum;
                }
            };

            this.getEmojisFromWords = function (quote) {
                var words = [];
                var word = '';

                quote += " ";

                for (var i = 0; i < quote.length; i++) {
                    if (quote[i] !== ' ') word += quote[i];
                    else {
                        words.push(word);
                        word = '';
                    }
                }

                for (var j = 0; j < words.length; j++) {
                    if (getMeAnEmoji(words[j]) !== "") words[j] = ":" + getMeAnEmoji(words[j]) + ":";
                }

                console.log(words);
                return words;
            };

            this.getEmoji = function (quote, emojis, containers, checkAnswers) {
                var i = 0;
                var position = 0;
                var result;
                var word = '';
                var isEmoji = new RegExp(":");
                var _quote = quote;

                while (i < quote.text.length) {
                    if (isEmoji.test(quote.text[i])) {
                        result = ( /\:(\w+)\:/.exec(quote.text) )[1];
                        emojis.push(new that.Emoji(":" + result + ":", i));
                        containers.push(new that.Container('emoji', []));
                        checkAnswers.push(new that.Emoji(":" + result + ":", position));

                        quote.text[i] = quote.text[i].replace(':' + result + ':', '_emoji_');

                        position++;
                    }
                    else {
                        containers.push(new that.Container('word', quote.text[i]));
                    }
                    word = '';
                    i++;
                }

                $http.get('/resources/emojis.json')
                    .success(function (data) {
                        for (var j = 0; j < 3; j++) {
                            emojis.push(new that.Emoji(":" + data[parseInt(Math.random() * data.length)] + ":"));
                        }
                    });

                return _quote;
            };

        });
})();
            

Create Emoji Controller for get quotes and checking results, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('main')
        .controller('EmojiCtrl', EmojiCtrl);

    function EmojiCtrl($scope, DEFAULT_IMAGE, EmojiService, AdminQuotesService, $log) {
        var vm = this;

        vm.checkAnswers = [];
        vm.quote = {};
        vm.quotes = [];
        vm.emojis = [];
        vm.containers = [];
        vm.win = false;

        vm.DEFAULT_IMAGE = DEFAULT_IMAGE;

        var random = EmojiService.Random;
        var getEmojisFromWords = EmojiService.getEmojisFromWords;
        var getEmoji = EmojiService.getEmoji;
        var Quote = EmojiService.Quote;
        var Emoji = EmojiService.Emoji;

        var getRandomQuote = _getRandomQuote;
        var getUserAnswers = _getUserAnswers;

        vm.getUserAnswerLength = getUserAnswerLength;
        vm.nextQuote = nextQuote;
        vm.checkAnswer = checkAnswer;
        vm.getUserAnswerLength = getUserAnswerLength;

        $scope.getOptionsContainer = getOptionsContainer;

        function _getRandomQuote(quotes) {
            var _random = random.getRandomInt(0, quotes.length - 1);
            console.log(quotes[_random]);
            return quotes[_random].slug;
        }

        function _getUserAnswers(containers) {
            var userAnswers = [];
            var position = 0;

            for (var i = 0; i < containers.length; i++) {

                if (!Array.isArray(containers[i].item)) continue;
                userAnswers.push(new Emoji(containers[i].item[0].code, position));
                position++;

            }

            return userAnswers;
        }

        function getUserAnswerLength() {
            var userAnswersLength = 0;

            for (var k = 0; k < vm.containers.length; k++) {
                if (!Array.isArray(vm.containers[k].item)) continue;
                if (vm.containers[k].item.length !== 0) userAnswersLength += 1;
            }
            return userAnswersLength;
        }

        function nextQuote() {
            getQuote(getRandomQuote(vm.quotes));
        }

        function checkAnswer() {
            var result = [];
            var position = 0;

            function in_array(value, array) {
                for (var i = 0; i < array.length; i++) {
                    if (array[i] == value) return true;
                }
                return false;
            }

            if (vm.getUserAnswerLength() === vm.checkAnswers.length) {
                var userAnswers = getUserAnswers(vm.containers);
                for (var j = 0; j < userAnswers.length; j++) {
                    vm.checkAnswers[j].code === userAnswers[j].code ? result.push(true) : result.push(false);
                }

                console.log(result);

                for (var i = 0; i < vm.containers.length; i++) {

                    if (!Array.isArray(vm.containers[i].item)) continue;
                    if (!result[position]) {
                        vm.emojis[vm.containers[i].item[0].jqyoui_pos] = new Emoji(vm.containers[i].item[0].code, i);
                        vm.containers[i].item.splice(0, 1);
                    }
                    position++;

                }

                console.log(vm.emojis);
                !in_array(false, result) ? vm.win = true : vm.win = false;
            }
        }

        function getOptionsContainer(container) {
            return {
                accept: function (dragEl) {
                    if (container.length >= 1) {
                        return false;
                    } else {
                        return true;
                    }
                }
            }
        }

        function getQuotes() {
            function success(response) {
                response.data.objects.forEach(function (quote) {
                    vm.quotes.push(
                        new Quote(
                            getEmojisFromWords(quote.metadata.text),
                            quote.metadata.author,
                            quote.slug
                        )
                    );
                });
                $log.info(vm.quotes);

                getQuote(getRandomQuote(vm.quotes));

            }

            function failed(response) {
                $log.error(response);
            }

            AdminQuotesService
                .getQuotes(true)
                .then(success, failed);
        }

        function getQuote(slug) {
            function success(response) {
                vm.quote = new Quote(
                    getEmojisFromWords(response.data.object.metadata.text),
                    response.data.object.metadata.author,
                    response.data.object.slug
                );

                vm.emojis = [];
                vm.containers = [];
                vm.checkAnswers = [];
                vm.win = false;

                getEmoji(
                    vm.quote,
                    vm.emojis,
                    vm.containers,
                    vm.checkAnswers
                );

                vm.emojis.sort(function (a, b) {
                    return a.code.charCodeAt(1) - b.code.charCodeAt(2)
                });

                vm.emojis.reverse();
                console.log('emojis', vm.emojis);
            }

            function failed(response) {
                $log.error(response);
            }

            AdminQuotesService
                .getQuoteBySlug(slug)
                .then(success, failed);
        }

        getQuotes();

        $('.emoji').draggable(); // FOR TouchScreen
    }
})();
            

Create Emoji Module, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('emoji', [])
        .config(config);

    config.$inject = ['$stateProvider', '$urlRouterProvider'];
    function config($stateProvider, $urlRouterProvider) {

        $stateProvider
            .state('main.emoji', {
                url: '',
                templateUrl: '../views/emoji/emoji.html',
                controller: 'EmojiCtrl as emojiCtrl'
            });
    }
})();
            

What's going on here:

  1. We created Emoji Service for get emoji from words.
  2. We created Emoji Controller for drag and drop emoji, get quotes and checking results.
  3. We created Emoji Module.

Create Author Controller for getting information of author, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('main')
        .controller('AuthorCtrl', AuthorCtrl);

    function AuthorCtrl($stateParams, $scope, DEFAULT_IMAGE, AdminAuthorsService, Flash, $log) {
        var vm = this;

        vm.author = {};

        vm.DEFAULT_IMAGE = DEFAULT_IMAGE;

        getAuthor($stateParams.slug);

        function getAuthor(slug) {
            function success(response) {
                response.data.object.metadata.born = new Date(response.data.object.metafields[2].value);
                response.data.object.metadata.died = new Date(response.data.object.metafields[3].value);
                vm.author = response.data.object;
            }

            function failed(response) {
                $log.error(response);
            }

            AdminAuthorsService
                .getAuthorBySlug(slug)
                .then(success, failed);
        }
    }
})();

Create Author Module, copy and paste the code below:

(function () {
    'use strict';

    angular
        .module('author', [])
        .config(config);

    config.$inject = ['$stateProvider', '$urlRouterProvider'];
    function config($stateProvider, $urlRouterProvider) {

        $stateProvider
            .state('main.author', {
                url: 'author/:slug',
                templateUrl: '../views/author/author.html',
                controller: 'AuthorCtrl as vm',
                data: {
                    is_granted: ['ROLE_GUEST']
                }
            });
    }
})();

What's going on here:

  1. We can see information about authors.

Conclusion:

We were able to consume the Cosmic JS API with our actions and dispatcher functions. I hope you enjoyed this tutorial as much as I did, if you have any questions reach out to us on Twitter and join our community on Slack.

You may also like


Medium has become the de-facto platform for publishing online content.  In this article, I'm going to show you how to build a Medium backup application using Node.js and Cosmic JS.

We've got a new feature to make adding existing media to your Objects even easier.  Now when you click the image icon on any content editor, you will see a folder icon to browse existing media in your Bucket.

Brand Managers manage, well, brands.  Seems simple enough right?  It does in title and theory alone.  Managing a brand means managing the brand’s tone, voice, messaging, consumer segmentation, price points, marketing, advertising and all of the subsequent elements and assets that fall out of such an engagement.  Having managed brands for years myself, I can attest to the magnitude of the job at hand.  Once the client has agreed upon a general direction, it becomes the brand manager’s responsibility to ignite passion and results from the internal agency team that services the account.  As my workload would increase month over month as business heated up or an account was grown, I went through the whole Automation | Delegation | Elimination routine to see what I could cut out of my schedule as busy work.  The problem?  I was only one person.  I could only affect hours tallies on my end, but had little to no influence over design, development, copywriting & production. 


The area that always seemed to be the weak link in terms of staying on budget was in development.  Boutique agencies struggle to attract qualified talent with their long work hours and subpar compensation, and then after taking a gamble on a more junior talent that is developed over time, retention is a beating.  Companies line up with development jobs that pay 2X, sometimes 3X what a boutique agency is willing to part with for that developer’s compensation package.  This is all before taking into account staging servers, hosting servers, CMS logins, local installations of CMS systems and all of the red tape and bureaucracy associated that can bog down a productive workflow.  As a result, my quotes back to clients for websites, microsite, landing pages and applications were always a bit higher than they were expecting.  I started searching for a cloud-based solution to my CMS woes to cut out some of the middle men and see if there was an easier way to 'get this digital property live'. 

I found 
Cosmic JS.  Had I been told as a Brand Manager that I could eliminate the local CMS, the hosting server and the shared logins of content editing, I would have seen the value immediately.  No longer having to build APIs on a per-CMS / per-client basis, no longer having to build out a proprietary backend, yet still attaining the same custom-value would have been a lifesaver and a half for a brand manager focused on the bottom line.  It would have easily cut my back end developers’ hours estimates by 40%, eliminated costly hosting servers and would have streamlined content-centric employees within the agency to not have to deal with the red tape of updating content within a traditional CMS. 

Whether we picked out a
content-ready application or plugged GitHub into Cosmic JS, I’m seeing time and cost savings at every turn.  Music to a brand manager’s ears, and music to a boutique agency’s margin and bottom line.  As it turns out, it also benefits the client as their content is put first, their content is pushed live more quickly and is devourable globally on any device.

In this installment of the Cosmic JS Developer Spotlight Series, we sat down with Rick Hanlon, a Front End Engineer  and recent New Yorker that is now residing in London, England working on the front end team at Facebook. Rick is also on the core team of Jest, a JavaScript testing platform. Follow Rick on Twitter or LinkedIn and enjoy the Q/A.

Did you know that we have some great resources available over on our GitHub page?  Use these packages, examples and clients to help you build your next big project or contribute to an existing one.

Tools

1. Cosmic JS Node Package

- This is a great package for your Node.js app.  
Easily add this to your JS setup with npm install cosmicjs

2. Cosmic JS Browser Package

- This is a great package for your your browser-based apps.  
Easily add this to your JS setup with npm install cosmicjs-browser

3. Cosmic JS PHP Client

- This is the official PHP client that makes adding a CMS to your PHP app a breeze.

Example Websites

1. Astral (PHP)

- This is a really cool PHP single page application built using the PHP client on an html5up.net frontend.

- This is a single page React app that uses React Router and the Flux pattern.  The pages load fast!

I hope you find that these links and resources help you learn more about building with the Cosmic JS content API.  If you have any questions about the API, you can learn more in the Cosmic JS API Documentation.

Building and maintaining a React app can be no mean feat. There plenty of tutorials out there covering the technical aspects of making a React app, but as with any technology, it's often hard to find information on best practices.

In this post we'll be exploring some tips, tricks, and techniques we've learnt whilst producing React/GraphQL apps for our clients. Hopefully these will help you make your project more performant and simplify maintenance.