Tuesday, September 29, 2015

Resolve Angular promises multiple times

As you know that a promise can only be resolved once. While building a framework for my application, I came into a requirement that I need to resolve the same promise multiple times. In order to resolve the same promise multiple times, I found a hack solution that works.

First I clone the original promise object (actually the promise state). I will then clone this promise and then keep resolving this when needed. Here is the code that does this:

    if (promiseState === undefined)
        promiseState = angular.copy(deferred.promise.$$state);
    angular.extend(deferred.promise.$$state, promiseState)
    deferred.resolve();

In the above code, I am using promiseState to keep a copy of the original promise state. I am using kind of singleton pattern to store the promise state. Before resolving the promise, I clone the original promise state and override the current promise state. With this trick I was able to resolve the same promise multiple times.

Here is the complete code. You can also get this code at this Plunker (http://plnkr.co/edit/HsTpGIcxAHwvYAH3UGbQ?p=preview)

<html>
<head>
    <title>Resolve Angular promises multiple times</title>
</head>
<body ng-app="multipleResolves">
    <div ng-controller="index as vm">
        Click the button below to resolve a promise. Every click will resove the same promise again, thereby resolving a promise multiple times
        <br /><br />
        <button ng-click="vm.resolve()">Resolve</button>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
    <script>
        angular.module('multipleResolves', [])
        .controller("index", index);
        function index($scope, $q) {
          var deferred, promiseState

            var vm = {
              resolve: resolve
            }

            init();
            return vm;

            function init() {
                angular.extend($scope, vm);

                //creating the $q
                deferred = $q.defer();

                deferred.promise.then(function(){
                  alert('resolved');
                })
            }

            function resolve() {
                // below three lines are the key for resolving a promise multiple times
                 if (promiseState === undefined)
                     promiseState = angular.copy(deferred.promise.$$state);
                 angular.extend(deferred.promise.$$state, promiseState)
              deferred.resolve();
            }

        }
    </script>
</body>
</html>

Thursday, September 10, 2015

AngularJS Dynamic Validation and Error Messages

AngularJS directive ngMessages provides a mechanism to show the error message dynamically. The documentation of this can be found at:


Unfortunately this documentation does not provide a sample working code which links the validation and error messages. In this blog I will show how to utilize the ngMessages to show validation error messages that are not predefined, in other words dynamically showing the messages.

In my scenario, I am doing some validations on the server (asp.net) and want to show the messages returned by the server. Let’s assume that user enters a username or something in the UI and this data is posted back to the server. On server I perform some validations such as user name should be unique and then want to show those validation messages attached to the form elements, in my case the textbox. For this dynamic ngMessages is a good fit. To demo this, I extended the AngularJS example to show the dynamic error message. Here is the AngularJS example for the ngMessages


As you see the ngMessage example on AngularJS site is using required and other messages. For this I am going to add the dynamic messages as shown below

<div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
    <div ng-message="required">You did not enter a field</div>
    <div ng-repeat="errorMessage in errorMessages">
        <div ng-message-exp="errorMessage.type">{{ errorMessage.text }}</div>
    </div>
</div>

The errorMessages object will contain the messages that we dynamically add to the textbox control. Further ngRepeat will provide us an ability to attach multiple error messages.

Now when we get the error messages from the server, we can add those to the errorMessages object and then set the validation of textbox control to false as shown by the below code

function getDynamicErrorMessage(control) {
    //making a http request and getting the error. Add that error to the errorMessages
    var serverErrors = [{ type:'dynamicMessage', text:'Error Message Shown Dynamically'}]
    angular.extend(vm.errorMessages, serverErrors);
    control.$setValidity('dynamicMessage', false);
}

With the above few lines of code, we can get the dynamic error messages and show them in UI using AngularJS ngMessages.

Here is the complete code:

<html>
<head>
    <title>Dynamic Messages Sample</title>
</head>
<body ng-app="dynamicMessages">
    <div ng-controller="index as vm">
        <form name="myForm" novalidate>
            <label>
                Enter your name:
                <input type="text" name="myName" ng-model="name" required />
            </label>
            <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
            <div ng-messages="myForm.myName.$error" style="color:maroon" role="alert">
                <div ng-message="required">You did not enter a field</div>
                <div ng-repeat="errorMessage in errorMessages">
                    <div ng-message-exp="errorMessage.type">{{ errorMessage.text }}</div>
                </div>
            </div>
            <button ng-click="getDynamicErrorMessage(myForm.myName)">Get Dynamic ErrorMessage</button>
            <button ng-click="clearDynamicErrorMessage(myForm.myName)">Clear Dynamic ErrorMessage</button>
        </form>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-messages.min.js"></script>
    <script>
        angular.module('dynamicMessages', ['ngMessages'])
          .controller("index", index);

        function index($scope) {
            var vm = {
                errorMessages: [],
                getDynamicErrorMessage: getDynamicErrorMessage,
                clearDynamicErrorMessage: clearDynamicErrorMessage
            }

            init();
            return vm;

            function init() {
                angular.extend($scope, vm);
            }

            function getDynamicErrorMessage(control) {
                //making a http request and getting the error. Add that error to the errorMessages
                var serverErrors = [{
                    type: 'dynamicMessage',
                    text: 'Error Message Shown Dynamically'
                }]
                angular.extend(vm.errorMessages, serverErrors);
                control.$setValidity('dynamicMessage', false);
            }

            function clearDynamicErrorMessage(control) {
                control.$setValidity('dynamicMessage', true);
            }
        }
    </script>
</body>
</html>

You can also view this code in Plunker