4
I am trying to create a directive that is an input that provides an object in $Scope only if it is successfully created by its constructor method.
I want the value only to be assigned to the variable in the scope, if it is the result of a constructor of an object, which encapsulates the creation/validation rules in its constructor.
Next to the input, the directive should have a span, where it will display a validation error. If the constructor does not validate the value, an Exception must be generated and displayed in a field next to it, as validation.
Here, I created a cpf object, which encapsulates its rules. The angular directive provides an input that generates the object in $Scope only if it is successfully created.
I created this Address and it works. However, the type restrict: Element does not allow to reuse as well as a component. I cannot declare a placeholder in my custom element, or other things I could apply directly to the input.
I would like to know how to make it into a more modular directive.
Maybe Attribute, so I can decorate the input with other attributes, like a placeholder, or a mask. Or also, use ngModel to know which variable to place the instantiated object.
//-------------Angular---------------------->
        var app = angular.module('teste', []);
        
//Diretiva:
        app.directive('sgInputModel', function(){
            return {
                restrict: 'E',
                scope: {
                    set : '&onSet'
                },
                template: '<input ng-model="modelo" ><span ng-bind="modeloErro"></span>',
                link: function(scope, element, attrs){
                    scope.$watch('modelo', setModelo);
                    function setModelo(){
                        console.log(scope.modelo)
                        scope.modeloErro = '';
                        if(!scope.modelo)
                            return;
                        try{
                            scope.set({value:scope.modelo});
                        }catch(e){
                            scope.modeloErro = e.message;
                        }
                    }
                }
            }
        });
//Controller:
        app.controller('pedidoCtl', [
            '$scope',
            '$http',
            '$log',
            function ($scope, $http, $log, URL_SELECT) {
              
              $scope.sgSetCpf = function (value){
                    $scope.cpf = null;
                    if(value.length == 11)
                        $scope.cpf = new Cpf(value);
                };
              
              }]);
//-------------Objeto CPF---------------------->
    Cpf = function (cpf) {
        cpf = retirarCaracteres(cpf);
        if (!this.validar(cpf))
            throw new CpfException('Cpf inválido');
        Object.defineProperty(this, 'cpf', {
            value: cpf
        });
        
        if(!Cpf.instances[this.formatado]){
            Cpf.instances[this.formatado] = this;
        }
        else
            return Cpf.instances[this.formatado];
    };
    
    Cpf.instances = [];
    Object.defineProperties(Cpf.prototype, {
        formatado: {
            get: function(){
                return this.cpf.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})$/,"$1.$2.$3-$4");
            }
        },
        validar: {
            value: function(cpf){
                cpf = String(cpf);
                var numeros, digitos, soma, i, resultado, digitos_iguais;
                digitos_iguais = 1;
                if (cpf.length < 11)
                    return false;
                for (i = 0; i < cpf.length - 1; i++)
                    if (cpf.charAt(i) != cpf.charAt(i + 1))
                    {
                        digitos_iguais = 0;
                        break;
                    }
                if (!digitos_iguais)
                {
                    numeros = cpf.substring(0, 9);
                    digitos = cpf.substring(9);
                    soma = 0;
                    for (i = 10; i > 1; i--)
                        soma += numeros.charAt(10 - i) * i;
                    resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
                    if (resultado != digitos.charAt(0))
                        return false;
                    numeros = cpf.substring(0, 10);
                    soma = 0;
                    for (i = 11; i > 1; i--)
                        soma += numeros.charAt(11 - i) * i;
                    resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
                    if (resultado != digitos.charAt(1))
                        return false;
                    return true;
                }
                else
                    return false;
            }
        }
    });
    Cpf.prototype.toString = function () {
        return this.formatado;
    };
    
    Cpf.prototype.valueOf = function(){
        return Number(this.ano + this.mes);
    };
    
    
    function CpfException(message) {
      this.name = 'CpfException';
      this.message= message;
    }
    CpfException.prototype = new Error();
    CpfException.prototype.constructor = CpfException;
    function retirarCaracteres(string){
      return String(string).replace(/\D/g, '');
    }<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="teste" ng-controller="pedidoCtl">
  
        Cpf:
        <sg-input-model 
            on-set="sgSetCpf(value)"
        ></sg-input-model>
        {{cpf.formatado}}
  
</body>
I would do the same, receive the variables in element attributes and assign to the package of the directive
– fabiohbarbosa