Obejście autouzupełniania przeglądarki AngularJS przy użyciu dyrektywy

111

Wysyłając formularz w AngularJS i korzystając z przeglądarki zapamiętaj hasło, a przy kolejnej próbie logowania pozwolisz przeglądarce wypełnić formularz logowania nazwą użytkownika i hasłem, $scopemodel nie zostanie zmieniony na podstawie autouzupełniania.

Jedyny brudny hack, jaki znalazłem, to użycie następującej dyrektywy:

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);
        }
    };
}]);

Problem w tym, że ngModel.$setViewValue(element.val());nie zmienia modelu ani widoku na podstawie element.val()zwróconej wartości. Jak mogę to osiągnąć?

lucassp
źródło
Ten kod wygląda dobrze na pierwszy rzut oka ... ale gdzie jest reszta (znaczniki itp.)? Czy masz jakieś skrzypce, które widzimy?
Ben Lesh
Oto plunk : plnkr.co/edit/CHrBAVU9Ycl2ex2DRr6R Nie jestem pewien, czy działa bezpośrednio na plunkerze, ponieważ działa w ramce iframe.
lucassp
1
Nie musisz określać zakresu. $ Zastosuj wewnątrz $ timeout kątowego. Możesz go potrzebować w natywnym window.setTimeout. Ale lepszym pomysłem jest skorzystanie z wersji Angulara.
gorpacrate
1
Istnieje "oficjalna" poprawka dotycząca tego problemu, opracowana przez firmę Angular dev tbosch . Szczegółowe informacje można znaleźć na stronie answer stackoverflow.com/a/25687396/3009639 poniżej.
orszaczky
Niestety „oficjalna” poprawka to porzucić oprogramowanie i nie działa w wielu przeglądarkach. Problemy zostały zgłoszone, ale nie zostały rozwiązane, więc poszukiwania są kontynuowane ...
cyberwombat

Odpowiedzi:

45

Najwyraźniej jest to znany problem z Angular i obecnie jest otwarty

Nie jestem pewien, co mógłbyś tutaj zrobić oprócz jakiejś pracy, takiej jak próba. Wygląda na to, że jesteś na dobrej drodze. Nie udało mi się zmusić przeglądarki, aby spróbowała zapamiętać hasło do Twojego pliku plunk, więc nie jestem pewien, czy to zadziała, ale spójrz:

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>

Myślę, że po prostu musisz trochę uprościć swoje podejście. Jedyną rzeczą, którą zdecydowanie zalecam, jest sprawdzenie ngModel.$pristinei upewnienie się, że nie nadpisujesz danych wejściowych złego użytkownika. Ponadto 3 sekundy to prawdopodobnie za długo. Nie powinieneś być zmuszony do wywoływania $ apply () w $ timeout, BTW, powinno automatycznie ustawić w kolejce $ podsumowanie.

Prawdziwy haczyk: czy Twoja przeglądarka pokonuje Angulara w wykonaniu? A co z moją przeglądarką?

Jest to prawdopodobnie wojna nie do wygrania, dlatego Angular (lub Knockout) nie był w stanie jej łatwo rozwiązać. Nie ma gwarancji stanu danych wprowadzonych w momencie początkowego wykonania dyrektywy. Nawet w momencie inicjalizacji Angulara ... Więc jest to trudny problem do rozwiązania.

Ben Lesh
źródło
1
Słuszna uwaga o nieskazitelnym stanie. Cóż, 3 sekundy służą tylko do testów. Wydaje się, że okno dialogowe „Zapisz hasło” działa w przeglądarce Safari. To kolejna kwestia, którą muszę zbadać.
lucassp
Po prostu oszukuj go lokalnym magazynem. :) ... Będę o tym myślał. Mam jednak wątpliwości co do wykonalności działania autouzupełniania z dowolnymi wiązaniami dwukierunkowymi.
Ben Lesh,
Tak, ale nadal muszę być w stanie zaktualizować model z dyrektywy, aby działał.
lucassp
1
Żartowałem z localStorage, nie chciałbyś tam przechowywać haseł.
Ben Lesh,
1
To nie zadziała z Safari i autouzupełnianiem karty kredytowej, ponieważ to autouzupełnianie jest uruchamiane w dowolnym momencie przez użytkownika
Dallas Clark
35

Oto rozwiązanie, które jest znacznie mniej hakerskie niż inne prezentowane rozwiązania i jest semantycznie poprawne AngularJS: 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);
    }
  };
});

Następnie wystarczy dołączyć dyrektywę do formularza:

<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>
Ezekiel Victor
źródło
2
Ten działał. Wypróbowaliśmy większość powyższych bez żadnego rezultatu. Dzięki!!! Wynik jest na mobbr.com
Patrick Savalle
1
Ponieważ korzysta z jQuery, nie oczekuje się, że będzie działać bez jQuery.
Quinn Strahl
1
Mamy rok 2018 i to wciąż jest poprawka. Dzięki Ezechiel!
Scott Manny
35

Nie musisz używać $timeoutani niczego takiego. Możesz skorzystać z systemu zdarzeń.

Myślę, że jest bardziej Angularish i nie zależy od jQuery ani niestandardowego przechwytywania zdarzeń.

Na przykład w programie obsługi przesyłania:

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

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

Następnie możesz mieć taką autofilldyrektywę:

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

Wreszcie Twój kod HTML będzie wyglądał następująco:

<input type="text" name="username" ng-model="user.id" autofill="autofill"/>
bekos
źródło
14
W moim przypadku przycisk przesyłania jest wyłączony, gdy dane wejściowe są puste.
gorpacrate
4
Czy nigdy nie masz z tym problemu, ponieważ jest asynchroniczny? gdzie wywołanie logowania do serwera już wychodzi, zanim zdarzenie zostało zreplikowane, a dyrektywa miała czas na zaktualizowanie zakresu?
Sander,
12

Nie musisz już hakować! Angular dev tbosch stworzył polyfill, który wyzwala zdarzenie change, gdy przeglądarka zmienia pola formularza bez wyzwalania zdarzenia change:

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

Na razie nie wbudują tego w kod Angular, ponieważ jest to poprawka błędu przeglądarki, a także działa bez Angulara (np. Dla zwykłych aplikacji jQuery).

„Wypełnienie będzie sprawdzać zmiany w ładowaniu dokumentu, a także po pozostawieniu danych wejściowych (tylko w tej samej formie). Jeśli chcesz, możesz jednak uruchomić sprawdzanie ręcznie.

Projekt zawiera testy jednostkowe, a także testy półautomatyczne, więc w końcu mamy miejsce na zebranie wszystkich różnych przypadków użycia wraz z wymaganymi ustawieniami przeglądarki.

Uwaga: to wypełnienie działa ze zwykłymi aplikacjami AngularJS, z aplikacjami AngularJS / jQuery, ale także ze zwykłymi aplikacjami jQuery, które nie używają Angular. "

Można go zainstalować z:

bower install autofill-event --save

Dodaj skrypt autofill-event.js po jQuery lub Angular na swojej stronie.

Spowoduje to wykonanie następujących czynności:

  • po DOMContentLoaded: sprawdź wszystkie pola wejściowe
  • pole jest pozostawione: zaznacz wszystkie inne pola w tym samym formularzu

API (aby ręcznie uruchomić sprawdzanie):

  • $el.checkAndTriggerAutoFillEvent(): Wykonaj sprawdzenie wszystkich elementów DOM w danym elemencie jQuery / jQLite.

Jak to działa

  1. Zapamiętaj wszystkie zmiany w elementach wejściowych przez użytkownika (nasłuchiwanie zdarzeń zmian), a także przez JavaScript (przechwytując $ el.val () dla elementów jQuery / jQLite). Ta zmieniona wartość jest przechowywana w elemencie we właściwości prywatnej.

  2. Sprawdzanie elementu pod kątem automatycznego wypełnienia: Porównaj bieżącą wartość elementu z zapamiętaną wartością. Jeśli jest inny, wywołaj zdarzenie zmiany.

Zależności

AngularJS lub jQuery (działa z jednym lub dwoma)

Więcej informacji i źródło na stronie github .

Oryginalne wydanie Angular nr 1460 na Github można przeczytać tutaj.

orszaczky
źródło
2
To nie działa w moich przypadkach. Metoda checkAndTriggerAutoFillEvent () jest wyzwalana i generuje zdarzenia, ale AngularJS nigdy nie aktualizuje swoich modeli i uważa, że ​​pola są puste.
Splaktar
Nie miałem żadnych problemów z użyciem tego polyillu. Jeśli nie możesz sprawić, by działał poprawnie, utwórz osobne pytanie zawierające kod. Jeśli znajdziesz błąd, sprawdź bilety na github lub otwórz nowy.
orszaczky
Tak, myślę, że jest to związane z tym błędem: github.com/tbosch/autofill-event/issues/11
Splaktar
1
ngModelOptionsw połączeniu z autofill-eventoznacza, że ​​możesz teraz określić changejako jedno ze updateOnzdarzeń, aby upewnić się, że model jest poprawnie zsynchronizowany.
morloch
10

Brudny kod, sprawdź, czy problem https://github.com/angular/angular.js/issues/1460#issuecomment-18572604 został naprawiony przed użyciem tego kodu. Ta dyrektywa wyzwala zdarzenia, gdy pole jest wypełnione, nie tylko przed przesłaniem (jest to konieczne, jeśli musisz obsłużyć dane wejściowe przed przesłaniem)

 .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);
                   }
               };
});
OZ_
źródło
5

Wydaje się, że jasne rozwiązanie na wprost. Nie potrzeba jQuery.

AKTUALIZACJA:

  • Model jest aktualizowany tylko wtedy, gdy wartość modelu nie jest równa rzeczywistej wartości wejściowej.
  • Sprawdzanie nie kończy się przy pierwszym autouzupełnianiu. Na przykład, jeśli chcesz użyć innego konta.

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();
        }
    }
}]);
gorpacrate
źródło
4
+1 dobre rozwiązanie, podobne do tego, które wymyśliłem. Jedyne co sugerowałbym to najpierw sprawdzić czy model jest $pristineprzed zmianą, a dopiero po zmianie zachować jego $pristinestan. W przeciwnym razie okaże się, że jeśli formularz zostanie załadowany bez danych autouzupełniania, powyższa dyrektywa nadal będzie aktualizować model, a następnie sprawi, że dirtynawet jeśli formant formularza powinien być nadal uważany za nietknięty. przykład tutaj, używając twojej dyrektywy. Skomentowałem kod, który chciałbym do niego dodać: jsfiddle.net/OACDesigns/L8Sja/4
OACDesigns
1
również, myślę, że scope:truepowinno byćscope:{}
OACDesigns
4

Rozwiązanie 1 [użycie $ timeout]:

Dyrektywa:

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>

Rozwiązanie 2 [Korzystanie ze zdarzeń kątowych]:

Ref: odpowiedź Becko

Dyrektywa:

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>

Rozwiązanie 3 [Korzystanie z wywołań metod przekazywania]:

Dyrektywa:

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>
Robin Rizvi
źródło
2
Rozwiązanie 1 działało bardzo dobrze przez jakiś czas, ale teraz na angularjs 1.4.9 już nie działa. Sprawdzanie model.$validdyrektywy zwraca wartość true zarówno przed, jak i po $setViewValue, ale element nadal jest z ng-invalidklasą
Jan,
4

Cóż, najłatwiej jest naśladować zachowanie przeglądarki, więc jeśli wystąpi problem ze zdarzeniem zmiany, po prostu uruchom je samodzielnie. Dużo prostsze.

Dyrektywa:

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>

Możesz zrobić kilka odmian, takich jak umieszczenie dyrektywy w formularzu i wywołanie zdarzenia na wszystkich wejściach z klasą .dirty podczas przesyłania formularza.

pedroassis
źródło
3

To jest sposób jQuery:

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

To jest Angular sposób:

 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 /> 
Nishchit Dhanani
źródło
2
Całkowicie nie-kątowy sposób.
gorpacrate
1
@gorpacrate: Teraz sprawdź to pod kątem.
Nishchit Dhanani
2
Zakładki Angular Way mają zbyt wiele spacji. Tylko żartuje. Uwielbiam przewijanie w poziomie.
Daniel Birowsky Popeski
to nie działa w trybie kątowym, ponieważ nie ma wyzwalacza funkcji na elemencie. Myślę, że wymagałoby to uwzględnienia jquery
Tomas
1
triggerHandler('input')powinno być ok, jeśli nie masz pełnego jquery
Mutmatt
1

Oto inne obejście, które jest mniej hakerskie, ale wymaga dodatkowego kodu w kontrolerze.

HTML:

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

Dyrektywa (CoffeeScript):

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

Kontroler:

controllers.controller 'FormController', [->
    $scope.submitForm = ->
        username = $scope.getUsername?() ? $scope.username
        # HTTP stuff...
]
ukłucie
źródło
Masz to w waniliowym JavaScript?
f1lt3r
CoffeeScript.org zapewnia tłumacza: zrobiono tutaj
jab
1

To jedyne rozwiązanie, które znalazłem, które pozwoliło wszystkim walidacjom mojego Angulara działać zgodnie z przeznaczeniem, w tym wyłączyć / włączyć przycisk przesyłania. Instaluje się z altanką i 1 tagiem skryptu. Bazinga!

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

Roland Hordos
źródło
1
to wypełnienie poly nie pasuje do przycisku przesyłania / wejścia wiążącego się ze stanem formularza. chyba że klikniesz na stronie dowolny punkt, w którym chcesz wywołać skrót (wydaje się, że akcja powoduje, że przeglądarka wykonuje prawdziwe wypełnienie), wtedy przycisk staje się aktywny.Strona testowa z testami ręcznymi
e-chmura.
1

Zmiana wartości modelu zamiast korzystania z funkcji limitu czasu zadziałała dla mnie.

Oto mój kod:

module.directive('autoFill', [ function() {
    return {
        require: 'ngModel',
        link:function(scope, element, attr, ngModel) {
            var origVal = element.val();
            if(origVal){
                ngModel.$modelValue = ngModel.$modelValue || origVal;
            }
        }
    };
}]);
Swaron Chen
źródło
1

Jednowierszowe obejście w procedurze obsługi przesyłania (wymaga jQuery):

if (!$scope.model) $scope.model = $('#input_field').val();
archpollux
źródło
Tak naprawdę nie jest to jednolinijka, jeśli jest zawarta w dyrektywie, a z pewnością powinna.
isherwood
0

Wymuszam $ setValue (val ()) przy przesyłaniu: (to działa bez 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);
malix
źródło
0

Jestem bardzo nowy w Angularjs, ale znalazłem proste rozwiązanie tego problemu => Zmuszanie Angulara do ponownej oceny wyrażenia ... zmieniając je! (oczywiście musisz zapamiętać wartość początkową, aby powrócić do stanu początkowego) Oto sposób, w jaki wygląda to w funkcji kontrolera podczas wysyłania formularza:

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

gdzie oczywiście wartość wprowadzona do hasła została ustawiona przez system Windows, a nie przez użytkownika.

Le neveu
źródło
0

Możesz wypróbować ten kod:

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

    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            var origVal = elem.val();
            if (origVal != '') {
                elem.trigger('input');
            }
        }
    }
});
Rohit
źródło
0

Niewielka modyfikacja tej odpowiedzi ( https://stackoverflow.com/a/14966711/3443828 ): użyj interwału $ zamiast limitu czasu $, aby nie musieć ścigać się z przeglądarką.

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
    }
  });
user3443828
źródło
0

To jest rozwiązanie, które ostatecznie wykorzystałem w moich formularzach.

.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'
  };  
}]);

A szablon formularza będzie

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

W ten sposób mogłem uruchomić wszystkie parsery / elementy formatujące, które mam w moim modelu ng i mieć przejrzystą funkcjonalność przesyłania.

Anirudhan J
źródło
0

Rozwiązanie bez dyrektyw:

.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);
    }])
ReklatsMasters
źródło
0

To prosta poprawka, która działa we wszystkich przypadkach, które przetestowałem zarówno w przeglądarce Firefox, jak i Chrome. Zauważ, że przy najwyższej odpowiedzi (dyrektywa bez limitu czasu) miałem problemy z -

  • Przyciski wstecz / dalej przeglądarki, nie uruchamiaj ponownie zdarzeń ładowania strony (aby poprawka nie miała zastosowania)
  • Ładowanie danych logowania jakiś czas po załadowaniu strony. np. w przeglądarce Firefox kliknij dwukrotnie pole logowania i wybierz spośród zapisanych poświadczeń.
  • Potrzebuję rozwiązania, które aktualizuje się przed przesłaniem formularza, ponieważ wyłączam przycisk Zaloguj do czasu podania poprawnych danych wejściowych

Ta poprawka jest oczywiście bardzo głupia i hakerska, ale działa w 100% przypadków -

function myScope($scope, $timeout) {
    // ...
    (function autoFillFix() {
        $timeout(function() { 
            $('#username').trigger('change'); 
            $('#password').trigger('change'); 
            autoFillFix(); }, 500);                    
    })();
}
Richard Nichols
źródło
1
mogą zastąpić $timeoutz $intervaldać przyszłość DEVS nieco więcej kontekstu i pozbyć się dziwnie wyglądających wywołania rekurencyjne tam dzieje
Mutmatt
0

Żadne z tych rozwiązań nie działało w moim przypadku użycia. Mam kilka pól formularza, które używają ng-change do obserwowania zmian. Za pomocą$watch nie pomaga, ponieważ nie jest uruchamiane przez autouzupełnianie. Ponieważ nie mam przycisku przesyłania, nie ma łatwego sposobu na uruchomienie niektórych rozwiązań i nie udało mi się użyć interwałów.

Skończyło się na wyłączeniu autouzupełniania - nie jest to idealne rozwiązanie, ale znacznie mniej zagmatwane dla użytkownika.

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

Znalazłem odpowiedź tutaj

cyberwombat
źródło
-1

Jeśli używasz jQuery, możesz to zrobić w formularzu:

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();
}
Hans Kerkhof
źródło
1
Chociaż może to zadziałać, nie jest rozsądne w przypadku bardziej złożonych formularzy.
origin1tech
-1

Jeśli chcesz zachować prostotę, po prostu uzyskaj wartość za pomocą javascript

W kontrolerze Angular JS:

var nazwa_użytkownika = document.getElementById ('nazwa_użytkownika'). wartość;

user361697
źródło
Myślę, że nie rozumiesz, w czym tkwi problem
aelor