programing

지시어를 사용하여 AngularJS 브라우저 자동 채우기 회피책

linuxpc 2023. 3. 27. 21:04
반응형

지시어를 사용하여 AngularJS 브라우저 자동 채우기 회피책

Angular Angular에서 하고 기능을 할 때 이후 JS 로그인 폼을 입력하도록 .$scope모델은 자동 채우기에 따라 변경되지 않습니다.

제가 발견한 유일한 해킹은 다음 지시를 사용하는 것입니다.

app.directive("xsInputSync", ["$timeout" , function($timeout) {
    return {
        restrict : "A",
        require: "?ngModel",
        link : function(scope, element, attrs, ngModel) {
            $timeout(function() {
                if (ngModel.$viewValue && ngModel.$viewValue !== element.val()) {
                    scope.apply(function() {
                        ngModel.$setViewValue(element.val());
                    });
                }
                console.log(scope);
                console.log(ngModel.$name);
                console.log(scope[ngModel.$name]);
            }, 3000);
        }
    };
}]);

는 '이러다'라는입니다.ngModel.$setViewValue(element.val());해서 것은 .element.val()?떻게게 하면 ?? ???

이것은 Angular의 기존 문제이며 현재 열려 있습니다.

네가 여기서 뭘 할 수 있을지 모르겠어 네가 하는 일 말고는 말이야올바른 방향으로 가고 있는 것 같아요.브라우저가 당신의 plunk 비밀번호를 기억하도록 할 수 없었기 때문에 이것이 작동할지 모르겠지만 확인해 보세요.

app.directive('autoFillSync', function($timeout) {
   return {
      require: 'ngModel',
      link: function(scope, elem, attrs, ngModel) {
          var origVal = elem.val();
          $timeout(function () {
              var newVal = elem.val();
              if(ngModel.$pristine && origVal !== newVal) {
                  ngModel.$setViewValue(newVal);
              }
          }, 500);
      }
   }
});
<form name="myForm" ng-submit="login()">
   <label for="username">Username</label>
   <input type="text" id="username" name="username" ng-model="username" auto-fill-sync/><br/>
   <label for="password">Password</label>
   <input type="password" id="password" name="password" ng-model="password" auto-fill-sync/><br/>
   <button type="submit">Login</button>
</form>

접근 방식을 좀 단순화하면 될 것 같아요.가 꼭 은 꼭 해 보세요.ngModel.$pristine사용자의 입력을 덮어쓰지 않도록 해야 합니다.3번입니다.$timeout, BTW" $apply()" "Digest" "Digest" "Digest" "Digest" 입니다.

중요한 점은 브라우저가 Angular를 제치고 실행할 수 있다는 것입니다.내 브라우저는?

이것은 아마도 이길 수 없는 전쟁일 것이고, 그래서 앵글(또는 녹아웃)은 그것을 쉽게 해결할 수 없었다.지시문이 처음 실행될 때 입력된 데이터의 상태를 보장할 수 없습니다.앵글이 초기화할 때도...그래서 그것은 해결하기 어려운 문제이다.

여기 제시된 다른 솔루션보다 훨씬 덜 진부하고 의미론적으로 견실한 솔루션이 있습니다.JS: http://victorblog.com/2014/01/12/fixing-autocomplete-autofill-on-angularjs-form-submit/

myApp.directive('formAutofillFix', function() {
  return function(scope, elem, attrs) {
    // Fixes Chrome bug: https://groups.google.com/forum/#!topic/angular/6NlucSskQjY
    elem.prop('method', 'POST');

    // Fix autofill issues where Angular doesn't know about autofilled inputs
    if(attrs.ngSubmit) {
      setTimeout(function() {
        elem.unbind('submit').submit(function(e) {
          e.preventDefault();
          elem.find('input, textarea, select').trigger('input').trigger('change').trigger('keydown');
          scope.$apply(attrs.ngSubmit);
        });
      }, 0);
    }
  };
});

그런 다음 양식에 지시문을 첨부하기만 하면 됩니다.

<form ng-submit="submitLoginForm()" form-autofill-fix>
  <div>
    <input type="email" ng-model="email" ng-required />
    <input type="password" ng-model="password" ng-required />
    <button type="submit">Log In</button>
  </div>
</form>

꼭 쓸 는 없어요.$timeout할 수 .이벤트 시스템을 사용할 수 있습니다.

좀 더 Angularish하고 jQuery나 커스텀 이벤트 캐치에는 의존하지 않습니다.

예를 들어, 송신 핸들러의 경우는, 다음과 같습니다.

$scope.doLogin = function() {
    $scope.$broadcast("autofill:update");

    // Continue with the login.....
};

에 이렇게 요.autofill뭇매를 맞다

.directive("autofill", function () {
    return {
        require: "ngModel",
        link: function (scope, element, attrs, ngModel) {
            scope.$on("autofill:update", function() {
                ngModel.$setViewValue(element.val());
            });
        }
    }
});

마지막으로 HTML은 다음과 같습니다.

<input type="text" name="username" ng-model="user.id" autofill="autofill"/>

더 이상 해킹할 필요 없어!Angular dev tbosch는 브라우저가 변경 이벤트를 트리거하지 않고 양식 필드를 변경할 때 변경 이벤트를 트리거하는 폴리필을 만들었습니다.

https://github.com/tbosch/autofill-event

현재로서는 브라우저의 버그 수정이므로 Angular 코드에 내장하지 않고 Angular 없이 동작합니다(예를 들어 플레인 jQuery 앱).

폴리필은 문서 로드 시 및 입력이 남아 있을 때(같은 형태로만) 변경을 확인합니다.그러나 원하는 경우 수동으로 검사를 트리거할 수 있습니다.

프로젝트에는 유닛 테스트와 반자동 테스트가 있기 때문에 필요한 브라우저 설정과 함께 다양한 사용 사례를 수집할 수 있습니다.

주의:이 폴리필은 플레인 Angular와 함께 작동합니다.JS 앱, AngularJS/jQuery 앱뿐만 아니라 Angular를 사용하지 않는 일반 jQuery 앱도 있습니다."

다음과 같이 설치할 수 있습니다.

bower install autofill-event --save

「」를 합니다.autofill-event.js jQuery 또는 Angular 뒤에 있습니다.

다음과 같은 작업이 수행됩니다.

  • DOMContentLoaded 후: 모든 입력 필드를 확인합니다.
  • 필드가 남았습니다.같은 폼의 다른 모든 필드를 체크합니다.

API(수동으로 검사를 트리거하려면):

  • $el.checkAndTriggerAutoFillEvent(): / 에 대해 jQuery / jQLite DOM 입니다.

구조

  1. 사용자(변경 이벤트 수신) 및 JavaScript(jQuery/jQLite 요소의 $el.val()을 가로채기)에 의한 입력 요소에 대한 모든 변경 사항을 기억하십시오.변경된 값은 개인 속성의 요소에 저장됩니다.

  2. 요소의 자동 채우기 확인: 요소의 현재 값을 기억된 값과 비교합니다.다를 경우 변경 이벤트를 트리거합니다.

의존 관계

AngularJS 또는 jQuery(둘 중 하나 또는 둘 다 사용 가능)

자세한 내용은 github 페이지를 참조하십시오.

Github의 오리지널 Angular Issue #1460은 여기에서 읽을있습니다.

더티 코드. 이 코드를 사용하기 전에 https://github.com/angular/angular.js/issues/1460#issuecomment-18572604 문제가 해결되었는지 확인하십시오.이 지시문은 제출 전뿐만 아니라 필드가 채워지면 이벤트를 트리거합니다(제출 전에 입력을 처리해야 하는 경우 필요).

 .directive('autoFillableField', function() {
    return {
                   restrict: "A",
                   require: "?ngModel",
                   link: function(scope, element, attrs, ngModel) {
                       setInterval(function() {
                           var prev_val = '';
                           if (!angular.isUndefined(attrs.xAutoFillPrevVal)) {
                               prev_val = attrs.xAutoFillPrevVal;
                           }
                           if (element.val()!=prev_val) {
                               if (!angular.isUndefined(ngModel)) {
                                   if (!(element.val()=='' && ngModel.$pristine)) {
                                       attrs.xAutoFillPrevVal = element.val();
                                       scope.$apply(function() {
                                           ngModel.$setViewValue(element.val());
                                       });
                                   }
                               }
                               else {
                                   element.trigger('input');
                                   element.trigger('change');
                                   element.trigger('keyup');
                                   attrs.xAutoFillPrevVal = element.val();
                               }
                           }
                       }, 300);
                   }
               };
});

확실한 해결책이 될 것 같네요jQuery는 필요 없습니다.

갱신:

  • 모델 값이 실제 입력 값과 같지 않은 경우에만 모델이 업데이트됩니다.
  • 체크는 첫 번째 자동 채우기에서 멈추지 않습니다.예를 들어 다른 계정을 사용하고 싶은 경우.

app.directive('autofillable', ['$timeout', function ($timeout) {
    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            scope.check = function(){
                var val = elem[0].value;
                if(ctrl.$viewValue !== val){
                    ctrl.$setViewValue(val)
                }
                $timeout(scope.check, 300);
            };
            scope.check();
        }
    }
}]);

솔루션 1 [$timeout 사용]:

지시:

app.directive('autoFillSync', function($timeout) {
    return {
      require: 'ngModel',
      link: function(scope, elem, attrs, model) {
          var origVal = elem.val();
          $timeout(function () {
              var newVal = elem.val();
              if(model.$pristine && origVal !== newVal) {
                  model.$setViewValue(newVal);
              }
          }, 500);
      }
    };
});

HTML:

<form name="myForm" ng-submit="login()">
  <label for="username">Username</label>
  <input type="text" id="username" name="username" ng-model="username" auto-fill-sync/><br/>
  <label for="password">Password</label>
  <input type="password" id="password" name="password" ng-model="password" auto-fill-sync/><br/>
  <button type="submit">Login</button>
</form>

해결책 2 [각 이벤트 사용]:

참고 자료: Beco의 답변

지시:

app.directive("autofill", function () {
    return {
        require: "ngModel",
        link: function (scope, element, attrs, ngModel) {
            scope.$on("autofill:update", function() {
                ngModel.$setViewValue(element.val());
            });
        }
    };
});

HTML:

<form name="myForm" ng-submit="login()">
  <label for="username">Username</label>
  <input type="text" id="username" name="username" ng-model="username" autofill/><br/>
  <label for="password">Password</label>
  <input type="password" id="password" name="password" ng-model="password" autofill/><br/>
  <button type="submit">Login</button>
</form>

해결책 3 [릴레이 방식 호출 사용]:

지시:

app.directive('autoFill', function() {
    return {
        restrict: 'A',
        link: function(scope,element) {
            scope.submit = function(){
                scope.username = element.find("#username").val();
                scope.password = element.find("#password").val();
                scope.login();//call a login method in your controller or write the code here itself
            }

        }
    };
});

HTML:

<form name="myForm" auto-fill ng-submit="submit()">
   <label for="username">Username</label>
   <input type="text" id="username" name="username" ng-model="username" />
   <label for="password">Password</label>
   <input type="password" id="password" name="password" ng-model="password" />
   <button type="submit">Login</button>
</form>

브라우저의 동작을 에뮬레이트하는 가장 쉬운 방법은 변경 이벤트에 문제가 있을 경우 직접 부팅하는 것입니다.훨씬 더 간단하죠.

지시:

yourModule.directive('triggerChange', function($sniffer) {
    return {
        link : function(scope, elem, attrs) {
            elem.on('click', function(){
                $(attrs.triggerChange).trigger(
                    $sniffer.hasEvent('input') ? 'input' : 'change'
                );
            });
        },
        priority : 1
    }
});

HTML:

<form >
    <input data-ng-model="user.nome" type="text" id="username">

    <input data-ng-model="user.senha" type="password" id="password" >

    <input type="submit" data-ng-click="login.connect()" id="btnlogin" 
           data-trigger-change="#password,#username"/>
</form>

폼에 디렉티브를 붙이고 폼 제출 시 .dirty 클래스가 있는 모든 입력에 대해 이벤트를 실행하는 등 몇 가지 변경을 수행할 수 있습니다.

jQuery 방법은 다음과 같습니다.

$(window).load(function() {
   // updates autofilled fields
   window.setTimeout(function() {
     $('input[ng-model]').trigger('input');
   }, 100);
 });

이것은 Angular way 입니다.

 app.directive('autofill', ['$timeout', function ($timeout) {
    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            $timeout(function(){
                $(elem[0]).trigger('input');
                // elem.trigger('input'); try this if above don't work
            }, 200)
        }
    }
}]);

HTML

<input type="number" autofill /> 

다음은 덜 해킹적이지만 컨트롤러에 추가 코드가 필요한 다른 해결 방법입니다.

HTML:

<form ng-submit="submitForm()" ng-controller="FormController">
    <input type="text" ng-model="username" autocomplete-username>
    <input type="submit">
</form>

지시(CoffeeScript):

directives.directive 'autocompleteUsername', ->
    return (scope, element) ->
        scope.getUsername = ->
            element.val()

컨트롤러:

controllers.controller 'FormController', [->
    $scope.submitForm = ->
        username = $scope.getUsername?() ? $scope.username
        # HTTP stuff...
]

이것은, 송신 버튼의 무효화/유효화 등, 모든 Angular 검증이 설계대로 동작하도록 한 유일한 솔루션입니다.bower 및 스크립트태그 1개를 사용하여 설치합니다.바징가!

https://github.com/tbosch/autofill-event

타임아웃 기능을 사용하지 않고 모델 값을 변경한 것이 효과가 있었습니다.

코드는 다음과 같습니다.

module.directive('autoFill', [ function() {
    return {
        require: 'ngModel',
        link:function(scope, element, attr, ngModel) {
            var origVal = element.val();
            if(origVal){
                ngModel.$modelValue = ngModel.$modelValue || origVal;
            }
        }
    };
}]);

송신 핸들러의 1 행의 회피책(jQuery 필요):

if (!$scope.model) $scope.model = $('#input_field').val();

송신시에 $setValue(val())를 강제 설정합니다(jQuery 없이 동작합니다).

   var ValidSubmit = ['$parse', function ($parse) {
    return {
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                post: function postLink(scope, element, iAttrs, controller) {
                    var form = element.controller('form');
                    form.$submitted = false;
                    var fn = $parse(iAttrs.validSubmit);
                    element.on('submit', function(event) {
                        scope.$apply(function() {
                            var inputs = element.find('input');
                            for(var i=0; i < inputs.length; i++) {
                                var ele = inputs.eq(i);
                                var field = form[inputs[i].name];
                                field.$setViewValue(ele.val());
                            }
                            element.addClass('ng-submitted');
                            form.$submitted = true;
                            if(form.$valid) {
                                fn(scope, {$event:event});
                            }
                        });
                    });
                    scope.$watch(function() { return form.$valid}, function(isValid) {
                        if(form.$submitted == false) return;
                        if(isValid) {
                            element.removeClass('has-error').addClass('has-success');
                        } else {
                            element.removeClass('has-success');
                            element.addClass('has-error');
                        }
                    });
                }
            }
        }
    }
}]
app.directive('validSubmit', ValidSubmit);

Angularjs는 처음이지만, 그 문제에 대한 간단한 해법을 발견했어요=> Angular로 표현 재평가...변경함으로써! (초기 상태로 되돌리려면 초기값을 기억해야 합니다.)다음으로 컨트롤러 기능으로 폼을 송신하는 방법을 나타냅니다.

    $scope.submit = function () {
                var oldpassword = $scope.password;
                $scope.password = '';
                $scope.password = oldpassword;
//rest of your code of the submit function goes here...

물론 비밀번호 입력에 입력된 값은 사용자가 아닌 창에 의해 설정됩니다.

다음 코드를 사용해 볼 수 있습니다.

yourapp.directive('autofill',function () {

    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            var origVal = elem.val();
            if (origVal != '') {
                elem.trigger('input');
            }
        }
    }
});

이 답변에 대한 약간의 수정사항(https://stackoverflow.com/a/14966711/3443828): 브라우저에 레이스를 걸 필요가 없도록 $190 대신 $190을 사용합니다.

mod.directive('autoFillSync', function($interval) {
    function link(scope, element, attrs, ngModel) {
        var origVal = element.val();
        var refresh = $interval(function() {
          if (!ngModel.$pristine) {
            $interval.cancel(refresh);
          }else{
            var newVal = element.val();
            if (origVal !== newVal) {
              ngModel.$setViewValue(newVal);
              $interval.cancel(refresh);
            }
          }
        }, 100);
    }

    return {
      require: 'ngModel',
      link: link
    }
  });

이것이 결국 제 양식에 사용하게 된 해결책입니다.

.directive('autofillSync', [ function(){
  var link = function(scope, element, attrs, ngFormCtrl){
    element.on('submit', function(event){
      if(ngFormCtrl.$dirty){
        console.log('returning as form is dirty');
        return;
      }   
      element.find('input').each(function(index, input){
        angular.element(input).trigger('input');
      }); 
    }); 
  };  
  return {
    /* negative priority to make this post link function run first */
    priority:-1,
    link: link,
    require: 'form'
  };  
}]);

그리고 양식의 템플릿은

<form autofill-sync name="user.loginForm" class="login-form" novalidate ng-submit="signIn()">
    <!-- Input fields here -->
</form>

이렇게 하면 ng-model에서 가지고 있는 모든 파서/포맷터를 실행하여 전송 기능을 투과적으로 할 수 있었습니다.

지침 없는 솔루션:

.run(["$window", "$rootElement", "$timeout", function($window, $rootElement, $timeout){

        var event =$window.document.createEvent("HTMLEvents");
        event.initEvent("change", true, true);

        $timeout(function(){

            Array.apply(null, $rootElement.find("input")).forEach(function(item){
                if (item.value.length) {
                    item.$$currentValue = item.value;
                    item.dispatchEvent(event);
                }
            });

        }, 500);
    }])

이것은 Firefox와 Chrome에서 테스트한 모든 경우에 적용되는 간단한 수정입니다.top answer(timeout을 수반하는 지시)에서는, 다음과 같은 문제가 있었습니다.

  • 브라우저의 뒤로/앞으로 버튼, 페이지 로드 이벤트를 다시 시작하지 않음(이 때문에 수정이 적용되지 않음)
  • 페이지 로드 후 일정 시간 후 자격 증명 로드. 예를 들어 Firefox에서 로그인 상자를 두 번 클릭하고 저장된 자격 증명 중에서 선택합니다.
  • 유효한 입력이 제공될 때까지 로그인 버튼을 비활성화하기 때문에 양식을 제출하기 전에 업데이트할 솔루션이 필요합니다.

이 수정은 분명 매우 어리석고 해킹적이지만, 100% 효과가 있습니다.

function myScope($scope, $timeout) {
    // ...
    (function autoFillFix() {
        $timeout(function() { 
            $('#username').trigger('change'); 
            $('#password').trigger('change'); 
            autoFillFix(); }, 500);                    
    })();
}

이 솔루션들 중 어느 것도 제 사용 사례에 효과가 없었습니다.변경 내용을 확인하기 위해 ng-change를 사용하는 폼 필드가 있습니다.사용.$watch자동 채우기에 의해 트리거되지 않기 때문에 도움이 되지 않습니다.송신 버튼이 없기 때문에, 몇개의 솔루션을 실행할 수 있는 간단한 방법이 없고, 인터벌 사용에도 성공하지 못했습니다.

결국 자동 채우기를 비활성화했습니다. 이상적이지는 않지만 사용자에게 훨씬 덜 혼란스러웠습니다.

<input readonly onfocus="this.removeAttribute('readonly');">

해답은 이쪽

jQuery를 사용하는 경우 폼 제출 시 이 작업을 수행할 수 있습니다.

HTML:

<form ng-submit="submit()">
    <input id="email" ng-model="password" required 
           type="text" placeholder="Your email">
    <input id="password" ng-model="password" required 
           type="password" placeholder="Password">
</form>

JS:

 $scope.submit = function() {
     $scope.password = $('#password').val();
}

단순하게 하려면 javascript를 사용하여 값을 구하십시오.

각도 js 컨트롤러:

var 사용자 이름 = document.getElementById('사용자 이름')입니다.가치

언급URL : https://stackoverflow.com/questions/14965968/angularjs-browser-autofill-workaround-by-using-a-directive

반응형