Angular Directives with object-constructing methods

Asked

Viewed 896 times

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>

1 answer

1

You could put more variables in the Cope and be passing them the placeholder, for example.

You would also have to modify your template to accept this placeholder.

You could put for example all attributes of an input in Scope and pass them through Scope.

  • I would do the same, receive the variables in element attributes and assign to the package of the directive

Browser other questions tagged

You are not signed in. Login or sign up in order to post.