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