Posts with tag: Angular

The live feedback is often forgotten when working with form validation. Therefore, I have made a simple web application that will present live validation feedback as the user input email & password in order to create a new account. The technologies used for this example is Bootstrap in order to create a nice looking view, and AngularJS in order to present live data & for some validation help.

The end result will look something like this:

BigImage

 

First we need to create a HTML page containing the input form needed.

The HTML page will contain the AngularJS bindings in order to present live updates but also to check validation variables in order to present the correct color.

In this example we are making use of AngularJS to do some of the validations for us:

loginForm.email.$error.required

Which will make sure that the field 'email' contains a value

 

loginForm.email.$error.email

Which is used to validate the field as an email address.

 

loginForm.email.$dirty

Which will make sure that the data has changed (meaning no initial values).

 

loginForm.email.$invalid / loginForm.email.$valid

Which determines whether the control is in a valid state.

 

What also should be noted is that ng-disabled is used in order to only activate the submit button when all of the fields are valid.

<!DOCTYPE html>
<html ng-app="validationApp">
<head>
     <title></title>
     <meta charset="utf-8" />
     <link href="Content/bootstrap.css" rel="stylesheet" />
     <link href="site.css" rel="stylesheet" />
</head>
<body>
     <form ng-controller="validationCtrl" name="loginForm">
          <div ng-cloak class="container">
               <div class="row col-xs-12">
                    <h1>Form validation with Bootstrap & AngularJS</h1>
                    <h4>Create a new account below</h4>
               </div>
               <!--Setup validation control for email-->
               <div class="row form-group" ng-class="{'has-error' : loginForm.email.$dirty && loginForm.email.$invalid, 'has-success' : loginForm.email.$dirty && !loginForm.email.$invalid}">
                    <div class="col-sm-6">
                         <input class="form-control" type="email" name="email" ng-model="email" placeholder="Email" required />
                    </div>
                    <div class="col-sm-6">
                         <span style="color:red;" ng-show="loginForm.email.$dirty && loginForm.email.$invalid">
                              <span ng-show="loginForm.email.$error.required">Email is required.</span>
                              <span ng-show="loginForm.email.$error.email">Invalid email address.</span>
                         </span>
                         <span style="color:green;" ng-show="loginForm.email.$dirty && !loginForm.email.$invalid">
                              OK
                         </span>
                    </div>
               </div>

               <!--Setup validation control for the password field-->
               <div class="row" style="margin-top:10px;">
                    <div class="form-group"
                         ng-class="{
                         'has-error' : loginForm.password.$dirty && (loginForm.password.$invalid || passwordStrength == 'too weak'),
                         'has-success' : loginForm.password.$dirty && !loginForm.password.$invalid && passwordStrength == 'good',
                         'has-warning' : loginForm.password.$dirty && !loginForm.password.$invalid && passwordStrength != 'good' && passwordStrength != 'too weak'}">
                    <div class="col-sm-6">
                         <input class="form-control" name="password" type="password" ng-model="password" placeholder="Password" required />
                    </div>
               <div class="col-sm-6">
                    <span style="color:red;" ng-show="loginForm.password.$dirty">
                         <span ng-show="loginForm.password.$error.required">Password is required.</span>
                         <span ng-show="loginForm.password.$error.required == null && passwordStrength == 'too weak'">Your password is too weak</span>
                    </span>
                    <span style="color:orange;" ng-show="loginForm.password.$dirty && !loginForm.password.$invalid && passwordStrength != 'good' && passwordStrength != 'too weak'">
                         Password is {{passwordStrength}}
                    </span>
                    <span style="color:green;" ng-show="loginForm.password.$dirty && !loginForm.password.$invalid && passwordStrength == 'good'">
                         Password is {{passwordStrength}}
                    </span>
               </div>
          </div>
     </div>

     <!--Setup validation control for the second password field-->
     <div class="row" style="margin-top:10px;">
          <div class="form-group"
               ng-class="{
               'has-error' : loginForm.passwordRepeat.$dirty && loginForm.passwordRepeat.$invalid,
               'has-success' : loginForm.passwordRepeat.$dirty && !loginForm.passwordRepeat.$invalid && passwordRepeatResult == true}">
               <div class="col-sm-6">
                    <input class="form-control" name="passwordRepeat" type="password" ng-model="passwordRepeat" placeholder="Retype password" required />
               </div>
               <div class="col-sm-6">
                    <span style="color:red;" ng-show="loginForm.passwordRepeat.$dirty">
                         <span ng-show="passwordRepeatResult == false">
                              Passwords do not match
                         </span>
                    </span>
                    <span style="color:green;" ng-show="loginForm.passwordRepeat.$dirty">
                         <span ng-show="passwordRepeatResult == true">
                              Passwords match
                         </span>
                    </span>
               </div>
          </div>
     </div>

     <!--Submit-->
     <div class="row col-xs-12" style="margin-top:10px;">
     <!--Disable submit button if input is not valid-->
          <input type="submit" value="Create account" class="btn btn-primary btn-sm"
          ng-disabled="loginForm.password.$invalid || loginForm.email.$invalid || !passwordRepeatResult || passwordStrength != 'weak'" />
     </div>
</div>
</form>
<footer>
     <script src="Scripts/jquery-1.9.1.js"></script>
     <script src="Scripts/bootstrap.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
     <script src="site.js"></script>
</footer>
</body>
</html>

 

As for the JavaScript file we have a few custom validations in order to display different results depending on the password strength.

In order for this to work efficiently, Angular watches has been created that will be notified when the model has changed.

var validationApp = angular.module('validationApp', []);

validationApp.controller('validationCtrl', ['$scope', function ($scope) {
//Validating password strength
$scope.checkPassword = function (password) {
     if (password == null) {
          return 'too weak';
     }
     if (password.length > 14 && password.match(/\d+/g) != null) {
          return 'good';
     }
     else if (password.length > 9 && password.match(/\d+/g) != null) {
          return 'pretty good';
     }
     else if (password.length > 5 && password.match(/\d+/g) != null) { //Password is 6 characters or longer
          return 'weak';
     }
     else {
          return 'too weak';
     }
}

//Check if the two passwords match
$scope.matchPassword = function (password, passwordRetype) {
     if (password != null && passwordRetype != null) {
          if (password.length > 0 && passwordRetype.length > 0 && password == passwordRetype) {
               return true;
          }
          else {
               return false;
          }
     }
     else {
          return false;
     }
}

//Setup watch on the passsword variable
$scope.$watch('password', function (newValue, oldValue) {
     $scope.passwordStrength = $scope.checkPassword(newValue);
     $scope.passwordRepeatResult = $scope.matchPassword(newValue, $scope.passwordRepeat);
});

//Setup watch on the second password variable
$scope.$watch('passwordRepeat', function (newValue, oldValue) {
     $scope.passwordRepeatResult = $scope.matchPassword($scope.password, newValue);
})
}]);

The example project can be found here:

Form validation - Source


I have an Angular project in which I need to interact with a CRM 2016 instance, that is, I need to create a record and open/navigate to it from within Angular.

I dont want to use the javascript SDK files because well they just seem klunky and non angular -ish.. So instead I wanted to do it with just a regular service.. Turns out it was quite easy. The hardest part was figuring out where Microsoft stored the GUID of the created record (spoiler: they stuck it in the header, more details on that here).

First off you need to add a service (or copy paste the CreateRecord method from this service to your own).

myApp.service('dataService', function ($http, $rootScope, $timeout, $q) {
    var pub = {};

    var crmAPIURL = Xrm.Page.context.getClientUrl() + "/api/data/v8.1/";

    pub.CreateRecord = function (entityName, record) {
        var url = crmAPIURL + entityName;
        return $http
        (
            {
                method: "POST",
                url: url,
                data: record,
                dataType: 'json',
                timeout: 15000
        }).then(function (data) { return data; });
    }

    return pub;
});

Now with that service method defined we can call it like this from one of our controllers:

$scope.CreateCompany = function ()
{
    // define the entity record with all the fields you want to set.
    var account = {
        name: "My Test Company",
        address1_line1: "SyntaxWarriors road 1337"
    };

    // call the service defined previously with the data and the name of the entity according to the web api
    // the entity names are listed here: https://your_organization_name.crm4.dynamics.com/api/data/v8.1/
    // in my case I wanted to create an account record which is called "accounts" (yes, the service tries to pluralize all things).
    $dataService.CreateRecord("accounts", account).then(function (data)
    {
        // this will return something like: "https://your_organization_name.crm4.dynamics.com/api/data/v8.1/accounts(59e11f14-4489-e611-80de-c4346bacbdc4)"
        // the service returns the GUID of the created record in the header.. for some unexplained annoying reason I dont know. 
        var entityUrl = data.headers("OData-EntityId");

        // do some regex to get the data in between parentheses.
        var getDataBetweenParenthesesRegex = /\(([^)]+)\)/;
        var matches = getDataBetweenParenthesesRegex.exec(entityUrl);

        // uncomment these if you want to see what you're actually getting back.
        // console.log(data)
        // console.log(matches); the guid matches

        // the second match (1) is the guid without the (). Lets open a new window to that.
        if (matches.length >= 1) {
            Xrm.Utility.openEntityForm("account", matches[1]);
        }
    });
}