Sunday, January 8, 2017

Moving to Angular2

Recently I moved to Angular2. Now that it is released it is time to take a look. My first impression is good ! It has a steep learning curve, but I think not as steep as Angular1. I love the more structured approach with TypeScript. Number of codelines are seriously reduced.

Saturday, May 23, 2015

Using Select ng-options and ng-model binding

I found it really difficult to get the select with options working in a two way databinding with AngularJS.
When I insert data I want it not to default, but in change mode I want it to default to the right object.  (the previous selected during insert).

After searching through different examples I finally got it to work as I want it.

In this example I'm selecting a customer for a work log administration.
There are two parts to it.

1. A controller part.
2. A HTML part.

I'm using bootstrap for my HTML formatting, but the example can be used plain also.

Here is the HTML part:



<select ng-model="SelectedCustomer" class="form-control"
  ng-options="Customer.customername for Customer in CustomerData.Customers.items track by Customer.customername"
     style="width: 444px;" required="required">
</select>


All I do in the controller for the update part is set the right model cutomer from my releated object like:

$scope.SelectedCustomer=$scope.WorklogData.currentWorklog.customer;

So the model in ng-model really reflects the object.

Friday, September 19, 2014

You got to love services in AngularJS.

So now that I  have the basics working it is time to refactor, so creating new datagrids will be a lot easier. I have made a service that handles all grid functionality. I call it the BrowseService.
Now the Controller for loading and handling the sorting and querying looks as follows:



var CompaniesApp = angular.module('Companies', ['CompanyService','ContractService','BrowseService']);

CompaniesApp.controller("CompaniesGridCtrl", function($http, $scope, $location, CompanySrv,BrowseSrv){
 // Grid Controller uses CompanySrv as the service to get the data from, and BrowseSrv to manage the grid. 
 $scope.companyData = CompanySrv.data;        // Let scope data point to to service data
 $scope.Browse=BrowseSrv;
 $scope.SearchString="";
 BrowseSrv.Init('/NewCompany','/EditCompany/','Name:',$scope.SearchString,CompanySrv.getCompanies,CompanySrv.deleteCompany);
 BrowseSrv.loaddata('Name');         // initial data load

}); 

As you can see, I also pass the BrowseService as a dependency.  I set the
$scope.Browse=BrowseSrv; 
so I can call the service from my HTML 

I my HTML I can then code the following referring to the service:


<div>
 <table id="box-table-a" style="width: 70%">
  <thead>
   <tr>
    <th scope="col"></th>
    <th scope="col"><b>{{Browse.getsearchlabel()}}</b><input type="text"
     ng-model="SearchString" ng-change="Browse.refresh(SearchString)"></th>
    <th scope="col"></th>
    <th scope="col"></th>
    <th scope="col"></th>
    <th scope="col"></th>
    <th scope="col"><button id="newbutton"
      ng-click="Browse.GotoNew()">&nbsp; &nbsp;&nbsp;&nbsp;
      Nieuw &nbsp;&nbsp;&nbsp;</button></th>
   </tr>
  </thead>
  <thead>
   <tr>
    <th scope="col"><a href=""
     ng-click="Browse.ChangeSortOrder('Company_id','Nr:')">Id</a></th>
    <th scope="col"><a href=""
     ng-click="Browse.ChangeSortOrder('name','Naam:')">Naam</a></th>
    <th scope="col"><a href=""
     ng-click="Browse.ChangeSortOrder('Contact_Name','Contact persoon:')">Contact
      persoon</a></th>
    <th scope="col"><a href=""
     ng-click="Browse.ChangeSortOrder('Contact_Tel','Contact Tel-Nr:')">Contact
      Tel-Nr</a></th>
    <th scope="col"><a href=""
     ng-click="Browse.ChangeSortOrder('Contact_Email','Contact E-mail:')">Contact
      E-mail</a></th>
    <th scope="col"></th>
    <th scope="col"></th>
   </tr>
  </thead>
  <tbody>
   <tr ng-repeat="Company in companyData.companies">
    <td>{{Company.Company_Id}}</td>
    <td>{{Company.Name}}</td>
    <td>{{Company.Contact_Name}}</td>
    <td>{{Company.Contact_Tel}}</td>
    <td>{{Company.Contact_Email}}</td>
    <td>
     <button id="editbutton" ng-click="Browse.Edit(Company.Company_Id)">wijzig</button>
    </td>
    <td>
     <button id="deletebutton"
      ng-click="Browse.deleterow(Company.Company_Id)">verwijder</button>
    </td>
   </tr>
  </tbody>
  <tfoot id="tf">
   <tr>
    <td></td>
    <td><a href="" ng-click="Browse.Previous()">Vorige</a>&nbsp;<a href=""
     ng-click="Browse.Next()">Volgende</a></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
   </tr>
  </tfoot>
 </table>
</div>

You have to love Angular !

Saturday, August 23, 2014

Finalizing my CRUD for AngularJS

Today, I have finalized what I consider my version 1 for a CRUD made with angular based on Rest services.

I have two controllers defined. One for the Grid and One for the Form.
Here is my Grid controller.

var CompaniesApp = angular.module('Companies', ['CompanyService']);

CompaniesApp.controller("CompaniesGridCtrl", function($http, $scope, $location, CompanySrv){
// Grid Controller uses CompanySrv as the service to get the data from 
 $scope.companyData = CompanySrv.data;        // Let scope data point to to service data
 $scope.SearchString="";
 var loadData = function (Orderby) { 
  if (Orderby !== $scope.LastOrderby)      // Clear search string if sort order changes
   $scope.SearchString="";
  $scope.LastOrderby=Orderby;        // Remember last order by
  CompanySrv.getCompanies(Orderby, $scope.SearchString);  // Get the companies for the grid
 };
 $scope.Searchlabel='Naam:';         // initial sorting
 loadData('Name');           // initial data load
 //
 $scope.gotoAddCompany = function () {        // Pressed the new button in the grid
  $location.path( '/NewCompany');
 };
 $scope.editCompany = function(pCompany_id) {    // Pressed the edit company in the grid
  $location.path( '/EditCompany/' + pCompany_id);
 };
 $scope.UpdateTable = function () {       // Update called from header click to reorder grid.
  loadData($scope.LastOrderby);
 };
 $scope.deleteCompany= function(p_Company_id) {
  CompanySrv.deleteCompany(p_Company_id,true)
  .then (function(){
   loadData($scope.LastOrderby);}
  );
 }
 $scope.refreshData = function (p_Orderby,p_NewSearchlabel) { // From filtering in textbox update
  $scope.Searchlabel=p_NewSearchlabel;
  loadData(p_Orderby);
 };
}); 

The controller uses the CompanySrv (service) as I blogged about before. I have some extra code, since I want to be able to click on a header and then resort my data, and have my search box on the screen search by the column clicked.


<div>
 <p id="searchtext" >
  <b>{{Searchlabel}}</b><input type="text" ng-model="SearchString"
   ng-change="UpdateTable()">
 </p>
 <table id="box-table-a" style="width: 70%">
  <thead >
   <tr>
    <th scope="col"><a href="" ng-click="refreshData('Company_id','Nr:')">Id</a></th>
    <th scope="col"><a href="" ng-click="refreshData('name','Naam:')">Naam</a></th>
    <th scope="col"><a href="" ng-click="refreshData('Contact_Name','Contact naam:')">Contact
      persoon</a></th>
    <th scope="col"><a href="" ng-click="refreshData('Contact_Tel','Contact Tel-Nr:')">Contact
      Tel</a></th>
    <th scope="col"><a href="" ng-click="refreshData('Contact_Email','Contact E-mail:')">Contact
      Email</a></th>
    <th scope="col"></th>
    <th scope="col"><button id="newbutton"
      ng-click="gotoAddCompany()">&Nieuw&</button></th>
   </tr>
  </thead>
  <tbody>
   <tr ng-repeat="Company in companyData.companies">
    <td>{{Company.Company_Id}}</td>
    <td>{{Company.Name}}</td>
    <td>{{Company.Contact_Name}}</td>
    <td>{{Company.Contact_Tel}}</td>
    <td>{{Company.Contact_Email}}</td>    <td>
      <button id="editbutton" ng-click="editCompany(Company.Company_Id)">wijzig</button>
    </td>
    <td>
     <button id="deletebutton" ng-click="deleteCompany(Company.Company_Id)">verwijder</button>
    </td>
   </tr>
  </tbody>
 </table>
</div>

The resulting output looks as following:

By typing in the text-box the data will immediately be filtered from the back-end, depending on the column clicked. The text label will also change accordingly.

For the Form part the controller part is code like below:


CompaniesApp.controller("CompaniesFormCtrl",function($http,$scope,$log,$location,$routeParams,CompanySrv){

 $scope.companyData = CompanySrv.data; // Set the scope data to the service data

 $scope.goHome = function () {     // used in comany form to cancel so must be scope function
  $location.path( '/Companies');
 };
 var param = $routeParams.Companyid;  // see if a company id is passed on url, then get it from the server
 if (param!=null) {      // Parameter passed on form, must be update instead of delete.
  CompanySrv.getCompany(param)
  .then(function(data) {
  },function(error) {
   alert("Error in CompanyCrud-10: "+  error.data);
  }
  );
  $scope.Mode="Update";
 }
 else         // no parmeter thus insert
 {
  $scope.companyData=null;
  $scope.Mode="Insert";
 }

 $scope.submit = function(form) {     // insert/ update form. 
  // Trigger validation flag.
  $scope.submitted = true;
  if (form.$invalid) {     // If form is invalid, return and let AngularJS show validation errors.
   return;
  }
  if ($scope.Mode=="Update")   // Call update service as promise.
   CompanySrv.saveCompany($scope.companyData.currentCompany)
   .then(function(data) {
    $scope.goHome();
   }, function(error) {
    scope$message=error;
   });
  else
   CompanySrv.insertCompany($scope.companyData.currentCompany)
   .then(function(data) {
    $scope.goHome();
   }, function(error) {
    scope$message=error;
   });
 };
}); 


The corresponding HTML is:


<form name="CompanyForm">
 <h1>Bedrijf</h1>
 <table id="box-table-a" style="width:50%">
  <tr>
   <td>Bedrijfs-nr:</td>
   <td><b>{{companyData.currentCompany.Company_Id}}</b></td>
  </tr>
 
  <tr>
   <td>Bedrijfs-naam:</td>
   <td><input ng-model="companyData.currentCompany.Name" type="text" maxlength="50" required="required"/></td>
  </tr>
  <tr>
   <td>Contact persoon:</td>
   <td><input ng-model="companyData.currentCompany.Contact_Name" type="text" maxlength="50" /></td>
  </tr>
  <tr>
   <td>Contact Email:</td>
   <td><input type="email" ng-model="companyData.currentCompany.Contact_Email" maxlength="80"/></td>
  </tr>
  <tr>
   <td>Contact Telefoon-nummer:</td>
   <td><input type="text" ng-model="companyData.currentCompany.Contact_Tel" maxlength="10"/></td>
  </tr>
  <tr>
   <td>
    <button id="Savebutton" ng-click="submit(CompanyForm)">Bewaar</button>
    <button id="Cancelbutton" formnovalidate ng-click="goHome()">Annuleer</button>
   </td>
   <td></td>
  </tr>
 </table>
 {{message}}
</form>

Monday, August 18, 2014

Creating service wrapper for restapi to database in AngularJs

I finally had some time this weekend to refactor my code and start writing services to access my database objects. What I really needed was some way to wrap around the $http service to make things more readable and logical in my code.

Here is my wrapper for access to the company data table.



var Company = angular.module('CompanyService',[]);
Company.factory('CompanySrv',
  ['$http',
   function ($http) {
   var CompanySrv = {
     data: {
      currentCompany: {},
      companies : []
     },
     getCompany: function (p_Id) {
      return $http.get(GloServername + "RestCompanies/getone/"+ p_Id + "/" + GetNewKey())
      .success(function success(data) {
       CompanySrv.data.currentCompany = data;
      })
      .error(function error() {
      });
     },
     getCompanies : function(p_Orderby,p_Zoekstring){
      var httprequest="";
      if (p_Zoekstring=="" || p_Zoekstring==null)
       httprequest = GloServername + "RestCompanies/" + p_Orderby + "/" + GetNewKey();
      else
       httprequest = GloServername + "RestCompanies/" + p_Orderby + "/" + p_Zoekstring + "/" + GetNewKey();
      return $http.get(httprequest)
      .success(function success(data) {
       CompanySrv.data.companies = data;
      })
      .error(function error() {
      });
     },
     insertCompany : function(company){
      return $http.post(GloServername + "RestCompanies/Post",company)
      .success(function(data, status, headers) {
      })
      .error(function(data, status, headers, config) {
      });
     },
     saveCompany : function(company){
      return $http.put(GloServername + "RestCompanies/Put",company)
      .success(function success() {
      })
      .error(function error() {
      });
     },
     deleteCompany : function(p_Id,p_Confirmation){
      if (p_Confirmation==true)
      {
       var retVal = confirm('Verwijder bedrijf');
       if (retVal!=true)
        return;
      }
      return $http.delete(GloServername + "RestCompanies/Delete/" + p_Id)
      .success(function success() {
       ;
      })
      .error(function error() {
       ;
      });
     }
   };
   return CompanySrv;
  }
  ]);  


Basically it contains crud code for insert,delete and updating company data, but it also contains a collection of companies, that can be filled with the getCompanies method. This method take two parameters, a filter and an order by string. Both will by passed by my Rest service, so the correct data is returned. This service is used in my controller. I generally create two controllers. One to manged my company grid, and one to manage my company form. The name of the controller says it all : CompaniesFormCtrl and CompaniesGridCtrl. Let me show you my CompaniesFormCtrl, this is the controller that's matching the From to edit my companies. The corresponding Html is named EditCompany.Html.

Sunday, August 17, 2014

Making my SPA application in AngularJS

Ok, now that I have some pages and a basic understanding, the possibility of a SPA (Single Page Application) seems the next challenge. A SPA consist of an entry page with somewhere in the middle a ng-view tag, just like this :

<div ng-view>
</div>


In between the two divs you will replace the content with the help of a routing mechanism. To use routing you need to include the angular-route.min.js script in your html page. To load pages into you ng-view use a way with buttons or links that will navigate to another page: My Example:


<div class="container">
<div class="row">
<table>
<tr>
<td><a id="Menubutton" href="#/Contracts"> Contracts </a></td>
<td><a id="Menubutton" href="#/Companies"> Companies </a></td>
<td><a id="Menubutton" href="#/About"> About </a></td>
</tr>
</table>
<div ng-view></div>


You will need routing set up in you app module: Here is an example (my app.js):


var ContractsApplication = angular.module('ContractsApp', ['ngRoute','ngResource','Contracts','Companies']);

ContractsApplication.config(['$routeProvider',
                  function($routeProvider,$routeParams) {
 $routeProvider.
 when('/AddNewOrder', {
  templateUrl: 'add-order.html'

 }).
 when('/Home', {
  templateUrl: 'index.html'

 }).
 
 when('/About', {
  templateUrl: 'About.html'
 }).
 when('/NewContract', {
  controller: 'ContractsFrm',
  templateUrl: 'NewContract.html'
 }).
 
 when('/NewCompany', {
  controller: 'CompaniesFormCtrl',
  templateUrl: 'NewCompany.html'
 }).
 when('/EditCompany/:Companyid', {
  controller: 'CompaniesFormCtrl',  
  templateUrl: 'EditCompany.html'
 }).

 when('/Companies', {
  controller: 'CompaniesCtrl',  
  templateUrl: 'Companies.html'
 }).
 
 when('/Contracts', {
  controller: 'ContractsCtrl',  
  templateUrl: 'Contracts.html'

 });
}]);



As you can see the:

#/Companies
matches
/Companies

in the when part of the router. You will have to pass the template that gets loaded.
The template is not a full HTML page but a html partial. You can also pass a controller to be used in the page partial that gets loaded. You do not have a controller in the page itself.

For instance my About.html looks as following:


<h2>About</h2>
Contract application Version 1.01 Date : 14-aug-2014
 
 A small snip-it indeed ! 
Do not forget to add the scripts you need in the index.html.
Here is my complete index.html:

 
<!DOCTYPE html>
<html lang="en">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<head>
<title>Contracts</title>
</head>

<body ng-app="ContractsApp">

 <div class="container">
  <div class="row">
   <table>
    <tr>
     <td><a id="Menubutton" href="#/Contracts"> Contracts </a></td>
     <td><a id="Menubutton" href="#/Companies"> Companies </a></td>
        <td><a id="Menubutton" href="#/About"> About </a></td>
    </tr>
   </table>
   <div ng-view></div>

  </div>
 </div>
 <script src="Scripts/angular.min.js"></script>
 <script src="Scripts/angular-route.min.js"></script>
 <script src="Scripts/angular-resource.min.js"></script>
 <script src="Scripts/app.js"></script>
 <script src="Scripts/ContractCRUD.js"></script>
 <script src="Scripts/Contract_Utils.js"></script> 
 <script src="Scripts/Form.js"></script>
 <script src="Scripts/CompanyCRUD.js"></script>
 <script src="Scripts/CompanySrv.js"></script>
 <script src="//code.jquery.com/jquery-1.10.2.js"></script>
 <script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script>

</body>
</html>

Modularizing my AngularJS application

Slowly I'm refactoring My Angular application.
I really like to put general functionality in separate files and services. Not an easy task in Angular, since you really have to get the concept right with modules and dependency injection.

My main application in app.js is dependent on Contracts and Companies.
The Contracts module depends on services that I want to use in all my forms, called frmServices.
In Frmservices I want to use the HTTP Service, for instance to have a more generic delete call that I want to use from wherever I like.

With trail and error the structure now looks like this:

Main app.js (partial)

var ContractsApplication = angular.module('ContractsApp', ['ngRoute','ngResource','Contracts','Companies']);

Company.js (partial)
 
var CompaniesApp = angular.module('Companies', ['frmServices']);
 


Form.js (dependent on $http)


var FormApp = angular.module('frmServices', [])                                                                                                                                                                       
.factory("frm", ['$http', function($http) {                                                                                                                                                  
    return {                                                                                                                                                                                                             
        Delete: function(p_Deltext,p_Url,p_Id) {
            var retVal = confirm(p_Deltext);
            if (retVal==true) {
                var httprequest=GloServername + p_Url + "/Delete/" + p_Id;
                $http.delete(httprequest).success(function() {
                    return true;   
                }).error(function(data,status){alert("failure Delete: HTTP code:" + status)});
            }
            return false;
        },

        Update: function() {
            //Do something else here
        }
    }}]);



When you want to use the delete function in the service, do not forget to inject the service in your controller. In this case in the Company.js (the frm injection):
CompaniesApp.controller("CompaniesCtrl",function($http,$scope,$location,frm){

You can then call the delete from within the controller as following:
    if (frm.Delete("Delete ?","RestCompanies",pCompany_id)==true)

Hope this helps. It took me several hours to figure it all out. The nice thing is however you can have a whole hierarchy of dependent modules. Be carfull with your service names however. They have to be unique. There is a lot more refactoring to do, since ultimately I would like to pass a company service to the delete function, that will take care of the delete.