Wednesday 26 June 2013

First Crud in Rails+Angular JS



Get the whole code here: https://github.com/aarkerio/rails-angularjs

This a howto about how create your first R+AJS. AngularJS (AJS) is an Ecmascript framework that gives a further and deeper step into the DOM-Javascript merge. AJS is a bidirectional framework, this means that DOM elements and the Javascript code are under an uninterrupted communication and using the $scope object as the application "glue". This "magic link" will saves you many problems and will improve your productivity. This more completes and advanced features are the reason of why AJS is chosen over another options as Backbone.  

 
As you can all starts with the classic:

$ rails new myangular

Now you must download angular.min.js from the angular site currently 1.0.6 and set in the dir APP/assets/javascripts.

Now we create the dirs wee need:

$ mkdir app/assets/javascript/angular
$ mkdir app/assets/javascript/angular/controllers

The Task controller:


// file: app/assets/javasript/angular/controller/tasks_controller.js

'use strict';

Site.controller('crudController', ['$scope', 'Task', 'Tasks', 'EditTask', function($scope, Task, Tasks, EditTask) {

 $scope.orderProp = 'description';
 $scope.tasks = Tasks.get();  // initial fill

 $scope.$watch('tasks', function() {
   console.log('scope.tasks has changed');
  }, true);
 // add task
 $scope.addTask = function(task) {
    Task.save({task:task});
    console.log('addTask: getTasks function'+JSON.stringify($scope.tasks));
    $scope.task.description = '';   // clean form
    $scope.tasks = Tasks.get();  // refill list
  };

  // edit 
  $scope.EditCtrl = function(task) {
        $scope.task = EditTask.get();
        console.log('EditCtrl function'+JSON.stringify(task));
        //console.log('addTask: getTasks function'+JSON.stringify($scope.task));
        //$scope.task = {'task':task};
  };
  
  // remove
  $scope.removeTask = function(task) {
    console.log(task);
    var deleteUser = confirm('Are you absolutely sure you want to delete?'); 
    if (deleteUser) 
    {
        $scope.id = task.id;
        Task.delete({id:task.id});      // services task.js
        // $scope.tasks = Tasks.get();  // refill list
        $scope.tasks = Tasks.get();    // refill list
    }
  };
}]);

Site.controller('TaskDetailCtrl', ['$scope', '$location', '$routeParams', 'Task', 'Tasks', 'EditTask', function($scope, $location, $routeParams, Task, Tasks, EditTask) {
   console.log('TaskDetailCtrl: '+JSON.stringify($routeParams));
   $scope.task = EditTask.get($routeParams);
   // console.log('scope.task:' + JSON.stringify( $scope.task ));
   // update
    $scope.updateTask = function(task) {
      console.log('update function task:' + JSON.stringify(task));
      //console.log($routeParams);
      Task.update({id:task.id}, task);
      $location.path('/tasks');
   };

  // remove
  $scope.removeTask = function(task) {
     console.log(task);
     var deleteUser = confirm('Are you absolutely sure you want to delete?'); 
     if (deleteUser) 
     {
         $scope.id = task.id;
         Task.delete({id:task});  // services task.js
         $location.path('/tasks');
     }
  };

}]);

function TaskShowCtrl($scope, $location, $routeParams, $dialog, Movie) {"use strict";
    $scope.task = Task.show({
        task_id : $routeParams.task_id
    });
} 

The app file:

// file: app/assets/javascripts/angular/app.js
'use strict';

// Declare app level module which depends on filters, and services
var services    = angular.module("crudServices", []); 
var controllers = angular.module("crudController", []);
var Site        = angular.module('Site', ['ngResource', 'crudServices', 'crudController']);

Site.config(function ($routeProvider, $locationProvider) {
  $routeProvider
                .when('', {redirectTo: '/' })
                .when('/tasks', {templateUrl: '/assets/angular/partials/tasks/index.html', controller: 'crudController'})
                .when('/tasks/:id', {templateUrl:'assets/angular/partials/tasks/show.html', controller:TaskShowCtrl})
                .when('/tasks/:id/edit', {templateUrl:'detail.html', controller:'TaskDetailCtrl'})
                .otherwise({redirectTo:"/"});
  // configure html5 to get links working on jsfiddle
  $locationProvider.html5Mode(true);
});

// Rails Token
Site.config(['$httpProvider', function(provider) {
  provider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');  // this needs jquery
  provider.defaults.headers.post["Content-Type"]   = "application/json; charset=UTF-8";
}]);

The directive file:

// file: app/assets/javascripts/angular/directives/tasks_directives.js
Site.directive('editInPlace', function() {
  return {
    restrict: 'A',
    scope: { value:"=editInPlace" },
    template: '',
    link: function ( $scope, element, attrs ) {
      // Let's get a reference to the input element, as we'll want to reference it.
      var inputElement = angular.element( element.children()[1] );
      
      // This directive should have a set class so we can style it.
      // element.addClass( '.edit-in-place' );
      
      // Initially, we're not editing.
      $scope.editing = false;
      
      // ng-click handler to activate edit-in-place
      $scope.edit = function () {
            $scope.editing = true;
        
            // We control display through a class on the directive itself. See the CSS.
            element.addClass( 'active' );
        
            // And we must focus the element. 
            // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function, 
            // we have to reference the first element in the array.
            inputElement[0].focus();
      };
      
      // When we leave the input, we're done editing.
      inputElement.prop('onblur', function() {
          $scope.editing = false;
          element.removeClass( 'active' );
      });
    }
  };
});

No comments: