Skip to content

Instantly share code, notes, and snippets.

@hectoregm
Last active October 3, 2020 19:05
Show Gist options
  • Save hectoregm/9572359 to your computer and use it in GitHub Desktop.
Save hectoregm/9572359 to your computer and use it in GitHub Desktop.
Tutorial for basic CRUD using AngularJS and Firebase

Tutorial para AngularFire (AngularJS + Firebase)

Introduccion

En este tutorial haremos uso de AnguarJS y de Firebase (esta combinacion es tambien llamada AngularFire) para implementar un CRUD basico para el ingreso de usuarios. En este tutorial se tiene como requisitos tener instalado git y tener una cuenta en Firebase

AngularJS

Es un framework MVC que esta implementado en Javascript este vive en el lado del cliente (navegador) y dado que usaremos como backend a Firebase que nos da un BD desde el cliente es solo necesario un servidor web para poder enviar HTML, CSS y el Javascript de la aplicacion. Haremos uso de un servidor web usando Node.js desde la consola para ver como va nuestra aplicacion.

Hay que bajar e instalar Node.js hay paquetes para todos los SO principales.

Firebase

Firebase es una API que permite el almacenar y sincronizar informacion en milisegundos. Esta construido para dar servicio a aplicaciones mobiles o de web que necesitan de actualizaciones en tiempo real usando codigo del lado del cliente.

Hay que entrar a la pagina de registro de Firebase donde se debe ingresar el correo electronico y el password que se quiere utilizar para acceder a la cuenta. Se da click en 'Create Account' y nos lleva al dashboard de Firebase en donde nos crea nuestra primera aplicacion 'My First App' con su BD asociado de Firebase que debe ser de la forma '*.firebaseIO.com' a esta URL la llamaremos FIREBASE_URL en lo que resta del tutorial y es necesario tenerla a la mano.

Git

Para tener git es solo necesario bajar el instalador en git-scm y seguir las instrucciones.

Tutorial

Ya estamos listos para comenzar, primero debemos obtener la semilla, el esqueleto de la aplicacion, para AngularFire. En esta semilla tenemos lo basico para empezar a desarrollar, ya tenemos la estructura de directorios, scripts de apoyo, etc. Para obtener esta semilla abrimos una terminal y ejecutamos lo siguiente:

$ git clone [email protected]:hectoregm/angular-seed.git
$ cd angular-seed

Paso 0: Arrancando la semilla

NOTA: El codigo de esta seccion se encuentra en el tag step-0:

$ git checkout -f step-0

Ahora es necesario ver que todo este listo para desarrollar principalmente que el servidor web con nodejs este funcionando asi que es necesario ya tener instalado node y ejecutar lo siguiente:

$ node ./scripts/web-server.js

Este comando responde con algo parecido a "Http Server running at http://localhost:8000/" lo cual indica que esta sirviendo la aplicacion. Ahora el punto de entrada a una aplicacion AngularJS es en http://localhost:8000/app/index.html, asi que es necesario abrir nuestro navegador favorito en esta URL para ver como va tomando forma la aplicacion conforme pasa el tutorial.

Paso 1: Configurando Firebase y HomeCtrl

NOTA: El codigo de esta seccion se encuentra en el tag step-1:

$ git checkout -f step-1

Primero vamos a agregar un modulo de configuracion a nuestra aplicacion donde iran varias constantes entre ellas FBURL que es el URL hace nuestra BD en Firebase (que es la URL que obtuvimos al abrir una cuenta en Firebase) usando un nuevo archivo app/js/config.js:

'use strict';

// Declare app level module which depends on filters, and services
angular.module('myApp.config', [])

   // version of this seed app is compatible with angularFire 0.6
   // see tags for other versions: https://github.com/firebase/angularFire-seed/tags
   .constant('version', '0.6')

   // where to redirect users if they need to authenticate (see module.routeSecurity)
   .constant('loginRedirectPath', '/login')

   // your Firebase URL goes here
   .constant('FBURL', 'https://INSTANCE.firebaseio.com');

Ahora vamos a implementar un servicio que ayuda a hacer referencias a las rutas a los datos en Firebase, este codigo lo ponemos en app/js/services.js y en app/js/service.firebase.js respectivamente:

(function() {

  'use strict';

  /* Services */


  angular.module('myApp.services', ['myApp.service.firebase']).
    value('version', '0.1');
})();
angular.module('myApp.service.firebase', ['firebase'])

// a simple utility to create references to Firebase paths
   .factory('firebaseRef', ['Firebase', 'FBURL', function(Firebase, FBURL) {
      /**
       * @function
       * @name firebaseRef
       * @param {String|Array...} path
       * @return a Firebase instance
       */
      return function(path) {
         return new Firebase(pathRef([FBURL].concat(Array.prototype.slice.call(arguments))));
      }
   }])

   // a simple utility to create $firebase objects from angularFire
   .service('syncData', ['$firebase', 'firebaseRef', function($firebase, firebaseRef) {
      /**
       * @function
       * @name syncData
       * @param {String|Array...} path
       * @param {int} [limit]
       * @return a Firebase instance
       */
      return function(path, limit) {
         var ref = firebaseRef(path);
         limit && (ref = ref.limit(limit));
         return $firebase(ref);
      }
   }]);

function pathRef(args) {
   for(var i=0; i < args.length; i++) {
      if( typeof(args[i]) === 'object' ) {
         args[i] = pathRef(args[i]);
      }
   }
   return args.join('/');
}

Es necesario agregar este codigo a index.html para que se cargue al abrir la aplicacion:

     <script src="js/app.js"></script>
     <script src="js/config.js"></script>
     <script src="js/services.js"></script>
     <script src="js/service.firebase.js"></script>
     <script src="js/controllers.js"></script>

Tambien es necesario hacer modificaciones para activar a Firebase como un servicio mas en AngularJS, ademas vamos añadir una vista que va ser el home de la aplicacion. Asi tenemos que modificar app/js/app.js:

'use strict';


// Declare app level module which depends on filters, and services
angular.module('myApp', [
  'firebase',
  'ngRoute',
  'myApp.filters',
  'myApp.services',
  'myApp.directives',
  'myApp.controllers'
])
  .run(['$rootScope', 'FBURL', function($rootScope, FBURL) {
    if( FBURL === 'https://INSTANCE.firebaseio.com' ) {
      // double-check that the app has been configured
      angular.element(document.body).html('<h1>Please configure app/js/config.js before running!</h1>');
      setTimeout(function() {
        angular.element(document.body).removeClass('hide');
      }, 250);
    }
    else {
      $rootScope.FBURL = FBURL;
    }
  }])
  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/home',  {templateUrl: 'partials/home.html', controller: 'HomeCtrl'})
    $routeProvider.otherwise({redirectTo: '/home'});
  }]);

Cremos un archivo para el parcial de home y borramos los parciales que estan de prueba:

$ touch app/partials/home.html
$ rm app/partials/partial1.html app/partials/partial2.html

Ahora vamos a implementar un controlador basico para que maneje la ruta '/home' en app/js/controllers.js:

'use strict';

/* Controllers */

angular.module('myApp.controllers', [])
  .controller('HomeCtrl', [function() {

  }]);

Paso 2: Creando un usuario

El codigo de esta seccion se encuentra en el tag step-2:

$ git checkout -f step-2

Vamos a empezar creando una nueva ruta, un controlador y la vista para crear un usuario. La ruta sera /users/new, siendo el controlador asociado NewUserCtrl y la vista se llamara new_user.html, las vistas se guardan por convencion en el directiorio app/partials.

Definiendo una nueva ruta

Queremos definir una ruta por la cual se despliegue una vista con una forma para ingresar los datos de un nuevo usuario esto se hace en AngularJS definiendo una ruta que indica el controlador que maneja la interaccion en esa ruta dada y la vista que esta asociada. Asi que modificaremos el archivo app/js/app.js:

  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/home',  {templateUrl: 'partials/home.html', controller: 'HomeCtrl'})
    $routeProvider.when('/users/new', {templateUrl: 'partials/new_user.html', controller: 'NewUserCtrl'});
    $routeProvider.otherwise({redirectTo: '/home'});
  }]);

Creando la vista

Ahora implementamos la vista app/partials/new_user.html:

<h1>Create new user</h1>

<form class="form-horizontal" role="form">
  <div class="form-group">
    <label for="username" class="col-sm-2 control-label">Username:</label>
    <div class="col-sm-4">
      <input class="form-control" id="username"
             ng-model="user.username" placeholder="johnsmith"/>
    </div>
  </div>
  
  <div class="form-group">
    <label for="firstName" class="col-sm-2 control-label">First name:</label>
    <div class="col-sm-4">
      <input class="form-control" id="firstName"
             ng-model="user.firstName" placeholder="John"/>
    </div>
  </div>

  <div class="form-group">
    <label for="lastName" class="col-sm-2 control-label">Last name:</label>
    <div class="col-sm-4">
      <input class="form-control" id="lastName"
             ng-model="user.lastName" placeholder="Smith"/>
    </div>
  </div>

  <div class="form-group">
    <label for="email" class="col-sm-2 control-label">Email:</label>
    <div class="col-sm-4">
      <input type="email" class="form-control" id="email"
             ng-model="user.email" placeholder="[email protected]"/>
    </div>
  </div>

  <div class="form-group">
    <label for="password" class="col-sm-2 control-label">Password:</label>
    <div class="col-sm-4">
      <input type="password" class="form-control" id="password"
             ng-model="user.password" placeholder=""/>
    </div>
  </div>

  <div class="form-group">

    <div class="col-sm-offset-2 col-sm-10">
      <a ng-click="createNewUser()" class="btn btn-small btn-primary">Create</a>
    </div>
  </div>
</form>

Implementando el controlador NewUserCtrl

Ahora implementamos el controlador en app/js/controllers.js:

'use strict';

/* Controllers */

angular.module('myApp.controllers', [])
  .controller('HomeCtrl', [function() {

  }])
  .controller('NewUserCtrl', ['$scope', '$location', 'firebaseRef', function($scope, $location, firebaseRef) {
    $scope.createNewUser = function () {
      firebaseRef('users/'+ $scope.user.username).set({
        id: $scope.user.username,
        firstName: $scope.user.firstName,
        lastName: $scope.user.lastName,
        email: $scope.user.email,
        password: $scope.user.password
      });
      $location.path('/home');
    }
  }]);

Ahora solo queda agregar un link en el /home para poder crear un nuevo usuario en index.html:

    <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">AngularJS + Firebase Tutorial</a>
        </div>
        <div class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
            <li><a href="#/users/new">Create New User</a></li>
            <li><a href="#">Help</a></li>
          </ul>
        </div>
      </div>
    </div>

Asi agregamos un usuario nuevo:

Y vemos el cambio reflejado en Firebase:

Paso 3: Mostrar todos los usuarios

El codigo de esta seccion se encuentra en el tag step-3:

$ git checkout -f step-3

Ahora vamos a mostrar a todos los usuarios en el sistema, nuevamente vamos a crear una nueva ruta, controlador y vista. La ruta sera /users, siendo el controlador asociado UserCtrl y la vista se llamara user_index.html.

Definiendo la nueva ruta

Modificamos nuevamente el archivo app/js/app.js:

  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/users',  {templateUrl: 'partials/user_index.html', controller: 'UserCtrl'});
    $routeProvider.when('/users/new', {templateUrl: 'partials/new_user.html', controller: 'NewUserCtrl'});
    $routeProvider.otherwise({redirectTo: '/users'});
  }]);

Creando la vista

Ahora implementamos la vista, las funciones editUser y deleteUser las implementaremos en los siguientes pasos app/partials/user_index.html:

<h2>Users</h1>
<div class="span6">
  <table class="table table-striped table-condensed">
    <thead>
      <tr>
        <th style="min-width: 80px;">Username</th>
        <th style="min-width: 80px;">First name</th>
        <th style="min-width: 80px;">Last name</th>
        <th style="min-width: 80px;">Email</th>
        <th style="min-width: 80px;">Password</th>
        <th style="width:20px;"> </th>
        <th style="width:20px;"> </th>
      </tr>
    </thead>
    <tbody>
      <tr ng-repeat="user in users">
        <td>{{ user.id }}</td>
        <td>{{ user.firstName }}</td>
        <td>{{ user.lastName }}</td>
        <td>{{ user.email }}</td>
        <td>{{ user.password }}</td>
        <td><a ng-click="editUser(user.id)" class="btn btn-small btn-primary">Edit</a></td>
        <td><a ng-click="deleteUser(user.id)" class="btn btn-small btn-danger">Delete</a></td>
      </tr>
    </tbody>
  </table>
  <a ng-click="createNewUser()" class="btn btn-small btn-primary">Create New User</a>
</div>

Implementando el controlador UserCtrl

Ahora implementamos el controlador en app/js/controllers.js:

  }])
  .controller('UserCtrl', ['$scope', '$location', 'syncData', function($scope, $location, syncData) {
    $scope.users = syncData('users');

    $scope.createNewUser = function () {
      $location.path('/users/new');
    };
  }]);

Asi se ve ahora la aplicacion despues de agregar unos usuarios mas:

Paso 4: Editar un usuario

El codigo de esta seccion se encuentra en el tag step-4:

$ git checkout -f step-4

Ahora vamos a editar la informacion de un usuario ya en el sistema. La ruta sera /users/:id, siendo el controlador asociado UserDetailCtrl y la vista se llamara user.html.

Definiendo la nueva ruta

Modificamos nuevamente el archivo app/js/app.js:

  .config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/users',  {templateUrl: 'partials/user_index.html', controller: 'UserCtrl'});
    $routeProvider.when('/users/new', {templateUrl: 'partials/new_user.html', controller: 'NewUserCtrl'});
    $routeProvider.when('/users/:id',  {templateUrl: 'partials/user.html', controller: 'UserDetailCtrl'});
    $routeProvider.otherwise({redirectTo: '/users'});
  }]);

Creando la vista

Creamos la siguiente vista en app/partials/user.html:

<h1>User Detail</h1>

<form class="form-horizontal" role="form">
  <div class="form-group">
    <label for="username" class="col-sm-2 control-label">Username:</label>
    <div class="col-sm-4">
      <input disabled class="form-control" id="username"
             ng-model="user.id" placeholder="johnsmith"/>
    </div>
  </div>

  <div class="form-group">
    <label for="firstName" class="col-sm-2 control-label">First name:</label>
    <div class="col-sm-4">
      <input class="form-control" id="firstName"
             ng-model="user.firstName" placeholder="John"/>
    </div>
  </div>

  <div class="form-group">
    <label for="lastName" class="col-sm-2 control-label">Last name:</label>
    <div class="col-sm-4">
      <input class="form-control" id="lastName"
             ng-model="user.lastName" placeholder="Smith"/>
    </div>
  </div>

  <div class="form-group">
    <label for="email" class="col-sm-2 control-label">Email:</label>
    <div class="col-sm-4">
      <input type="email" class="form-control" id="email"
             ng-model="user.email" placeholder="[email protected]"/>
    </div>
  </div>

  <div class="form-group">
    <label for="password" class="col-sm-2 control-label">Password:</label>
    <div class="col-sm-4">
      <input type="password" class="form-control" id="password"
             ng-model="user.password" placeholder=""/>
    </div>
  </div>

  <div class="form-group">

    <div class="col-sm-offset-2 col-sm-10">
      <a ng-click="cancel()" class="btn btn-small">Cancel</a>
      <a ng-click="updateUser()" class="btn btn-small btn-primary">Update</a>
    </div>
  </div>
</form>

Implementando el controlador UserDetailCtrl

Ahora implementamos el controlador en app/js/controllers.js:

  .controller('UserDetailCtrl', ['$scope', '$location', '$routeParams', 'syncData', function($scope, $location, $routeParams, syncData) {
    $scope.user = syncData('users/' + $routeParams.id);
    $scope.updateUser = function () {
      $scope.user.$update({
        firstName: $scope.user.firstName,
        lastName: $scope.user.lastName,
        email: $scope.user.email,
        password: $scope.user.password
      });

      $location.path('/users');
    }
    $scope.cancel = function () {
      $location.path('/users');
    };
  }])
  .controller('UserCtrl', ['$scope', '$location', 'syncData', function($scope, $location, syncData) {
    $scope.users = syncData('users');

Modificamos al usuario hectoregm:

Cambiamos el nombre y la contraseña:

Y vemos los cambios:

Paso 5: Editar un usuario

El codigo de esta seccion se encuentra en el tag step-5:

$ git checkout -f step-5

Ahora vamos a eliminar un usuario del sistema esto sera en donde listamos todos los usuarios es decir en /users Como ya tenemos la vista y el boton en la tabla de usuarios solo queda implementar el callback deleteUser.

Modificando el controlador UserCtrl

Ahora hacemos las siguientes modificaciones en app/js/controllers.js:

  .controller('UserCtrl', ['$scope', '$location', 'syncData', function($scope, $location, syncData) {
    $scope.users = syncData('users');

    $scope.createNewUser = function () {
      $location.path('/users/new');
    };

    $scope.editUser = function (id) {
      $location.path('/users/' + id);
    };

    $scope.deleteUser = function(id) {
      $scope.user = syncData('users/' + id);
      $scope.user.$remove();
    }
  }]);

Final

Ya con esto tenemos un CRUD completo usando AngularJS y Firebase.

@jcjocop
Copy link

jcjocop commented Apr 28, 2016

Estimado Hector. Es posible obtener el código completo ? Yo fui creando cada archivo según los pasos pero al llegar al controller.js, usted indica que hay que "crearlo" de nuevo cuando ya se había creado antes (ver paso 2, sección: Implementando el controlador NewUserCtrl y paso 3, sección Implementando el controlador UserCtrl); por lo cual me confundí. Supongo además que usted utiliza el templeta seed. Gracias.

@alka33
Copy link

alka33 commented May 10, 2016

jcjocop lograsates resolver?

@jcjocop
Copy link

jcjocop commented May 10, 2016

Si. Lo que no se ahora es como eliminar un usuario. Gracias por preguntar

@J-Alex
Copy link

J-Alex commented May 27, 2016

¿cómo podría cambiar localhost en mi app local de firebase con una direccion diferente?

@herduin
Copy link

herduin commented Apr 3, 2020

Esta es la URL del repo con todo el ejemplo: https://github.com/hectoregm/angular-seed # #

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment