Category Archives: javaScript

everything about javascript

Coding javaScript

Input validation in Angular

Published by:

Validation is one of the main issues that developers have to deal with when handling user input in forms. The premise is that all user data coming in may be corrupt and some users may have bad intentions so validate inputs on the client and on the server side.
Maybe for this reason, angular (1.3+) provides a pretty powerful validation api through the all famous ngModel directive and its controller. By adding our custom directive to the input and requiring ngModel we can have a grip over the ngModel Controller which provides the validation api. So we start with something like:

disclaimer- should be only start-date in the markup. My syntax highlighter adds the =”” so ignore those.

So far so good- we have a form with an input where we will require the user to type in a date in a specific format within a specified date range and we will validate if that date is available for reservation on the server. So we bind te input to reservationStartDate and put in our custom directive – startDate.

Next thing, lets create the directive itself:

.directive('startDate',function(constVars,dateParserService,$http){ 
	return {
        restrict: 'A',
        require: ['ngModel'],
        link: link
    };

    function link(scope, element, attr, ctrls) {
        var ngModelController = ctrls[0];
    }

})

So far we don’t do anything but the important takeaway here is the require: [‘ngModel’] line when declaring our directive which says – “Hey let me use the ngModel Controller here”. Assume that in constVars we hold a date regex and dateParserService is custom logic that we created for parsing dates from strings. All the validation will happen in the link function of our directive and the required ngModel Controller is passed in the link function through the fourth argument (ctrls). In this case we will use the following methods for validation:

$parsers – that is a collection of functions where we sanitize input from user before handing it to the $validators. Every parser function passes the sanitized value to the next one. If we ever return undefined, the pipeline doesn’t reach the $validators.

$validators – name is pretty exemplary here – these are collection of functions where we apply validation logic.

$asyncValidators – same as above but we typically use these for server, api or whatever long running operations validation. They start not one after the other but simultaneously and deal with promises rather than values. If all resolve the value than validation passes, if one rejects it – validation fails. Let’s get to some specific example.

First of all, we want to check if the manually input value is in the format that we want the user to use and we will use regex – so we will put that in the $parsers:

function link(scope, element, attr, ctrls) {
        ngModelController.$parsers.unshift(function (viewValue) {
                var date;
                if (angular.isString(viewValue)) {
                    if (!constVars.dateFormatRegex.test(viewValue)) return undefined;
                    else {
                        date = dateParserService.parse(viewValue, "dd-MM-yyyy");
                        if (isNaN(date)) {
                            return undefined;
                        }else{
		            return date;
			}
                    }
                }
        });
}

I we can parse it we pass the parsed Date object down the pipeline, if not – return undefined, which stops the value propagation down the pipeline and sets myForm.reservationStartDate.$error.parse = true.
If we parsed the user input to date we want to validate if the user entered a date in a correct date interval (we don’t want dates before today for a reservation). We will put that into $validators:

		ngModelController.$validators.afterToday=function (modelValue,viewValue) {
			var today=new Date();
			if(today < modelValue){
				return true;
			}
			return false;	
        };

So after the date has been parsed it will be passed to the afterToday for business rule validation. Let's go a little further and add an asyncValidator. We will validate the date for availabiliy on the server:

ngModelController.$asyncValidators.isDateAvailable=function (modelValue) {
    return $http.post('api/date/available',modelValue).then(function(success){                       
        //yeah, went through                      
    },function(error){
        // no availability
    })
};

As i said, async validators (you may have many of those) will start running simultaneously and input will be validated only if all resolve the promise. You may give the user indication that something is loading by:

Checking Value on the server....

So that is the main validation pipeline of the ngModelController - $parsers-> $validators & $asyncValidators. There is one more hook that you can use - $viewChangeListeners which is again array of functions. It does not take args or return anything - these functions are used usually for additional $watches on the model instead of some validation logic. What is provided more in the api are methods to change the input state as $setPristine(),$setDirty(), $setTouched(), $setUntouched(). Those are self-explanatory so i wont elaborate on them.

By default the view value gets passed down the validation pipeline on every change (ie keystroke) which might be not necessary. You may want to validate the input on blur event only. So that is very easily configurable - you only need to decorate your input markup with ng-model-option:{updateOn:'blur'}

You can clone the source for this example and some more on https://github.com/ivopashov/angular-presentation It is in app->ngModelExample

javaScript

Angular directive for Twitter Bootstrap with datepicker extended to select hour

Published by:

If you find the native angular directives for twitter bootstrap neat to use but miss the functionality to select an hour from the datepicker (the original version get as granular as days), you are not alone. I know there are a bunch of other other datepicker directives out there but i am kind of used to this one and that’s why i extended it to use hours also. Note – if you include it in your project, beware to change the name to something other than “ui-bootstrap-tpls.js” because if you update packages it will be overwritten by the new one.

Clone it under: https://ivopashov@bitbucket.org/ivopashov/bootstrap-tpls-with-added-hour-to-the-datepicker.git

Coding javaScript

angular controller inheritance minification issue

Published by:

In Angular we use $injector service to require dependencies in any point of time. We can use it to create a hierarchy of controller inheritance very easily – consider the following example:

var ParentController=function($scope){
    $scope.triangle={
        a:3,
        b:4,
        c:5
    };
}

app.controller('ChildController',['$scope','$injector',function($scope, $injector){
    $injector.invoke(ParentController,this,{
        $scope:$scope
    })
}])

What we basically do is declare a regular js function (ParentController), inherit from it through the invoke method of $injector service and pass any dependencies in the curly braces. Note that all dependencies in the parent must be resolved in the child and then passed along in the $injector.invoke. So now we have $scope.triangle inherited in the ChildController.

The above example works great until we don’t minify the js files when things get ugly and $injector starts throwing errors in the console. We need a little angular specific hack to fix that:

instead of :

var ParentController=function($scope){
    $scope.triangle={
        a:3,
        b:4,
        c:5
    };
}

we need to do:

var ParentController=['$scope', function($scope){
    $scope.triangle={
        a:3,
        b:4,
        c:5
    };
}]

The reason is that angular resolves dependencies ($scope in the example) by their names and when minified, names become unrecognizable to angular. A workaround of that is to annotate the functions with the names of the dependencies as strings, which will not get minified.