Every time that I need to implement a registration form there is some source of country selector; thus I decided to create a small component to generate the list of countries as options of the select
element.
The ISO 3166 defines three different codes (two-letter, three-letter and numeric) for every country so I wanted this to be configurable in the component, bounding the ngModel to any desired value.
And of course, I didn’t want to wrap or rewrite the native select, but only work with the ngOptions
attribute.
Implementation
Trying to implement this on a clean way was a really interesting exercise which made me struggle for a while but also learn more about the internals of AngularJS.
First I learnt about the execution order of the compile
, preLink
and postLink
functions when using an element directive with an attribute directive. And you can see the results opening the console of this JSFiddle.
After that lesson I was sure that I needed to use the compile function of my custom directive to set the ngOptions
of the element, because it gets fired first. But I couldn’t solve it until I realized that the tAttrs
passed as an argument of the compile function is shared between all directive compile functions.
Thanks to that discovery the final implementation was easier than expected since we just need to set the ngOptions
on the shared tAttrs
list during the compile phase. As a side note I want to clarify that the attributes object could have been modified either in the directive controller or the preLink
function with similar outcome, but not in the postLink
as its fired after the parent is linked.
angular.module('angular-country-picker',[]) .directive('pvpCountryPicker', function() { var countries = [ {"name":"Afghanistan","alpha2":"AF","alpha3":"AFG","numeric":"004"}, // Alphabetical list of countries. {"name":"Zimbabwe","alpha2":"ZW","alpha3":"ZWE","numeric":"716"}]; return { controller: function($scope) { $scope.countries = countries; }, compile: function (tElement, tAttrs) { if(! tAttrs.pvpCountryPicker) { tAttrs.pvpCountryPicker = 'alpha2'; } var ngOptions = 'country.' + tAttrs.pvpCountryPicker + ' as country.name for country in countries'; tAttrs.$set('ngOptions', ngOptions); }, restrict: 'A' }; });
To-Do
Most of the time in our community what yesterday worked today is outdated, and with the major rework being done in the beta version of Angular 1.4 my implementation does not work any-more. So hopefully I will be able to fix it before Angular 1.4 become stable. I fixed it with a different approach.
Additionally I read some old post about redesigning the country selector which makes some interesting points hence I would like to work that idea in the future.
But for now you can install it using Bower or fork it from the repository.
$ bower install angular-country-picker
I did the same with knockout js in one of the application
So you should open source it 😉
I can’t see any demo on github or any where for this. Will increase the use of the library if users can SEE what it looks like.
Hi! That’s probably a good idea. Cheers, Pablo.