32

I have a problem and very strange behavior with autofill in Chrome. When I login and then logout from app, input fields (email, password) were autocompleted but fields looks like they are frozen and not clickable.

This bug is not every time reproduced, it happens in 1/10 cases. I noticed on logout when fields get autocompleted, after 1 seconds font gets smaller in inputs and after that if you click on input there it seems like you are not clicking , nothing happens, but if you type some text (numbers not work, stays like frozen) input field goes as normal.

Here is gif with strange behavior: https://gifyu.com/image/kTkX

I tried to set autocomplete="off" , but not working.

Also I matched all css clases in input fields to see is there some overriding css, but everything looks good.

<form [formGroup]="loginForm">

<input id="emailHeader" type="text" formControlName="email" placeholder="E-mail">

<input #password type="password" formControlName="password" placeholder="Lozinka">
<input type="submit" (click)="executeLogin()"  value="Prijava">

</form> 

I expect to fields not been frozen after autofill.

public loginForm: FormGroup;
  public emailInput: ElementRef;
  public passwordInput: ElementRef;
  @ViewChild('email') set emailContent(content: ElementRef) {
    this.emailInput = content;
  }
  @ViewChild('password') set passwordContent(content: ElementRef) {
    this.passwordInput = content;
  }

  // UI helpers
  public showLoginForm: boolean;
  public showBalance: boolean;
  public player: PlayerModel = new PlayerModel({});
  public balanceInfo: BalanceInfoModel = new BalanceInfoModel({});
  public nxcsBalanceInfo: NXCSBalanceInfoModel = new NXCSBalanceInfoModel({});
  public dialogType = DialogType;
  public customMessageError = '';

  // Store
  private headerState$: Observable<any>;
  private loginState$: Observable<any>;
  private playerState$: Observable<any>;
  private emailInput$: Observable<any>;
  private passwordInput$: Observable<any>;
  private balanceState$: Observable<any>;
  private headerSubscription: Subscription;
  private loginSubscription: Subscription;
  private playerSubscription: Subscription;
  private emailSubscription: Subscription;
  private passwordSubscription: Subscription;
  private balanceSubscription: Subscription;
  // tslint:disable-next-line:no-inferrable-types
  private leftMenu: string = '';
  // tslint:disable-next-line:no-inferrable-types
  private rightMenu: string = '';

  constructor(
    private authService: AuthService,
    private fb: FormBuilder,
    private store: Store<any>,
    private route: Router,
    private localStorageService: LocalStorageService,
    private playerService: PlayerService,
    private notificationService: NotificationService,
    private dialogService: DialogService,
    private helpers: HelpersService,
    private translateCode: TranslateCode,
        private promotionService: PromotionService,
    ) {
    this.loginForm = this.buildLoginForm();
  }

  ngOnInit() {
    this.setupStore();
  }

  ngAfterViewInit() {
    this.formEventsAfterViewInit();
  }

  ngOnDestroy() {
    this.headerSubscription.unsubscribe();
    this.loginSubscription.unsubscribe();
    this.playerSubscription.unsubscribe();
    this.notificationService.closeConnection();
  }

  public executeLogin() {
    if(!this.loginForm.valid) {
      this.customMessageError = this.translateCode.transform("EMPTY_INPUT_MESSAGE");
      return;
    }

    this.authService.login(new LoginModel({...this.loginForm.value, details: this.helpers.sendSessionData()}))
      .subscribe(
        data => {
          this.localStorageService.setUserAfterLogin(data.token);
          this.customMessageError = '';
          this.loginForm.reset();
          this.route.navigate(['/app/casino']);
        },
        error => {
          error.message.includes('Račun je zaključan') ? this.store.dispatch(new PopupNotification(error.message)) : this.customMessageError = error.message
          this.addAfterErrorSubscription();
        }
      );
  }

  public openDialog(dialogType: string): void {
    switch (dialogType) {
      case DialogType.PAYMENT:
         this.openWithdrawalDialog()
        break;
      case DialogType.PAYMENT_DEPOSIT:
          this.checkRegistrationStep();
      break;
      case DialogType.TRANSACTION_HISTORY:
        this.store.dispatch(new OpenDialog({
          type: dialogType,
        }));
      break;
    }
  }

  public openInternalTransactionsDialog(): void {
    this.promotionService.getPromotionsByLocation('NXCS_DEPOSIT')
      .subscribe(
                data => this.dialogService.openDialog(MENU_DIALOGS.INTERNAL_TRANSACTION, { promotions: data }),
        error => this.dialogService.openDialog(MENU_DIALOGS.INTERNAL_TRANSACTION, { promotions: []}),
      );
  }

  public backToRegistrationStep() : void {
    switch (this.player.registrationStep) {
      case 1 :  this.route.navigate(['/auth/registration/step-two']);
                break;
      case 2 : this.route.navigate(['/auth/registration/step-three']);
                break;
      case 3 : this.route.navigate(['/auth/registration/step-four']);
                break;
      case 4 : this.route.navigate(['/auth/registration/step-five']);
                break;
      case 5 : this.route.navigate(['/auth/registration/step-six']);
                break;
      default : this.route.navigate(['/login']);
                break;
    } 
  }

  public toggleMenu(dialog): void {
    if (dialog === 'left') {
      this.leftMenu = this.leftMenu === dialog ? '' : dialog;
    }
    if (dialog === 'right') {
      this.rightMenu = this.rightMenu === dialog ? '' : dialog;
    }
    this.dispatchShadow();
  }

  private openWithdrawalDialog(_data: any = {}): void {
    const playerRole = this.localStorageService.getPlayer()['profileRole'];

    if (playerRole  === 'WITHDRAWAL_DISABLED' && this.player.uploadedAdditionalInfo) {
      this.store.dispatch(new OpenNotification({ type: NotificationType.WITHDRAWAL_DISABLED }));
      return;
    }

    playerRole  === 'WITHDRAWAL_DISABLED' ?
    this.store.dispatch(new OpenNotification({type: NotificationType.MONEY_LAUNDERING})) :
    this.dialogService.openDialog(MENU_DIALOGS.WHITDRAWALS, _data);
  }

  private openProceedToRegistration(): void {
    this.store.dispatch(new OpenNotification ({type: NotificationType.PROCEED_REGISTRATION}))
  }

  private checkRegistrationStep(): void {
    if(this.player.registrationStep < 6) {
      this.openProceedToRegistration();
    } else {
      this.dialogService.openDialog(MENU_DIALOGS.DEPOSITS, {});
    }
  }

  private dispatchShadow(): void {
    if (this.leftMenu !== '') {
      this.store.dispatch(new OpenedLeftMenu());
      this.leftMenu = '';
    }
    if (this.rightMenu !== '') {
      this.store.dispatch(new OpenedRightMenu());
      this.rightMenu = '';
    }
  }

  private buildLoginForm(): FormGroup {
    return this.fb.group({
      email: [
        '', Validators.compose([Validators.required, Validators.min(5)]),
      ],
      password: [
        '', Validators.compose([Validators.required, Validators.min(5)])
      ],
    });
  }

  private loadBalance(): void {
    this.playerService.getPlayerBalance().toPromise()
      .then(data => this.store.dispatch(new SetPlayerBalance({balanceInfo: new BalanceInfoModel(data) })))
      .then(() => {
        if (this.player.externalId) {
          this.playerService.getNXCSPlayerBalance()
            .subscribe(
              data => this.store.dispatch(new SetPlayerNXCSBalance({ nxcsBalanceInfo: new NXCSBalanceInfoModel(data) })),
              error => console.log(error),
            );
        }
      });
  }

  // Store methods
  private setupStore(): void {
    this.headerState$ = this.store.pipe(select('headerStore'));
    this.loginState$ = this.store.pipe(select('loginStore'));
    this.playerState$ = this.store.pipe(select('playerStore'));
    this.balanceState$ = this.store.pipe(select('balanceStore'));
    this.addSubscriptions();
  }

  private formEventsAfterViewInit(): void {
    if (this.emailInput && this.passwordInput) {
      this.emailInput$ = fromEvent(this.emailInput.nativeElement, 'focus');
      this.passwordInput$ = fromEvent(this.passwordInput.nativeElement, 'focus');
      this.addFormEventsSubscriptions();
    }
  }

  private addFormEventsSubscriptions(): void {
      this.emailSubscription = this.emailInput$.subscribe(() => this.triggerEmailFocus());
      this.passwordSubscription = this.passwordInput$.subscribe(() => this.triggerPasswordFocus());
  }

  private triggerEmailFocus(): void {
    this.emailInput.nativeElement.select();
    if (this.emailSubscription) {
      this.emailSubscription.unsubscribe();
    }
  }

  private triggerPasswordFocus(): void {
    this.passwordInput.nativeElement.select();
    if (this.passwordSubscription) {
      this.passwordSubscription.unsubscribe();
    }
  }

  private addSubscriptions(): void {
    this.addHeaderSubscription();
    this.addLoginSubscription();
    this.addPlayerSubscription();
    this.setBalanceSubscription();
  }

  private addHeaderSubscription(): void {
    this.headerSubscription = this.headerState$
    .subscribe(headerState => this.showLoginForm = headerState !== HeaderActionTypes.LoginPage);
  }

  private addLoginSubscription(): void {
    this.loginSubscription = this.loginState$
    .subscribe(loginState => {
      if (loginState) {
        this.loadBalance();
        this.notificationService.connect(localStorage.getItem('token'));
      } else {
        this.notificationService.closeConnection();
      }
      this.showBalance = loginState;
      this.formEventsAfterViewInit();
    });
  }

  private addPlayerSubscription(): void {
    this.playerSubscription = this.playerState$
    .subscribe(playerData => this.player = playerData);
  }

  private addAfterErrorSubscription(): void {
    this.passwordSubscription = this.passwordInput$.subscribe(() => {
      if (this.customMessageError !== '') {
        this.customMessageError = '';
        this.passwordSubscription.unsubscribe();
      }
    });
  }

}
Sofyan Thayf
  • 1,228
  • 2
  • 10
  • 22
  • 1
    Happens also to me, yours isn't an isolated case. +1 – Cristian Traìna Oct 02 '19 at 12:20
  • 3
    Hello and welcome to stackoverflow ! It will be easier to help you if you provide some (simplified) code from your application. – Christophe Le Besnerais Oct 02 '19 at 12:20
  • 2
    Sounds a bit like the JS is still making calculations after rendering the form and is blocking UI until it stops. Are you fetching the autofill suggestions or something else that you have to wait on before the form can work? And hence, network delays can hinder rendering? – Shilly Oct 02 '19 at 12:20
  • Agree with @Shilly that it seems like the UI is locked, likely still processing some script. Use Chrome's dev tools to investigate. – jcruz Oct 02 '19 at 13:42
  • How is it possible to be locked only that 2 inputs, and all other things on page works normal? There is no script processing i checked. Something is weird with autofill from Chrome. On Mozzila , Safari and ME works all normal – Vladimir Jakovljevic Oct 02 '19 at 13:45
  • Yes, agree that it appears that something for the form is still processing and slowing up the form fields. As @Shilly asked, are you fetching any data when that component loads, anything that is a little heavier to process? Can you provide a bit more of the code around that component/page? – Drew Reese Oct 02 '19 at 14:46
  • No, I`m not fetching any data. That is header and login form, I don`t have any data to fetch. – Vladimir Jakovljevic Oct 03 '19 at 06:26
  • With the code we see and the information you have given us, we can only guess. So we'll need more info to be able to say anything meaningful. – Shilly Oct 03 '19 at 07:31
  • @shilly I added .ts file – Vladimir Jakovljevic Oct 03 '19 at 08:29
  • 12
    Oh damn, that is not how you are supposed to work with angular forms, there is so much that could go wrong here, the `@ViewChild` declaration, I'm not sure that one would even work. When you use `formControl` you don't need `@ViewChild()`. And you have way too many subscriptions, that creates a high risk of memory leaks and infinity loops that can easily freeze the UI. – Nerijus Pamedytis Oct 16 '19 at 16:55
  • Why do you want a ref for inputs when there are a couple of method to do that AFAI can guess @NerijusPamedytis seems to be right so the fix should be use the form group directly to get the value instead of using `@ViewChild` as a check you can do a console.log inside your setter at @ViewChild You'll see thousands of consoles which are freezing your page. You can wrap your code outside ngZone – Black Mamba Oct 18 '19 at 10:08
  • 2
    There is always simple way to find a bug in such cases. Create simple form without listeners or whatever. Check is bug present or not. If it is still present with pure html that means it is Chrome bug. If it appear after you add some of you listeners it means you have some problems with you listeners. – Arseniy-II Oct 23 '19 at 05:33
  • Does the following fix from [here](https://stackoverflow.com/a/57370688/2678218) work for you? – Cold Cerberus Oct 23 '19 at 07:51
  • what about your CSS file? did you add any CSS about inputs? and does this happen also in other browsers? and your js code is so messy it needs to get better that might be one of the reasons which causes your problem – Khashayar Pakkhesal Oct 23 '19 at 08:28
  • I saw something slide in from off-canvas in video. Do you have jQuery mMenu plugin on site? I had that strange behavior twice now where mMenu was responsible for locking the input fields. – Matej Svajger Oct 23 '19 at 10:56
  • Here is a solution for you problem https://stackoverflow.com/a/30976223/12050954 – Pablo Trindade Jul 10 '20 at 19:46
  • This is happening for me too. (Same scenario like VladimirJakovljevic login and logout) Username and Password fields get locked after autofill on chrome browser only. I dont find cursor on fields when i clicked but locked field releases only when i start typing any characters. Its been 8 months since VladimirJakovljevic posted here. I dont want disable autofill. any solution for this issue? – kva Aug 01 '20 at 11:49
  • You can use a decorator for auto field and check the value in a limit time multiple check this value/autofield value. – Md. Abu Sayed Nov 04 '20 at 05:48
  • If you are trying to disable it all together, this article has some useful info as to why your solution is not working: https://gist.github.com/niksumeiko/360164708c3b326bd1c8 – ttattini Dec 10 '20 at 00:08
  • OP, can you rephrase your title maybe? to potentially get better responses. The issue seems unrelated to chrome autocomplete, and more to your angular code. If you reference angular in the title or description, it might be found by folks with more experience on that framework. – Dvid Silva Mar 15 '21 at 15:29
  • 2021 and i get the same error... kinda off. After a form submit all input fields lock up. clicking on another tab or minimizing the browsers and then returning to the page all is good. only happens in Chrome and Edge, not in Firefox not in Opera – rudy Mar 20 '21 at 05:01

2 Answers2

0

Have you tried using the a href tag? I know it's an obvious thing, but sometimes we forget to do things like that. Also, you can use the a:hover tag in your CSS.

Apoorva Chikara
  • 2,534
  • 3
  • 11
  • 20
  • 3
    Welcome to Stack Overflow. Thank you for your response. But, it is more close to being a comment rather than being an answer. You may see here how to write a good answer. https://stackoverflow.com/help/how-to-answer – Ozgur Sar Nov 16 '20 at 17:51
0

This is an issue that happens every time Google Chrome autofills the fields when you permit it to save your login credentials on any form. It bugged me out the first times as well. I tried giving it a shot or two back when I encountered it for the first, but I gradually moved on and accepted it as a not-a-big deal kinda bug that every chrome user gotta have to deal with. So in conclusion, it's got nothing to do with your code. If you want to unfreeze the input fields, start typing something in them to change their value. I hope, this helps you and your nerves in accepting this browser-related behavior.