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

How to Build an AngularJS Events App


In this tutorial I'm going to show you how to create an "Events" app using a little bit of Node, Angular JS 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 Bucket. 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 events-app
events-app$ touch package.json

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

//events-app/package.json
{
  "name": "events-app",
  "version": "1.0.0",
  "main": "app-server.js",
  "engines": {
    "node": "4.1.2",
    "npm": "3.5.2"
  },
  "description": "",
  "dependencies": {
    "bower": "^1.7.7",
    "http-server": "^0.9.0",
    "gulp": "^3.9.1",
    "gulp-autoprefixer": "^3.1.0",
    "gulp-concat": "^2.6.0",
    "gulp-concat-css": "^2.2.0",
    "gulp-minify-css": "^1.2.4",
    "gulp-webserver": "^0.9.1",
    "wiredep": "^3.0.0",
    "express": "^4.13.3"
  },
  "scripts": {
    "postinstall": "bower install",
    "start": "npm run production",
    "production": "node app-server.js"
  },
  "author": "",
  "license": "ISC"
}
            

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

events-app$ touch bower.json

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

//events-app/bower.json
{
  "name": "events-app",
  "description": "Events App",
  "version": "0.0.0",
  "homepage": "https://github.com/cosmicjs/events-app",
  "license": "MIT",
  "private": true,
  "dependencies": {
    "angular": "~1.4.x",
    "angular-mocks": "~1.4.x",
    "angular-bootstrap": "~1.1.x",
    "angular-cookies": "~1.4.x",
    "angular-route": "~1.4.x",
    "angular-ui-router": "0.2.x",
    "angular-resource": "1.4.x",
    "angular-animate": "~1.4.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-nvd3": "*",
    "infinity-angular-chosen": "^0.2.0",
    "angular-flash-alert": "^2.4.0",
    "components-font-awesome": "^4.7.0",
    "textAngular": "^1.5.16",
    "angular-loading-bar": "^0.9.0"
  },
  "resolutions": {
    "angular": "~1.4.x"
  },
  "devDependencies": {
    "cr-acl": "^0.5.0"
  }
}
            

Config app server:

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

What we're installing and why:

  1. We're going to use the AngularJS framework to a 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 events-app directory should look like:

events-app
|----app
|       |----auth
|                 |----auth.ctrl.js
|                 |----auth.service.js
|       |----config
|                 |----config.js
|       |----event
|                 |----add
|                           |----event.add.ctrl.js
|                           |----event.add.mdl.js
|                 |----feed
|                           |----event.feed.ctrl.js
|                           |----event.feed.mdl.js
|                 |----profile
|                           |----event.profile.ctrl.js
|                           |----event.profile.mdl.js
|                 |----event.ctrl.js
|                 |----event.mdl.js
|                 |----event.service.js
|       |----user
|                 |----profile
|                           |----user.profile.ctrl.js
|                           |----user.profile.mdl.js
|                 |----settings
|                           |----user.settings.ctrl.js
|                           |----user.settings.mdl.js
|                 |----user.ctrl.js
|                 |----user.mdl.js
|                 |----user.service.js
|       |----main.mdl.js
|----dist
|       |----css
|       |----img
|       |----js
|----css
|----views
|----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>Events 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">


    
    
    <!--[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:

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

var gulp = require('gulp'),
    webserver = require('gulp-webserver'),
    minifyCSS = require('gulp-minify-css'),
    concatCss = require('gulp-concat-css'),
    concat = require('gulp-concat'),
    wiredep = require('wiredep').stream,
    autoprefixer = require('gulp-autoprefixer');

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('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 config.js. Copy and paste the following code into your app/config/config.js file:

(function () {
    'use strict';

    var app = angular
                .module('main');

    app.constant('BUCKET_SLUG', 'your-bucket-slug');
    app.constant('URL', 'https://api.cosmicjs.com/v1/');
    app.constant('MEDIA_URL', 'https://api.cosmicjs.com/v1/your-bucket-slug/media');
    app.constant('READ_KEY', 'your-read-key');
    app.constant('WRITE_KEY', 'your-write-key');
    app.constant('DEFAULT_EVENT_IMAGE', 'url-image');

})();
            

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

(function () {
    'use strict';

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

            'event',
            'user'
        ])
        .config(config)
        .run(run);

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

        $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_USER':
                    state = 'main.event.feed';
                    break;
            }

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

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

    run.$inject = ['$rootScope', '$cookieStore', '$http', 'crAcl', 'AuthService'];
    function run($rootScope, $cookieStore, $http, crAcl, AuthService) {

        $rootScope.globals = $cookieStore.get('globals') || {};
        $http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

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

        crAcl
            .setRedirect('auth');

        if ($rootScope.globals.currentUser) {

            crAcl.setRole($rootScope.globals.currentUser.metadata.role);
        }
        else {
            crAcl.setRole();
        }

    }

})();
            

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.register = register;

        vm.showRegisterForm = false;

        vm.loginForm = null;
        vm.registerForm = 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('main.event.feed');
                    }
                    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);
        }

        function register(credentials) {
            function success(response) {
                $log.info(response);

                var currentUser = response.data.object.metafields;

                Flash.create('success', 'You have successfully signed up!');
                vm.credentials = {
                    username: currentUser[0].value,
                    password: currentUser[3].value
                };
                vm.showRegisterForm = false;
            }

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

            if (vm.registerForm.$valid)
                AuthService
                    .register(credentials)
                    .then(success, failed);
        }

    }
})();
            

Now we will create our Auth Service in app/auth/auth.service.js:

(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: 'username',
                        metafield_value_has: credentials.username,
                        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.register = function (user) {

                return $http.post(URL + BUCKET_SLUG + '/add-object', {
                    title: user.full_name,
                    type_slug: 'users',
                    slug: user.username,
                    metafields: [
                        {
                            key: "username",
                            type: "text",
                            value: user.username
                        },
                        {
                            key: "email",
                            type: "text",
                            value: user.email
                        },
                        {
                            key: "full_name",
                            type: "text",
                            value: user.full_name
                        },
                        {
                            key: "password",
                            type: "text",
                            value: user.password
                        },
                        {
                            key: "image",
                            type: "file",
                            value: "3b2180f0-2c40-11e7-85ac-e98751218524-1493421969_male.png"
                        },
                        {
                            key: "role",
                            type: "radio-buttons",
                            options: [
                                {
                                    value: "ROLE_USER"
                                },
                                {
                                    value: "ROLE_SUPER_ADMIN"
                                }
                            ],
                            value: "ROLE_USER"
                        }
                    ],

                    write_key: WRITE_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 User Controller for get current user and log out, copy and paste the code below:

(function () {
    'use strict';

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

    function UserCtrl($rootScope, $scope, $state, AuthService, Flash, $log) {
        var vm = this;

        vm.currentUser = $rootScope.globals.currentUser.metadata;

        vm.logout = logout;

        function logout() {
            function success(response) {
                $state.go('auth');

                $log.info(response);
            }

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

            AuthService
                .clearCredentials()
                .then(success, failed);
        }

        $scope.state = $state;

    }
})();
            

Next we will create our Create User Module:

(function () {
    'use strict';

    angular
        .module('user', [
            'user.profile',
            'user.settings'
        ])
        .config(config);

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

        $stateProvider
            .state('main.user', {
                url: 'user',
                abstract: true,
                data: {
                    is_granted: ['ROLE_USER']
                }
            });
    }
})();
            

What's going on here:

  1. We created User Service for our asynchronous calls to our Cosmic JS API.
  2. We created User Controller for getting current user and logout.

Next we will create our Event Service to get, update, add delete Events from the Cosmic JS API:

(function () {
    'use strict';

    angular
        .module('main')
        .service('EventService', function ($http,
                                          $cookieStore,
                                          $q,
                                          $rootScope,
                                          URL, BUCKET_SLUG, READ_KEY, WRITE_KEY, MEDIA_URL) {

            $http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

            this.getEvents = function () {
                return $http.get(URL + BUCKET_SLUG + '/object-type/events', {
                    params: {
                        limit: 100,
                        read_key: READ_KEY
                    }
                });
            };
            this.getEventsByUsername = function (username, ignoreLoadingBar) {
                return $http.get(URL + BUCKET_SLUG + '/object-type/events/search',
                    {
                        ignoreLoadingBar: ignoreLoadingBar,
                        params: {
                            metafield_key: 'user',
                            metafield_object_slug: username,
                            limit: 10,
                            read_key: READ_KEY
                        }
                    }
                );
            };
            this.getEventById = function (slug) {
                return $http.get(URL + BUCKET_SLUG + '/object/' + slug, {
                    params: {
                        read_key: READ_KEY
                    }
                });
            };
            this.updateEvent = function (event) {
                event.write_key = WRITE_KEY;

                return $http.put(URL + BUCKET_SLUG + '/edit-object', event);
            };
            this.removeEvent = function (slug) {
                return $http.delete(URL + BUCKET_SLUG + '/' + slug, {
                    ignoreLoadingBar: true,
                    headers:{
                        'Content-Type': 'application/json'
                    },
                    data: {
                        write_key: WRITE_KEY
                    }
                });
            };
            this.createEvent = function (event) {
                event.write_key = WRITE_KEY;

                var beginDate = new Date(event.metafields[1].value);
                var endDate = new Date(event.metafields[2].value);

                event.metafields[1].value = beginDate.getFullYear() + '-' + (beginDate.getMonth() + 1) + '-' + beginDate.getDate();
                event.metafields[2].value = endDate.getFullYear() + '-' + (beginDate.getMonth() + 1) + '-' + endDate.getDate();

                event.slug = event.title;
                event.type_slug = 'events';

                event.metafields[4] = {
                    key: "user",
                    type: "object",
                    object_type: "users",
                    value: $rootScope.globals.currentUser._id
                };
                return $http.post(URL + BUCKET_SLUG + '/add-object', event);
            };
            this.upload = function (file) {
                var fd = new FormData();
                fd.append('media', file);
                fd.append('write_key', WRITE_KEY);

                var defer = $q.defer();

                var xhttp = new XMLHttpRequest();

                xhttp.upload.addEventListener("progress",function (e) {
                    defer.notify(parseInt(e.loaded * 100 / e.total));
                });
                xhttp.upload.addEventListener("error",function (e) {
                    defer.reject(e);
                });

                xhttp.onreadystatechange = function() {
                    if (xhttp.readyState === 4) {
                        defer.resolve(JSON.parse(xhttp.response)); //Outputs a DOMString by default
                    }
                };

                xhttp.open("post", MEDIA_URL, true);

                xhttp.send(fd);

                return defer.promise;
            }
        });
})();
            

Our Event Controller will get all events and remove events:

(function () {
    'use strict';

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

    function EventCtrl(EventService, Notification, $log, $rootScope, DEFAULT_EVENT_IMAGE) {
        var vm = this;

        vm.getEvents = getEvents;
        vm.removeEvent = removeEvent;
        vm.DEFAULT_EVENT_IMAGE = DEFAULT_EVENT_IMAGE;

        function getEvents(username) {
            function success(response) {
                $log.info(response);

                vm.events = response.data.objects;
            }

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

            EventService
                .getEventsByUsername(username)
                .then(success, failed);
        }

        function removeEvent(slug) {
            function success(response) {
                $log.info(response);

                getEvents($rootScope.globals.currentUser.metadata.username);

                Notification.success('Deleted');
            }

            function failed(response) {
                Notification.error(response.data.message);

                $log.error(response);
            }

            EventService
                .removeEvent(slug)
                .then(success, failed);
        }
    }
})();
            

Our Event Module will render our events view:

(function () {
    'use strict';

    angular
        .module('event', [
            'event.profile',
            'event.feed',
            'event.add'
        ])
        .config(config);

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

        $stateProvider
            .state('main.event', {
                url: 'events',
                views: {
                    '': {
                        templateUrl: '../views/event/events.html',
                        controller: 'EventCtrl as vm'
                    }
                },
                data: {
                    is_granted: ['ROLE_USER']
                }
            });
    }

})();
            

What's going on here:

  1. We created Event Service for our asynchronous calls to our Cosmic JS API. We can create, update, remove and getting Events.
  2. We created Event Controller for getting all events and removing events.
  3. We created an Event Module to render our views.

Now let's create our Event Add Controller for adding events:

(function () {
    'use strict';

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

    function EventAddCtrl(EventService, Notification, $state, $log, $scope, MEDIA_URL, DEFAULT_EVENT_IMAGE, $timeout) {
        var vm = this;

        vm.createEvent = createEvent;
        vm.cancelUpload = cancelUpload;
        vm.upload = upload;

        vm.dateBeginPicker = false;
        vm.dateEndPicker = false;
        vm.contentEditor = true;
        vm.uploadProgress = 0;

        vm.event = {
            title: null,
            slug: null,
            content: null,
            metafields: [
                {
                    key: "image",
                    type: "file",
                    value: null
                },
                {
                    key: "date_begin",
                    type: "date",
                    value: null
                },
                {
                    key: "date_end",
                    type: "date",
                    value: null
                },
                {
                    key: "type",
                    type: "select-dropdown",
                    options: [
                        {
                            key: "social",
                            value: "Social"
                        },
                        {
                            key: "fun",
                            value: "Fun"
                        }
                    ],
                    value: "Social"
                }
            ]
        };

        $timeout(function() {
            vm.event.metafields[1].value = new Date();
            vm.event.metafields[2].value = new Date();
        }, 100);

        vm.flow = {};
        vm.background = {
            'background-image': 'url(' + DEFAULT_EVENT_IMAGE + ')'
        };

        vm.flowConfig = {
            target: MEDIA_URL,
            singleFile: true
        };

        function createEvent() {
            if (vm.flow.files[0])
                upload();
            else
                _createEvent(vm.event);
        }

        function _createEvent(event) {
            function success(response) {
                $log.info(response);

                Notification.success(
                    {
                        message: 'Created',
                        delay: 800,
                        replaceMessage: true
                    }
                );

                $state.go('main.event');
            }

            function failed(response) {
                Notification.error(
                    {
                        message: response.data.error,
                        delay: 4000,
                        replaceMessage: true
                    }
                );

                $log.error(response);
            }

            EventService
                .createEvent(event)
                .then(success, failed);
        }

        function cancelUpload() {
            vm.flow.cancel();
            vm.background = {
                'background-image': 'url(' + DEFAULT_EVENT_IMAGE.url + ')'
            };
        }

        $scope.$watch('vm.flow.files[0].file.name', function () {
            if (!vm.flow.files[0]) {
                return ;
            }
            var fileReader = new FileReader();
            fileReader.readAsDataURL(vm.flow.files[0].file);
            fileReader.onload = function (event) {
                $scope.$apply(function () {
                    vm.background = {
                        'background-image': 'url(' + event.target.result + ')'
                    };
                });
            };
        });

        function upload() {
            EventService
                .upload(vm.flow.files[0].file)
                .then(function(response){

                    vm.event.metafields[0].value = response.media.name;

                    createEvent(vm.event);

                    vm.flow.cancel();
                    vm.uploadProgress = 0;

                }, function(){
                    console.log('failed :(');
                }, function(progress){
                    vm.uploadProgress = progress;
                });

        }

    }
})();
            

Next we create the Event Module:

(function () {
    'use strict';

    angular
        .module('event.add', [])
        .config(config);

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

        $stateProvider
            .state('main.event.add', {
                url: '/add',
                views: {
                    '@main': {
                        templateUrl: '../views/event/event.profile.html',
                        controller: 'EventAddCtrl as vm'
                    }
                },
                data: {
                    is_granted: ['ROLE_USER']
                }
            });
    }

})();
            

What's going on here:

  1. We can add events.
  2. We can upload images.

Conclusion:

We were able to create a pretty complicated app to manage users, sessions, adding / editing events all through the Cosmic JS API. 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


In this Cosmic JS Developer Spotlight, we sat down with Devin Otway, a Software Engineer in San Francisco who currently works as a frontend engineer at Postmates. Devin recently launched a blog called Hacking Depression on Cosmic JS. Check him out on  Twitter  or  LinkedIn , and enjoy the Q/A.

Hello World!   We are officially in private beta mode.  Lots of work has been done up until this point to make Cosmic JS the best cloud-hosted content platform.  Sign up for an account and please send us some feedback.  Here is a copy of my blog post on the release:

Cosmic JS is a cloud-hosted content platform that makes it easy to manage content for websites and applications.

I built Cosmic JS because I saw a problem with scaling content across platforms and devices.  After years of building applications using installed content management systems, I became tired of rebuilding APIs to handle content distribution from a website to microsites, landing pages and applications.  I decided to build one API to handle all content outlets for easier and faster distribution, and Cosmic JS was born.

Cosmic JS allows for easy content management and distribution by giving you the power to store content as JSON objects in an API that can be delivered anywhere.


Cosmic JS is API-first, meaning your content can be distributed across all devices and platforms from your website, to microsites and landing pages, to native mobile applications which allows for faster development cycles.   And when you use Cosmic JS to serve data and files, application servers can be kept light-weight which saves on server costs.

Get started

Click here to sign up for a Cosmic JS account, it’s completely free to sign up.

Cosmic JS is currently in private beta but you will be notified when your account has been activated.

Start building

Click here to check out the available clients for JavaScript and PHP on GitHub.

Currently there are available clients for JavaScript and PHP to help you get started building scalable, content-ready applications.

View examples

Click here to view code for websites built using Cosmic JS.

I’ll post some tutorials on this blog soon to show you how easy it is to use Cosmic JS to manage content for your next project, so stay tuned.  If you have any questions, please post them below, or reach out to me on twitter or email me.

Thanks,
Tony Spiro

Click here to go to Cosmic JS
Click here to go to Cosmic JS on GitHub

Don’t project, just build it cool and easily usable.

Make it the best option available.

Make it the product YOU want to use.

Cosmic JS debutes its Enterprise Plans for Content Management and Application Development. 

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.

Now you can view the status of your deployment attempts.