【问题标题】:One of Angular Route is not working in Angular Prod BuildAngular Route 之一在 Angular Prod Build 中不起作用
【发布时间】:2020-01-03 07:07:26
【问题描述】:

我们有一个应用程序,其中导航到特定路线在开发服务中按预期工作。但是,当我构建和部署到 prod 时,它没有按预期工作,浏览器卡住并且无法关闭或更改任何内容。它正在进入挂起模式。

我还在 ngOnInit 代码函数调用中保留了 console.logs,它们执行良好,但浏览器挂起。

下面是我的组件代码:

import { Component, OnInit, ViewChild, OnDestroy, AfterViewInit } from '@angular/core';
import { FormGroup, NgForm, NgModel } from '@angular/forms';
import { SelectionModel } from '@angular/cdk/collections';
import { MatTableDataSource, MatCheckboxChange, MatPaginator, MatSort } from '@angular/material';
import { select } from '@angular-redux/store';
import { Observable, Subscription } from 'rxjs';
import { IReportMasters, ITestCode, ICandidateCredentials } from '../api/reports.interface';
import { IRequirementCode } from 'src/app/registration/api/registration.interface';
import { ReportsService } from '../api/reports.service';
import { trigger, transition, useAnimation } from '@angular/animations';
import { bounce } from 'ng-animate';
import { SnackbarService } from 'src/app/material/snackbar.service';
import { MatProgressButtonOptions } from 'mat-progress-buttons';
import { GlobalMessages } from 'src/app/globals/global.messages';
import globalConst from 'src/app/globals/global.const';
import { GlobalService } from 'src/app/services/global.service';
@Component({
  selector: 'app-cadidate-credentials',
  templateUrl: './cadidate-credentials.component.html',
  styleUrls: ['./cadidate-credentials.component.scss'],
  animations: [trigger('bounce', [transition('* => *', useAnimation(bounce))])]
})
export class CadidateCredentialsComponent implements OnInit, OnDestroy, AfterViewInit {
  @ViewChild('ccForm', { static: false }) ccForm: NgForm;
  bounce: any;
  today = new Date();
  birthdayMax = globalConst.birthdayMax;
  @select(['reports', 'masters']) masters$: Observable<IReportMasters>;
  @select(['reports', 'reqCodeYear']) reqCodeYear$: Observable<IReportMasters>;
  @select(['reports', 'candidateCredentials', 'masters', 'reqCodes']) reqCodes$: Observable<
    IRequirementCode[]
  >;
  @select(['reports', 'candidateCredentials', 'candidates']) candidates$: Observable<
    ICandidateCredentials[]
  >;
  @select(['reports', 'candidateCredentials', 'masters', 'tests']) tests$: Observable<ITestCode[]>;
  dataSource: MatTableDataSource<ICandidateCredentials> = new MatTableDataSource([]);
  displayedColumns: string[] = ['Candidate_Name', 'Login_user_Id', 'Password', 'isActive'];
  private paginator: MatPaginator;
  private sort: MatSort;
  searching: boolean;
  subs: Subscription[] = [];
  @ViewChild(MatSort, { static: false }) set matSort(ms: MatSort) {
    this.sort = ms;
    this.setDataSourceAttributes();
  }

  @ViewChild(MatPaginator, { static: false }) set matPaginator(mp: MatPaginator) {
    this.paginator = mp;
    this.setDataSourceAttributes();
  }
  @ViewChild('reqCodeV', { static: false }) reqCodeV: NgModel;
  selection = new SelectionModel<ICandidateCredentials>(true, []);
  formGroup: FormGroup;
  locations = [];
  years = [];
  months = [];
  submitting: boolean;
  // candidatesToActivate: ICandidateCredentials[] = [];

  constructor(
    private _reportsService: ReportsService,
    private _globalService: GlobalService,
    private _snackbarService: SnackbarService // private dispatcher: Dispatcher
  ) {}

  ngOnInit() {
    this.setUpLoadingReset();
    this.loadCandidates();
  }
  ngOnDestroy() {
    this.subs.forEach(sub => sub.unsubscribe());
  }
  ngAfterViewInit(): void {
    console.log('TCL: ngAfterViewInit');
    this.ccForm.valueChanges.subscribe(value => {
      this.searching = false;
    });
  }
  setUpLoadingReset() {
    console.log('TCL: setUpLoadingReset -> setUpLoadingReset');
    this.subs[this.subs.length] = this._globalService.globalLoadingReset$.subscribe(state => {
      console.log('TCL: ngOnInit -> state', state);
      this.searching = false;
      this.submitting = false;
    });
  }
  loadCandidates() {
    console.log('TCL: loadCandidates -> loadCandidates');
    this.subs[this.subs.length] = this.candidates$.subscribe(data => {
      console.log('TCL: loadCandidates -> this.candidates$.subscribe => data', data);
      this.searching = false;
      if (data.length) {
        this.dataSource = new MatTableDataSource<ICandidateCredentials>(data);
        this.selection = new SelectionModel<ICandidateCredentials>(
          true,
          this.dataSource.data.filter(item => item.isActive)
        );
      }
    });
  }
  /** Whether the number of selected elements matches the total number of rows. */
  isAllSelected() {
    const numSelected = this.selection.selected.length;
    const numRows = this.dataSource.data.length;
    return numSelected === numRows;
  }

  /** Selects all rows if they are not all selected; otherwise clear selection. */
  masterToggle() {
    this.isAllSelected()
      ? this.dataSource.data.forEach(row => {
          if (!row.isActive) {
            this.selection.toggle(row);
          }
        })
      : this.dataSource.data.forEach(row => this.selection.select(row));
  }

  /** The label for the checkbox on the passed row */
  checkboxLabel(row?: ICandidateCredentials): string {
    if (!row) {
      return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
    }
    return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${row.Candidate_Name}`;
  }

  reqCodeYearChanged(year, dependentControls: NgModel[]) {
    if (year) {
      this._reportsService.getReqCodesByYear(year);
    }
    dependentControls.forEach(control => control.reset());
  }

  reqCodeChanged(reqcode, dependentControls: NgModel[]) {
    this._reportsService.getTestByReqCode(reqcode);
    dependentControls.forEach(control => control.reset());
  }
  searchCandidateCredentials(ccForm: NgForm) {
    if (ccForm.valid) {
      this.searching = true;
      let sub: Subscription = this._reportsService.getCandidateCredentials(ccForm.value);
    }
  }
  resetForm(ccForm: NgForm) {
    ccForm.resetForm();
    ccForm.controls.IsRetake.setValue(false);
  }
  changedSelection(event: MatCheckboxChange, row: ICandidateCredentials) {
    event ? this.selection.toggle(row) : null;
  }
  setDataSourceAttributes() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }
  activateSelected(test) {
    if (this.countToActivate) {
      let candidates = this.selection.selected
        .filter(item => {
          return !item.isActive;
        })
        .map(item => {
          item.isActive = true;
          return item;
        });
      this.submitting = true;
      this.subs[this.subs.length] = this._reportsService
        .saveCandidateCredentials(candidates, test)
        .subscribe(
          data => {
            this.submitting = false;
            this._snackbarService.success(`Activated ${candidates.length} candidate(s).`);
          },
          err => {
            this._snackbarService.error(GlobalMessages.Reports.CANDIDATE_ACTIVATE_ERROR);
            this.submitting = false;
            candidates.forEach(item => {
              item.isActive = false;
            });
          }
        );
    } else {
      this._snackbarService.info('Please select atlease one candidate to activate.');
    }
  }
  get countToActivate() {
    return this.selection.selected.filter(item => {
      return !item.isActive;
    }).length;
  }

  get activateButtonOptions(): MatProgressButtonOptions {
    return {
      active: this.submitting,
      text: this.submitting ? 'Saving Data...' : 'Activate',
      buttonColor: 'accent',
      barColor: 'primary',
      raised: true,
      stroked: false,
      mode: 'indeterminate',
      value: 0,
      disabled: false,
      fullWidth: false,
      buttonIcon: {
        fontIcon: 'save'
      }
    };
  }
  get searchButtonOptions(): MatProgressButtonOptions {
    return {
      active: this.searching,
      text: this.searching ? 'Searching ...' : 'Search',
      buttonColor: 'primary',
      barColor: 'accent',
      raised: true,
      stroked: false,
      mode: 'indeterminate',
      value: 0,
      disabled: false,
      fullWidth: false,
      buttonIcon: {
        fontIcon: 'search'
      }
    };
  }
  resetValue(item: NgModel) {
    console.log('TCL: resetValue -> item', item);
    item.reset();
  }
}

更新 1:Prod 中的 Console.log 屏幕截图

Update2:预期结果低于 dev ng serve

【问题讨论】:

  • 错误是什么?
  • 你能展示你的控制台吗?可能是拼写错误。在部署之前在您的代码中尝试 tslint
  • 在边缘浏览器中显示长时间运行的脚本并提示我停止脚本。
  • 我认为与路由无关。在 setUpLoadingReset() 中设置调试点。为什么'console.log('TCL: ngOnInit -> state', state)' 没有日志检查你的网络选项卡,你是否得到响应
  • 好像和动画有关,可以分享一下你用的动画sn-p吗?

标签: angular


【解决方案1】:

您的组件已初始化(调用 ngOnInit)但从未进入 AfterViewInit 看起来很可疑。因此,在我看来,您的模板中或 OnInit 之后的某些内容(如 ViewChild 代码或动画)是错误的。

如果路由导致页面崩溃,这将是一个无限循环并尝试多次导航,但永远不会真正进入组件。为了证明这一点,您可以使用 enableTracing 选项启用路由器日志记录:

RouterModule.forRoot(routes, { enableTracing: true }) 

【讨论】:

  • 我做到了,并且没有发生这种无限重定向。我怀疑某些 JavaScript 正在无限期地执行,并且阻止 UI 渲染无法找到它是什么。我使用了 mat-progress-buttons npm 包中的 mat-bar-button。不确定它是否导致问题。
  • 好吧,这已经很好了,没有路线问题。为了更好地定位你的真正问题,你可以更深入地调试你的 JavaScript,调试从你的模板调用的所有部分(console.logs 也可以提供很大的帮助),如果没有帮助,把每一个可疑的东西都扔掉部分代码(和模板)
猜你喜欢
  • 2021-07-07
  • 1970-01-01
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
  • 2019-02-28
  • 2014-07-14
  • 2017-01-30
  • 1970-01-01
相关资源
最近更新 更多