Angular.js: ngModelController $parsers рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд▓рдЧрд╛рддрд╛рд░ рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ

рдХреЛ рдирд┐рд░реНрдорд┐рдд 10 рдЕрдЧре░ 2015  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: angular/angular.js

ngModelController $parser рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреБрдЫ рдирд┐рдпрдореЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рдЗрдирдкреБрдЯ рдорд╛рдиреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╕рдордп, $parser рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмрд╛рд░-рдмрд╛рд░ "рдЕрдорд╛рдиреНрдп" рдХреАрд╕реНрдЯреНрд░реЛрдХреНрд╕ рдкрд░ рдирд╣реАрдВ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдЕрдорд╛рдиреНрдп рд╡рд░реНрдгреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдирд┐рд░реНрджреЗрд╢ рд╕рднреА рдЧреИрд░-рдЕрдВрдХреАрдп рд╡рд░реНрдгреЛрдВ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред рдпрд╣ рдЬреНрдпрд╛рджрд╛рддрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдПрдХ рд╣реА рдЧреИрд░-рдЕрдВрдХреАрдп рд╡рд░реНрдг рдХреЛ рд▓рдЧрд╛рддрд╛рд░ рджреЛ рдмрд╛рд░ рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╣реИрдВ (рдЬреИрд╕реЗ 'xx'), рддреЛ рдЗрдирдкреБрдЯ рдореЗрдВ рдПрдХ 'x' рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ред рдпрджрд┐ рдЖрдк рддреАрд╕рд░реА рдмрд╛рд░ 'x' рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ 'x' рдХреЛ рд╣рдЯрд╛ рджреЗрдЧрд╛ред

рдореИрдВрдиреЗ рдПрдХ рдЕрд╕рдлрд▓ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓рд╛ рднреА рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рд╣реИред

рд╕рднреА рдХреЛрдб http://codepen.io/visnup/pen/YXgLVq?editors=101 рдкрд░ рдЪрд▓ рд░рд╣реЗ рд╣реИрдВ

рдирд┐рд░реНрджреЗрд╢рд╛рддреНрдордХ рдЙрдкрдпреЛрдЧ

<div ng-app="digits">
  <input ng-model="number" placeholder="digits only" digits-only />
</div>

рдЖрджреЗрд╢

angular
  .module('digits', [])
  .directive('digitsOnly', function() {
    return {
      require: 'ngModel',
      link: function link(scope, element, attrs, ngModel) {
        ngModel.$parsers.push(function(value) {
          var numbers = value.replace(/\D/g, '');
          element.val(numbers);
          return numbers;
        });
      }
    };
  });

рдЕрд╕рдлрд▓ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓рд╛

describe('digits', function() {
  beforeEach(angular.mock.module('digits'));

  let scope, input;
  beforeEach(inject(function($compile, $rootScope) {
    scope = $rootScope;
    input = $compile('<input ng-model="number" digits-only />')(scope);
  }));

  // works
  it('should block non-digits', function() {
    input.val('111x');
    input.triggerHandler('input');
    expect(input.val()).to.equal('111');
  });

  // doesn't work
  it('should not flash incorrect input', function() {
    input.val('111x');
    input.triggerHandler('input');
    input.val('111x');
    input.triggerHandler('input');
    expect(input.val()).to.equal('111');
  });
});

рдЗрд╕реЗ рдкрд╣рд▓реЗ #10700 рдореЗрдВ рд▓рд╛рдпрд╛ рдЬрд╛ рдЪреБрдХрд╛ рд╣реИред

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

$parsers $viewValue рдХреЛ $modelValue рд░реВрдк рдореЗрдВ "рд╕рд╣реЗрдЬрдиреЗ" рд╕реЗ рдкрд╣рд▓реЗ рдмрджрд▓рдиреЗ (рдХреА рдПрдХ рдкреНрд░рддрд┐) рдХреЗ рд▓рд┐рдП рд╣реИ (рдФрд░ рдпрд╣реА рдЖрдкрдХрд╛ рдЙрджрд╛рд╣рд░рдг рдХрд░ рд░рд╣рд╛ рд╣реИ)ред рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ $viewValue рдХреЛ рдирд╣реАрдВ рдмрджрд▓ рд░рд╣рд╛ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рддрддреНрд╡ рдХреЗ рдореВрд▓реНрдп рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИ), рдЬрд┐рд╕рд╕реЗ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрддрд╛ рд╣реИред

рдпрд╣ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рдмреЗрд╣рддрд░ рд╕рдЪрд┐рддреНрд░ рд╣реИ:

  1. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ '1' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд


      • $viewValue : 1


      • element.val() : 1



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1


      • element.val() : 1



  2. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x


      • element.val() : 1x



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x (рдкрд╛рд░реНрд╕рд░ рдПрдлрдПрди рд╕реЗ рдХрднреА рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛)


      • element.val() : 1 (рдкрд╛рд░реНрд╕рд░ рдПрдлрдПрди рд╕реЗ рдЕрджреНрдпрддрди)



  3. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x (рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЧрдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдкрд┐рдЫрд▓рд╛ $viewValue рднреА 1x )


      • element.val() : 1x



    • _No_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ (рдЪреВрдВрдХрд┐ $viewValue рдореЗрдВ рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЧрдпрд╛) !!!



      • $modelValue : 1


      • $viewValue : 1x


      • element.val() : 1x



  4. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1xx


      • element.val() : 1xx



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1xx


      • element.val() : 1



  5. _(...рдмреИрдХ рдЯреВ рд╕реНрдЯреЗрдк (2)...)_

рдЗрд╕реЗ рдареАрдХ рд╕реЗ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рдХрдИ "рдХреЛрдгреАрдп" рддрд░реАрдХреЗ рд╣реИрдВ, рдЬреИрд╕реЗ:

ngModel.$parsers.push(function (value) {
  var numbers = value.replace(/\D/g, '');
  if (numbers !== value) {
    ngModel.$setViewValue(numbers);   // Update the `$viewValue`
    ngModel.$render();                // Update the element's displayed value
  }
  return numbers;
});

рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдкреЗрди


рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╕рдм рдХреБрдЫ рдЙрдореНрдореАрдж рдХреЗ рдореБрддрд╛рдмрд┐рдХ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред
@visnup , рдЕрдЧрд░ рдХреБрдЫ рднреА рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рддреЛ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рдорд╣рд╕реВрд╕ рдХрд░реЗрдВред

рд╕рднреА 3 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

$parsers $viewValue рдХреЛ $modelValue рд░реВрдк рдореЗрдВ "рд╕рд╣реЗрдЬрдиреЗ" рд╕реЗ рдкрд╣рд▓реЗ рдмрджрд▓рдиреЗ (рдХреА рдПрдХ рдкреНрд░рддрд┐) рдХреЗ рд▓рд┐рдП рд╣реИ (рдФрд░ рдпрд╣реА рдЖрдкрдХрд╛ рдЙрджрд╛рд╣рд░рдг рдХрд░ рд░рд╣рд╛ рд╣реИ)ред рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ $viewValue рдХреЛ рдирд╣реАрдВ рдмрджрд▓ рд░рд╣рд╛ рд╣реИ (рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рддрддреНрд╡ рдХреЗ рдореВрд▓реНрдп рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИ), рдЬрд┐рд╕рд╕реЗ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛрддрд╛ рд╣реИред

рдпрд╣ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд╕рд╛рде рдмреЗрд╣рддрд░ рд╕рдЪрд┐рддреНрд░ рд╣реИ:

  1. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ '1' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : рдЕрдкрд░рд┐рднрд╛рд╖рд┐рдд


      • $viewValue : 1


      • element.val() : 1



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1


      • element.val() : 1



  2. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x


      • element.val() : 1x



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x (рдкрд╛рд░реНрд╕рд░ рдПрдлрдПрди рд╕реЗ рдХрднреА рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛)


      • element.val() : 1 (рдкрд╛рд░реНрд╕рд░ рдПрдлрдПрди рд╕реЗ рдЕрджреНрдпрддрди)



  3. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1x (рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЧрдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдкрд┐рдЫрд▓рд╛ $viewValue рднреА 1x )


      • element.val() : 1x



    • _No_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ (рдЪреВрдВрдХрд┐ $viewValue рдореЗрдВ рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рдирд╣реАрдВ рдкрд╛рдпрд╛ рдЧрдпрд╛) !!!



      • $modelValue : 1


      • $viewValue : 1x


      • element.val() : 1x



  4. рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ 'x' рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рддрд╛ рд╣реИред

    • _рдкрд╣рд▓реЗ_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1xx


      • element.val() : 1xx



    • _рдмрд╛рдж_ рдкрд╛рд░реНрд╕рд┐рдВрдЧ:



      • $modelValue : 1


      • $viewValue : 1xx


      • element.val() : 1



  5. _(...рдмреИрдХ рдЯреВ рд╕реНрдЯреЗрдк (2)...)_

рдЗрд╕реЗ рдареАрдХ рд╕реЗ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рдХрдИ "рдХреЛрдгреАрдп" рддрд░реАрдХреЗ рд╣реИрдВ, рдЬреИрд╕реЗ:

ngModel.$parsers.push(function (value) {
  var numbers = value.replace(/\D/g, '');
  if (numbers !== value) {
    ngModel.$setViewValue(numbers);   // Update the `$viewValue`
    ngModel.$render();                // Update the element's displayed value
  }
  return numbers;
});

рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдкреЗрди


рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдХреНрдпреЛрдВрдХрд┐ рд╕рдм рдХреБрдЫ рдЙрдореНрдореАрдж рдХреЗ рдореБрддрд╛рдмрд┐рдХ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИред
@visnup , рдЕрдЧрд░ рдХреБрдЫ рднреА рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рддреЛ рдкреНрд░рд╢реНрдиреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рддрдВрддреНрд░ рдорд╣рд╕реВрд╕ рдХрд░реЗрдВред

рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдХрд┐рд╕реА рднреА рд╕рдордп рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХреАрд╕реНрдЯреНрд░реЛрдХ рдХреЗ рд╕рд╛рде рд╣реЛрддреА рд╣реИ рдЬрдм рдирдпрд╛ $viewValue рдкреНрд░рддрд┐рдмрджреНрдз рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред $parsers рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ $setViewValue рдХреЗ рд╕реБрдЭрд╛рдП рдЧрдП рдЙрдкрдпреЛрдЧ рдХреЛ рдХрднреА-рдХрднреА рдХреБрдЫ рдлрд╝реЛрд░рдо рдореЗрдВ рд╕реАрдзреЗ $viewValue рд╕реЗрдЯ рдХрд░рдиреЗ рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХреЗ рд╕рд╛рде рдЯрд╛рд▓рд╛ рдЬрд╛рддрд╛ рд╣реИред

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рднреА рдХрд╛рдо рдХрд░реЗрдВрдЧреЗ:

ngModel.$viewValue = numbers;   // Update the '$viewValue'
ngModel.$commitViewValue(); //update $$lastCommittedViewValue
ngModel.$render();                // Update the element's displayed value

рдпрджрд┐ рдЖрдк рдХрд┐рд╕реА рднреА рд░рд┐рдХрд░реНрд╕рди рдиреБрдХрд╕рд╛рди рд╕реЗ рдмрдЪрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рддреЛ $$lastCommittedViewValue рдХреЛ рд╕реАрдзреЗ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ рдЖрдкрдХреЛ рдПрдирдХреИрдкреНрд╕реБрд▓реЗрд╢рди рдХрд╛ рдЙрд▓реНрд▓рдВрдШрди рдХрд░рдиреЗ рдореЗрдВ рдХреЛрдИ рдЖрдкрддреНрддрд┐ рдирд╣реАрдВ рд╣реИред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ рдЬрдм рдЗрди рдХрд╛рд░реНрдпреЛрдВ рдореЗрдВ рдЕрдирдВрдд рд░рд┐рдХрд░реНрд╕рди рд╣реЛрддрд╛ рд╣реИ рддреЛ рдореИрдВрдиреЗ рдРрд╕реЗ рдорд╛рдорд▓реЗ рджреЗрдЦреЗ рд╣реИрдВ рдЬрд╣рд╛рдВ рдЕрдзрд┐рдХрддрдо рдШрдЯрдирд╛рдУрдВ рдХреЗ рдмрд╛рдж рднреА рдХрдВрд╕реЛрд▓ рдХреЛ рдЗрд╕рдХреА рд╕реВрдЪрдирд╛ рдирд╣реАрдВ рджреА рдЬрд╛рддреА рд╣реИред рдкрд░реАрдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рдмреНрд░реЗрдХ рдкреНрд╡рд╛рдЗрдВрдЯ рд▓рдЧрд╛рдиреЗ рдФрд░ рдХрд┐рд╕реА рднреА рд░рд┐рдХрд░реНрд╕рди рдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдорд┐рдирдЯреЛрдВ рдХрд╛ рд╕рдордп рд▓рдЧрддрд╛ рд╣реИред

@gkalpak рдФрд░ @snaptech рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдПрдХ рд╕рд╛рде рдорд┐рд▓рдХрд░ рдПрдХ рд╕реБрдирд╣рд░рд╛ рд╕рдорд╛рдзрд╛рди рдмрдирд╛рддреЗ рд╣реИрдВ :): +1:

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

ashclarke picture ashclarke  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

landed1 picture landed1  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

guyandtheworld picture guyandtheworld  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

butchpeters picture butchpeters  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ceymard picture ceymard  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ