首页 > 解决方案 > 在 NgOnInit 和 NgAfterViewInit 上执行的链接任务

问题描述

伙计们,我真的很想正确处理 Angular 生命周期钩子。我不确定我在哪里弄错了。我试图阅读很多东西,并且从大约一个星期以来一直在努力解决它们。

我的问题

我有相当多的服务器 api 调用和一些我在NgOnInIt()期间应用的业务逻辑。但是这样做我有时会遇到RegisterationComponent.html:82 ERROR TypeError: Cannot read property 'titleId' of undefined. 在其他时候,我正在努力正确初始化向导。

我现在要详细定义你我所面临的是什么:

ngOnInit()

ngOnInit() {
    //First see if it is a redirect request:
    this.route.queryParamMap
    .pipe(
      map(params => params.get('payment')),
      filter(paramVal => paramVal != null),
      filter(paramVal => paramVal == 'success'),
      tap((paymentInd: string) => {
        this.setOrderDetails();
      }),
      untilDestroyed(this)
    ).subscribe((successPayment: string) => {
      //Update the transaction here

      this.regService.updateTransaction(this.registrationTransactionDetails)
      .pipe(
        filter((regUpdate: RegistrationTransaction) => regUpdate != null),
        tap((regUpdate: RegistrationTransaction) => {
          //This is so that user sees the correct template.
          this.showRegConfirmation = true;
          this.showConfirmation = false;
          
          this.wizard = new KTWizard(this.el.nativeElement, {
            startStep: 2
          });

          this.initializeWizardEvents();

          JsBarcode('#barcode', regUpdate.order.orderLine.barcode);
        }),
        untilDestroyed(this)
      )
      .subscribe((regUpdate: RegistrationTransaction) => {
        //Update the user details
        
        this._profileService.updateUser(this.userDetails.id, this.userDetails).subscribe();
      });
    });

    //fresh transaction case
    this.route.queryParamMap
    .pipe(
      map(params => params.get('payment')),
      filter(param => param == null),
      tap((paymentInd: string) => {
        this.setOrderDetails();

        //this is to make sure user sees the correct template even after refresh
        this.showConfirmation = true;
        this.showRegConfirmation = false;
      }),
      filter(id => this.registrationTransactionDetails.id == null),
      untilDestroyed(this)
    )
    .subscribe((paymentInd: string) => {
      this.regService
        .createTransaction(this.registrationTransactionDetails)
        .pipe(
          filter(regCreated => regCreated.id != null),
          tap((regCreated: RegistrationTransaction) => {
            if(!this._utilities.isNullOrUndefined(regCreated.id)){

              this.wizard = new KTWizard(this.el.nativeElement, {
                startStep: 1
              });

              this.initializeWizardEvents();

              
                                            
              this.regService
              .getSessionDetails(regCreated.eventId, regCreated.order.id)
              .pipe(
                tap((response: SessionResponse) => {
                  //Just so that we can update the registration details with the gateway order id as well.
                  this.registrationTransactionDetails = JSON.parse(this.storage.getItem(Constants.RegistrationStorageKey));
                  this.registrationTransactionDetails.gatewayOrderId = response.gatewayOrderId;

                  this.storage.setItem(Constants.RegistrationStorageKey, JSON.stringify(this.registrationTransactionDetails));

                }),
                untilDestroyed(this)
                )
              .subscribe((response: SessionResponse) => {
                console.log(response);

                this.gatewayConfig.session = response.session;
                this.gatewayConfig.callbacks = this.callback;

                Checkout.configure(this.gatewayConfig);
              });
            }
          }),
          untilDestroyed(this)
          )
        .subscribe((regCreated: RegistrationTransaction) => {
          
          this.registrationTransactionDetails = JSON.parse(this.storage.getItem(Constants.RegistrationStorageKey));
          
          //Save all the details fo the registration created.
          this.registrationTransactionDetails.id = regCreated.id;
          this.registrationTransactionDetails.order.id = regCreated.order.id;
          this.registrationTransactionDetails.order.orderLine.id = regCreated.order.orderLine.id;

          this.storage.setItem(
            Constants.RegistrationStorageKey,
            JSON.stringify(this.registrationTransactionDetails)
          );
        });     
    });

    this.regService
      .getCommonValues()
      .pipe(
        filter(list => list != null),
        tap((list: CommonLists) =>{
          this.filteredCities = _.filter(list.cities, { countryCode: this.userDetails.countryCode });
        }),
        untilDestroyed(this)
        )
      .subscribe((lists: CommonLists) => {
        this.countries = lists.countries;
        this.titles = lists.titles;
        this.genders = lists.genders;
        this.cities = lists.cities;
        this.jobFunctions = lists.jobFunctions;
        this.jobTitles = lists.jobTitles;
      });

  }

ngAfterViewInit()

ngAfterViewInit(): void {
    // Initialize form wizard
    //let wizard;
    
    if(this.showRegConfirmation && !this.showConfirmation)
    {
      this.wizard = new KTWizard(this.el.nativeElement, {
        startStep: 3
      });
    }
    else
    {
      this.wizard = new KTWizard(this.el.nativeElement, {
        startStep: 2
      });
    }
    

    // Validation before going to next page
    this.wizard.on('beforeNext', wizardObj => {
      // https://angular.io/guide/forms
      // https://angular.io/guide/form-validation
      // validate the form and use below function to stop the wizard's step
      // wizardObj.stop();
      this.onBeforeNext(wizardObj);
    });

    this.wizard.on('beforePrev', wizardObj => {
      // https://angular.io/guide/forms
      // https://angular.io/guide/form-validation
      // validate the form and use below function to stop the wizard's step
      // wizardObj.stop();
      this.onBeforePrev(wizardObj);
    });

    // Change event
    this.wizard.on('change', wizard => {
      setTimeout(() => {
        KTUtil.scrollTop();
      }, 500);
    });
  }

现在这个向导必须在 ngAfterViewInit 中初始化。我曾尝试在 ngOnInit 中执行此操作,但它不起作用。事件不起作用。

主要是你们在 queryParamsMap 订阅中看到的行是我尝试实现我想要实现的目标。我想根据状态用户登陆屏幕从不同的步骤启动向导。

this.wizard = new KTWizard(this.el.nativeElement, {
                startStep: 2
              });
    
              this.initializeWizardEvents();

此外,你们都可以找到这一行: this.setOrderDetails()<- 它在 ngOnInit 期间获取用户详细信息。它在 ngOnInit 之后运行,因此我在上面粘贴的运行时未定义标题错误期间遇到一些初始化错误。当数据到来时,它会填满 UI,但我不太明白如何解决这个错误。

RegistrationComponent.html 部分抛出错误

<!--begin: Form Wizard Step 2-->
          <div class="kt-wizard-v3__content" data-ktwizard-type="step-content" data-ktwizard-state="current">
            <div class="kt-form__section kt-form__section--first">
              <!-- <ng-template #loggedIn> -->
              <div class="kt-wizard-v3__form">
                <div class="wizard-title-area">
                  <p class="para">
                    <span class="name">Hi {{ userDetails.firstName }}, </span>You have logged in using your social
                    account. <a href="#">Click here</a> if this is not the correct information.
                  </p>
                </div>
                <div class="kt-separator kt-separator--border-2x separator-margin-top-0"></div>
                <form #userForm="ngForm">
                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-2">
                        <div class="form-group">
                          <mat-form-field>
                            <mat-select
                              id="prefix"
                              name="prefix"
                              placeholder="prefix"
                              [(ngModel)]="userDetails.titleId"
                              name="userTitle"
                              id="userTitle"
                              required
                            >
                              <mat-option *ngFor="let title of titles" [value]="title.id">{{
                                title.description
                              }}</mat-option>
                            </mat-select>
                          </mat-form-field>
                          <!-- <div
                            *ngIf="userTitle.invalid && (userTitle.dirty || userTitle.touched)"
                            class="alert alert-danger"
                          >
                            <div *ngIf="userTitle.errors.required">
                              Please select a Title
                            </div>
                          </div> -->
                        </div>
                      </div>
                      <div class="col-sm-4">
                        <div class="form-group">
                          <mat-form-field>
                            <input
                              matInput
                              #input
                              maxlength="20"
                              placeholder="First Name"
                              required
                              [(ngModel)]="userDetails.firstName"
                              [ngModelOptions]="{ standalone: true }"
                            />
                          </mat-form-field>
                        </div>
                      </div>
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <input
                              matInput
                              #input
                              maxlength="20"
                              placeholder="Last Name"
                              required
                              [(ngModel)]="userDetails.lastName"
                              [ngModelOptions]="{ standalone: true }"
                            />
                          </mat-form-field>
                        </div>
                      </div>
                    </div>
                  </div>
                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <input
                              matInput
                              type="email"
                              #input
                              maxlength="20"
                              placeholder="email"
                              required
                              [(ngModel)]="userDetails.email"
                              [ngModelOptions]="{ standalone: true }"
                            />
                          </mat-form-field>
                        </div>
                      </div>
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <mat-select
                              id="gender"
                              name="gender"
                              placeholder="gender"
                              [(ngModel)]="userDetails.genderId"
                              aria-required="true"
                              [ngModelOptions]="{ standalone: true }"
                            >
                              <mat-option *ngFor="let gender of genders" [value]="gender.id">{{
                                gender.alias
                              }}</mat-option>
                            </mat-select>
                          </mat-form-field>
                        </div>
                      </div>
                    </div>
                  </div>

                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                              <mat-label>Select your nationality</mat-label>

                            <mat-select
                              placeholder="nationality"
                              [(ngModel)]="userDetails.nationalityCode"
                              [ngModelOptions]="{ standalone: true }"
                            >
                              <mat-option *ngFor="let country of countries" [value]="country.code">{{
                                country.name
                              }}</mat-option>
                            </mat-select>
                          </mat-form-field>
                        </div>
                      </div>
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                              <mat-label>Select the country of residence</mat-label>
                            <mat-select
                              placeholder="country"
                              [(ngModel)]="userDetails.countryCode"
                              [ngModelOptions]="{ standalone: true }"
                              (selectionChange)="onCountryChange()"
                            >
                              <mat-option *ngFor="let country of countries" [value]="country.code">{{
                                country.name
                              }}</mat-option>
                            </mat-select>
                          </mat-form-field>
                        </div>
                      </div>
                    </div>
                  </div>

                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <mat-label>Select a job function</mat-label>
                            <mat-select
                              matInput
                              id="userJobFunction"
                              name="userJobFunction"
                              placeholder="job function"
                              [(ngModel)]="userDetails.jobFunctionId"
                              required
                              #userJobFunction="ngModel"
                            >
                              <mat-option *ngFor="let function of jobFunctions" [value]="function.id">{{
                                function.name
                              }}</mat-option>
                            </mat-select>
      
                            <mat-error *ngIf="userJobFunction.hasError('required')">
                                Please select a job function.
                            </mat-error>
      
                          </mat-form-field>
                        </div>
                      </div>
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <mat-label>Select a job title</mat-label>
                            <mat-select
                              matInput
                              id="userJobTitle"
                              name="userJobTitle"
                              placeholder="job title"
                              [(ngModel)]="userDetails.jobTitleId"
                              required
                              #userJobTitle="ngModel"
                            >
                              <mat-option *ngFor="let jobTitle of jobTitles" [value]="jobTitle.id">{{
                                jobTitle.name
                              }}</mat-option>
                            </mat-select>
                            <mat-error *ngIf="userJobTitle.hasError('required')">
                                Please select a job title.
                            </mat-error>
                          </mat-form-field>
                        </div>
                      </div>
                    </div>
                  </div>


                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <input
                              matInput
                              type="text"
                              #input
                              maxlength="20"
                              placeholder="phone"
                              required
                              [(ngModel)]="userDetails.mobile"
                              [ngModelOptions]="{ standalone: true }"
                            />
                          </mat-form-field>
                        </div>
                      </div>
                      
                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <mat-label>Select a city</mat-label>
                            <mat-select
                              matInput
                              id="userCity"
                              name="userCity"
                              placeholder="city"
                              [(ngModel)]="userDetails.city"
                              required
                              #userCity="ngModel"
                            >
                              <mat-option *ngFor="let city of filteredCities" [value]="city.id">
                                {{ city.name }}
                              </mat-option>
                            </mat-select>
      
                            <mat-error *ngIf="userCity.hasError('required')">
                                Please select a city.
                              </mat-error>
      
                          </mat-form-field>
                        </div>
                      </div>

                    </div>
                  </div>

                  <div class="form-input-wrap">
                    <div class="row">
                      <div class="col-sm-6">
                        <div class="form-group">

                          <mat-form-field>
                            <input matInput [matDatepicker]="userDOB" [max]="maxDate" id="userDOB" name="userDOB" placeholder="Date of Birth" [(ngModel)]="userDetails.userDOB"
                            [ngModelOptions]="{ standalone: true }">
                            <mat-datepicker-toggle matSuffix [for]="userDOB"></mat-datepicker-toggle>
                            <mat-datepicker #userDOB disabled="false"></mat-datepicker>
                          </mat-form-field>
                        </div>
                      </div>

                      <div class="col-sm-6">
                        <div class="form-group">
                          <mat-form-field>
                            <input
                              matInput
                              type="text"
                              #input
                              maxlength="20"
                              placeholder="company"
                              [(ngModel)]="registrationTransactionDetails.companyName"
                              [ngModelOptions]="{ standalone: true }"
                            />
                          </mat-form-field>
                        </div>
                      </div>
                    </div>
                  </div>                  
                </form>
              </div>
              <!-- </ng-template> -->
            </div>
          </div>
          <!--end: Form Wizard Step 2-->

任何帮助将不胜感激。谢谢!

标签: javascriptangulartypescriptangular8

解决方案


看起来像一个错误的定义变量,在你的模板RegisterationComponent.html88中,你应该有类似的东西variable.titleId,你的 .ts 文件中的变量应该像这样定义:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class YourComponentName {
  variable;
}

问题是,当你的组件被加载时,变量是未定义的,所以你应该像一个空对象一样定义,variable: typing = {}这样 html 组件就会得到undefined一个错误,如果你的组件指定了一些不同的东西,undefined你应该定义你的变量variable = {titleId: expectedValue}


推荐阅读