Monday, November 7, 2016

ngTable - CRUD operation in Table/Grid

To demonstrate CRUD operations in ngTable I will be using an example of the Employee portal in all my posts. This Employee portal has capabilities of adding, viewing, editing and deleting employee skill details. 



In this section we will be looking into the editable view of the employee page. This page has following functionalities:



- Option to add the new skill row(s) in the employee skill grid. (Add New Skill button below the grid)

- Option to remove exiting skill row. (Delete button in each row)

- Option to save employee skill data. (Save button below the grid)



- Filter skill name list based on skill type selected.

- When skill type is Technical, the Skill name cell gets filtered with data of type 'Technical'











- When skill type is 'Domain', skill name cell gets filtered with data of type 'Domain'.



- When skill type is 'Personal', skill name cell gets filtered with the data of type 'Personal'.





- Rating column has the option to select ratings from 1 to 5.

- Is Primary is the check-box column to say if the skill is primary or secondary. 







I will be dividing employee edit page in two parts. 
  • The first part talks bout the basic requirements of the editable view of the employee page and will cover the UI part of it along with basic functionalities like drop-down box data filtering and dependency between the controls. 
  • The second part is going to cover the core functionalities (add, remove, save) of the employee edit page.
In the previous post we had seen the employee and skill models. In this section I am providing the skeleton of  the web APIs and service to get the required data from the database. (As stated in the previous post the full source code of this application will be provided at the end of the series).

 [Route("api/[controller]")]
    public class EmployeeController : BaseController
    {
        private readonly JsonSerializerSettings _serializerSettings;

        IEmployeeServices _service;

        public EmployeeController(IEmployeeServices service)
        {
            _service = service;
            _serializerSettings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented
            };
        }

        // GET api/values
        [HttpGet]      
        public IEnumerable<Employee> Get()
        {
            return _service.GetAll();
        }

        // GET api/values/1
        [HttpGet("{id}")]
        public Employee Get(int id)
        {
            return _service.Get(id);
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]Employee Employee)
        {
            _service.Add(Employee);
        }

        [HttpPut]
        public void Put([FromBody]Employee Employee)
        {
            _service.Update(Employee);
        }

        // DELETE api/values/1
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
            _service.Delete(id);
        }

    }

  [Route("api/[controller]")]
    public class SkillController : BaseController
    {
        private readonly JsonSerializerSettings _serializerSettings;

        ISkillServices _service;

        public SkillController(ISkillServices service)
        {
            _service = service;
            _serializerSettings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented
            };
        }

        // GET api/values
        [HttpGet]
        //[Authorize(Policy = "Admin")]
        public IEnumerable<Skill> Get()
        {
            return _service.GetAll();
        }

        // GET api/values/1
        [HttpGet("{id}")]
        public Skill Get(int id)
        {
            return _service.Get(id);
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]Skill skill)
        {
            _service.Add(skill);
        }

        [HttpPut]
        public void Put([FromBody]Skill skill)
        {
            _service.Update(skill);
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
            _service.Delete(id);
        }
    }

Now lets build a view to display the employee details in AngularJS application. Below are the steps you need to follow:
  • Add ngTable module to where the app module is being declared.
                 var myApp = angular.module("myApp", ["ngTable"])
  • In the HTML file (partial view) add the following code where you want your employee skill table to appear. We have used Text boxes, drop-down boxes and the checkbox controls in the view to make the screen editable.  
            <div>
               <table ng-table="employeeSkills">
                  <tr ng-repeat="skill in $data">
                    <td data-title="'#'">{{$index + 1}}</td>
                    <td data-title="'Skill Type'" >
         <select name="skillType_{{$index +1}}" id="skillType_{{$index +1}}" ng-model="skill.skill.type" 
                                    ng-options="type.name for type in skillTypes track by type.id" 
                                    required ng-change="skillTypeChanged(skill.skill, $index)"></select>
                     </td>
                     <td data-title="'Skill Name'" >
<select name="skillName_{{$index +1}}" id="skillName_{{$index +1}}" ng-model="skill.skill"                                                                
                                ng-options="skillName.skillName for skillName in (availableSkills | filter:{type: {id: skill.skill.type.id}})
                                 track by skillName.id"   ></select>
                     </td>

                     <td data-title="'Rating '" >
                         <span>{{skill.rating }}</span>
                     </td>

                    <td data-title="'Is Primary'" >

                   <input type="checkbox" ng-model="skill.isPrimary" value="{{skill.isPrimary}}" />

                   </td>
                  <td>
                        <button  ng-click="removeSkill(skill)">   Delete  </button>

                    </td>

                </tr>

             </table>
        <table class="table">            
            <tr>
                <td>
                   <button  ng-click="addNewSkill()">Add New Skill</button>                   
                </td>
                <td>
                    <button  ng-click="save()" >Save</button>
                </td>              
            </tr>

        </table>

          </div
  • In the controller JavaScript file add the below code: (The employeeSkills are being hard coded here but in actual scenario a service call need to be made to get the details from database, I will be uploading the full source code at the end of the series so till then please bear with the hard coded values) .The object count of the object ngTableParams is set to empty array to make sure that pagination is disabled. The object dataset of the object ngTableParams is set with the employee skill data.  
           myApp.controller('editEmployeeSkillController', ['ngTableParams', '$scope', 
                  function (ngTableParams, $scope) {
                     $scope.skillTypes =  [{id: 1, name: 'Technical'},
                                                        {id: 2, name: 'Domain'},
                                                        {id: 3, name: 'Personal'}];
                                                   
                    var skills = [{type: {id: 1, name: 'Technical'}, name: 'Java', id: 1},
                       {type: {id: 1, name: 'Technical'}, name: '.NET', id: 2},
                       {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 3},
                       {type: {id: 1, name: 'Domain'}, name: 'LifeScience', id: 4},
                       {type: {id: 2, name: 'Domain'}, name: 'Media', id: 5},
                       {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6}];
            
        //These two lines are needed to create the dependency between skilltype and skill drop-down boxes          
        $scope.availableSkills = angular.copy(skills);
        $scope.originalSkills = angular.copy(skills);

                        var employee = {id: 1, firstName: 'Pratibha', lastName: 'Hyanki', employeeId:'xxx',
                              skills: [{skill: {type: {id: 1, name: 'Technical'}, name: '.Net', id: 2} isPrimary: true rating:5 id:1},
                                   { skill: {type: {id: 2, name: 'Domain'}, name: Media, id: 5} isPrimary:false, rating:3 id:2},          
                     { skill: {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6} isPrimary:true rating:1 id:3},
                                   { skill: {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 3}, isPrimary: trye rating:2  id:4}
                                  ]}; 

                       $scope.employeeSkills= new ngTableParams({}, {
                           dataset: employee.skills,
                           counts: []
                   });

          $scope.skillTypeChanged = function (skill, index) {
              $scope.availableSkills = angular.copy($scope.originalSkills );
              for (var i = 0; i < $scope.availableSkills.length; i++) {
                     if (skill.type.id == $scope.availableSkills[i].type.id) {
                         $scope.employeeSkills[index].skill = angular.copy($scope.availableSkills[i]);
                              break;
                     }
               }              
               $scope.availableSkills = angular.copy($scope.originalSkills );
          };  

       $scope.removeSkill = function (row) {
              var test = row;
              for (var i = 0; i < $scope.employeeSkills.length; i++) {
                  if (row === $scope.employeeSkills[i]) {
                        $scope.employeeSkills.splice(i, 1);
                           return;
                   }
               }
          };

      $scope.addNewSkill = function () {
           var row = { skill: "" id: "" isPrimary: false, rating: "" };
           $scope.employeeSkills.push(row);
      };

      $scope.save = function () {
           // code to save employee skill data
       };
         }]);

Saturday, November 5, 2016

ngTable - Readonly Table

To demonstrate ngTable capabilities I will be using an example of the Employee portal in all my posts. This Employee portal has capabilities of adding, viewing, editing and deleting employee skill data. 

Employee Skill View screen looks as below:

We have the employee data models in following manner:

    public class Employee
    {
        public Employee()
        {
        }
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName {get; set;}
        public IList<Skill> Skills { get; set; }                
    } 

  public class Skill
    {
        public Skill()
        {
        }
        public int ID { get; set; }
        public string Bame{ get; set; }
        public SkillType Type{get; set;}
        public int Rating { get; set; }   
        public int IsPrimary{ get; set; }              
    } 


  public class SkillType
    {
        public SkillType()
        {
        }
        public int ID { get; set; }
        public string Name{ get; set; } 
    } 

Lets assume that the services to get the employee data is already available, now lets build a view to display the employee details in angularJS application. Below are the steps you need to follow:
  • Add ngTable module to where the app module is being declared.
                 var myApp = angular.module("myApp", ["ngTable"])
  • In the HTML file (partial view) add the following code where you want your employee skill table to appear. We have used Span in place of text-boxes and drop-down boxes and disabled the checkbox as this is just the view screen of employee skills. 
            <div>

               <table ng-table="employeeSkills">

                  <tr ng-repeat="skill in $data">

                    <td data-title="'#'">{{$index + 1}}</td>

                    <td data-title="'Skill Type'" >

                         <span>{{skill.type.name }}</span>

                     </td>

                     <td data-title="'Skill Name'" >

                           <span>{{skill.name }}</span>

                     </td>
                     <td data-title="'Rating '" >
                         <span>{{skill.rating }}</span>
                     </td>
                    <td data-title="'Is Primary'" >
                   <input type="checkbox" ng-model="skill.isPrimary" value="{{skill.isPrimary}}" disabled />
                   </td>
                </tr>
             </table>
          </div
  • In the controller javascript file add the below code: (The employeeSkills are being hard coded here but in actual scenario a service call need to be made to get the details from database, I will be uploading the full source code at the end of the series so till then please bear with the hard coded values) .The object count of the object ngTableParams is set to empty array to make sure that pagination is disabled. The object dataset of the object ngTableParams is set with the employee skill data. 
          myApp.controller('viewEmployeeSkillController', ['ngTableParams', '$scope', 
                 function (ngTableParams, $scope) {

                 var skills = [

                            {name: "Java", type: {id: 1, name: 'Technical'}, rating: 2, IsPrimary: 'false'},

                            {name: "Life Science", type: {id: 2, name: 'Technical'}, rating: 4, IsPrimary: 'false'},

                            {name: "Communication", type: {id: 3, name: 'Technical'}, rating: 5, IsPrimary: 'false'}

                            ] ;     

                $scope.employeeSkills= new ngTableParams({}, {

                  dataset: skills,

                  counts: []
              });
          }]);


Friday, November 4, 2016

ng-table Depedent DropDown Boxes Part II

In this post I will be demonstrating how easy it is to make a drop-down box data dependent on the selected values of the other drop-down box in each row of the table, by using angular directives ng-model, ng-option and ng-change. 







The first three images shows how skills are dependent on skill types and last image shows the employee skill data in a grid/table.

To achieve this lets assume that we have skill types, skills and employee data as below:

skillTypes =  [{id: 1, name: 'Technical'},
                       {id: 2, name: 'Domain'},
                       {id: 3, name: 'Personal'}];

skills = [{type: {id: 1, name: 'Technical'}, name: 'Java', id: 1},
              {type: {id: 1, name: 'Technical'}, name: '.NET', id: 2},
              {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 3},
              {type: {id: 1, name: 'Domain'}, name: 'LifeScience,' id: 4},
              {type: {id: 2, name: 'Domain'}, name: 'Media', id: 5},
              {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6}];


employee = {id: 1, firstName: 'Pratibha', lastName: 'Hyanki', employeeId: 'xxx', 
                      skills: [ { skill: {type: {id: 1, name: 'Technical'}, name: '.NET', id: 2} id:1},
                                   {skill: {type: {id: 2, name: 'Domain'}, name: 'Media', id: 5} id:2},
                                   {skill: {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6} id:3},
                                   {skill: {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 6} id: 4}  
                                ]};

Now let's show this data in the screen with AngularJS and HTML.

Now lets build a view to display the dependency between two drop-down controls in angularJS application. Below are the steps you need to follow:
  • Add ngTable module to where the app module is being declared.
                 var myApp = angular.module("myApp", ["ngTable"])
  • In the controller javascript file add the below code: 
  •        myApp.controller('editEmployeeSkillController', ['ngTableParams', '$scope', 
                  function (ngTableParams, $scope) {
                     $scope.skillTypes =  [{id: 1, name: 'Technical'},
                                                        {id: 2, name: 'Domain'},
                                                        {id: 3, name: 'Personal'}];           
                                        
                    var skills = [{type: {id: 1, name: 'Technical'}, name: 'Java', id: 1},
                                {type: {id: 1, name: 'Technical'}, name: '.NET', id: 2},
                                {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 3},
                                {type: {id: 1, name: 'Domain'}, name: 'LifeScience', id: 4},
                                {type: {id: 2, name: 'Domain'}, name: 'Media', id: 5},
                                {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6}];

                    //Needed to create dependency between skill type and skill drop-down boxes
            $scope.originalSkills = angular.copy(skills);
                    $scope.availableSkills = angular.copy(skills);

                    var employee = {id: 1, firstName: 'Pratibha', lastName: 'Hyanki', employeeId:'xxx',
                                     skills: [ {skill: {type: {id: 1, name: 'Technical'}, name: '.NET', id: 2} id:1},
                                                  {skill: {type: {id: 2, name: 'Domain'}, name: 'Media', id: 5} id:2},
                                                  {skill: {type: {id: 3, name: 'Personal'}, name: 'Communication', id: 6} id:3},
                                                  {skill: {type: {id: 1, name: 'Technical'}, name: 'AngularJS', id: 3}. id:4}  
                                             ]}; 
      
                   $scope.employeeSkills= new ngTableParams({}, {
                           dataset: employee.skills,
                           counts: []


                   });

          $scope.skillTypeChanged = function (skill, index) {
              $scope.availableSkills = angular.copy($scope.originalSkills );
              for (var i = 0; i < $scope.availableSkills.length; i++) {
                     if (skill.type.id == $scope.availableSkills[i].type.id) {
                         $scope.employeeSkills[index].skill = angular.copy($scope.availableSkills[i]);
                              break;
                     }
               }              
               $scope.availableSkills = angular.copy($scope.originalSkills );
          };      
               }]);


  • In the HTML file (partial view) add the following code where you want your employee skill table to appear. We have used Text boxes, drop-down boxes and the checkbox controls in the view to make the screen editable.  
            <div>
               <table ng-table="employeeSkills">
                  <tr ng-repeat="skill in $data">
                    <td data-title="'#'">{{$index + 1}}</td>
                    <td data-title="'Skill Type'" >
          <select name="skillType_{{$index +1}}" id="skillType_{{$index +1}}" ng-model="skill.type" 
                                    ng-options="type.name for type in skillTypes track by type.id" 
                                    ng-change="skillTypeChanged(skill.skill, $index)"></select>
                     </td>
                     <td data-title="'Skill Name'" >
                   <select name="skillName_{{$index +1}}" id="skillName_{{$index +1}}" class="span3" ng-model="skill.skill"                                                                
                                ng-options="skillName.skillName for skillName in (availableSkills | filter:{type: {id: skill.skill.type.id}})
                                 track by skillName.id"></select>

                     </td>   
                </tr>

             </table>

          </div>

Depedent Dropdown boxes - Part I

In this post I will be demonstrating how easy it is to make a drop-down box data dependent on the selected values of the other drop-down box inside an edit form by using angular directives ng-model and ng-option. 

Lets take the example where we have states and there corresponding cities. Based on what is selected in the state drop-down control, the cities list gets filtered in the cities drop-down.




Available Models:

states =  [ {id: 1, name: 'Karnataka'},
                 {id: 2, name: 'TamilNadu'},
                 {id: 3, name: 'Kerala'}];

cities = [{state: {id: 1, name: 'Karnataka'}, name: 'Bangalore', id: 1},
              {state: {id: 1, name: 'Karnataka'}, name: 'Mangalore'.NET, id: 2},
              {state: {id: 1, name: 'Karnataka'}, name: 'Mysore', id: 3},
              {state: {id: 2, name: 'TamilNadu'}, name: 'Chennai', id: 4},
              {state: {id: 2, name: 'TamilNadu'}, name: 'Madurai', id: 5},
              {state: {id: 3, name: 'Kerala'}, name: 'Calicut', id: 6},
              {state: {id: 3, name: 'Kerala'}, name: 'Cochin', id: 7}];

Now lets build a view to display the dependency between two drop-down controls in angularJS application. Below are the steps you need to follow:
  • In the controller javascript file add the below code: 
  •        myApp.controller('citiesController', ['$scope', 
                  function ($scope) {
                     $scope.states =  [{id: 1, name: 'Karnataka'},
                         {id: 2, name: 'TamilNadu'},
                         {id: 3, name: 'Kerala'}];
                     $scope.cities = [{state: {id: 1, name: 'Karnataka'}, name: 'Bangalore', id: 1},
                                               {state: {id: 1, name: 'Karnataka'}, name: 'Mangalore'.NET, id: 2},
                                               {state: {id: 1, name: 'Karnataka'}, name: 'Mysore', id: 3},
                                               {state: {id: 2, name: 'TamilNadu'}, name: 'Chennai', id: 4},
                                               {state: {id: 2, name: 'TamilNadu'}, name: 'Madurai', id: 5},
                                               {state: {id: 3, name: 'Kerala'}, name: 'Calicut', id: 6},
                                               {state: {id: 3, name: 'Kerala'}, name: 'Cochin', id: 7}];     

                    $scope.currentCity =      {state: {id: 1, name: 'Karnataka'}, name: 'Bangalore', id: 1};
                  }]);


  • In the HTML file (partial view) add the following code where you want to see the state and city drop-down boxes to appear. 
          <table>          
             <tr>
                <td>
                    <label>Current State</label>
                </td>
                <td>
                    <select ng-model ="currentCity.state" 
                                 ng-options ="state.name for state in states track by state.id" >
                   </select>                   
                </td>
                <td>
                    <label >Current City</label>
                </td>               
                <td>
                     <select ng-model ="currentCity"                                                                
                                ng-options="city.name for city in (cities | filter:{state: {id: currentCity.state.id}})
                                 track by city.id">
                     </select>
                </td>
             </tr>
          </table>          


The above code generates following outputs based on the value selected from the current state drop-down box.

ngTable - Introduction

I was looking for a grid/table element with following requirements:
  • In-built filtering, sorting and paging.
  • Can be represented as a read only table.
  • An editable grid with just text boxes.
  • An editable grid with check-boxes and drop-down boxes.
  • A grid with ability to add and remove rows.
I came across various implementation of angularJS tables/grids:
  • ng-table 
  • ng-grid 
  • ui-grid
Among these I went with ng-table, only because it is very simple to use and has great documentation along with working examples (which is getting improved day by day).

Steps to use ng-table in AngularJS application:
  • First download ng-table .css as well as .js file and add a reference to it.
  • Add ngTable module to where the app module is being declared.
                 var myApp = angular.module("myApp", ["ngTable"])
  • In the HTML file (partial view) add the following code where you want your table to appear
            <div>

               <table ng-table="employeeSkills">

                  <tr ng-repeat="skill in $data">

                    <td data-title="'#'">{{$index + 1}}</td>
                    <td data-title="'Skill Type'" >
                         <span>{{skill.type.name }}</span>
                     </td>
                     <td data-title="'Skill Name'" >
                           <span>{{skill.name }}</span>
                     </td>
                     <td data-title="'Rating '" >
                         <span>{{skill.rating }}</span>
                     </td>
                    <td data-title="'Is Primary'" >
                   <input type="checkbox" ng-model="skill.isPrimary" value="{{skill.isPrimary}}" disabled />
                   </td>
                </tr>
             </table>
          </div
  • In the controller javascript file where you want to use ng-table declare ngTableParams in following way:
          myApp.controller('viewEmployeeSkillController', ['ngTableParams', '$scope', 

             function (ngTableParams, $scope) {

                var skills = [

                            {name: "Java", type: {id: 1, name: 'Technical'}, rating: 2, IsPrimary: 'false'},
                            {name: "LifeScience", type: {id: 2, name: 'Domain'}, rating: 5, IsPrimary: 'false'},
                            {name: "Communication", type: {id: 3, name: 'Personal'}, rating: 4, IsPrimary: 'false'}
                            ] ;     
                $scope.employeeSkills = new ngTableParams({}, {
                  dataset: skills,
                  counts: []
              });
          }]);