【问题标题】:Angular 12: ViewChild not working for ElementRef inside modalsAngular 12:ViewChild 不适用于模态中的 ElementRef
【发布时间】:2022-01-04 08:02:18
【问题描述】:

我有模式,我正在使用谷歌地图服务搜索位置。我收到TypeError: Cannot read properties of undefined (reading 'nativeElement')的错误

HTML

<input
                type="text"
                [ngClass]="{ error_border: submitted && f.location.errors }"
                class="form-control"
                formControlName="location"
                [readonly]="viewMode"
                (keydown.enter)="$event.preventDefault()" 
                placeholder="Search Location" 
                autocorrect="off" 
                autocapitalize="off" 
                spellcheck="off" 
                #search
              />

TS

    export class ListComponent implements OnInit, AfterViewInit {
        
            dbLocation:any;
              latitude!: number;
              longitude!: number;
              zoom!: number;
              address!: string;
              private geoCoder:any;
              searchFlag:boolean = false;
              @ViewChild('search' , { static: true }) public searchElementRef!: ElementRef ;
            ngOnInit(): void {
            }
              ngAfterViewInit() {
//----------autocomplete code block------------
                 //load Places Autocomplete
                 this.mapsAPILoader.load().then(() => {
                  // this.setCurrentLocation();
                   this.geoCoder = new google.maps.Geocoder;
             
                   let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
                   autocomplete.addListener("place_changed", () => {
                     this.ngZone.run(() => {
                       //get the place result
                       let place: google.maps.places.PlaceResult = autocomplete.getPlace();
             
                       //verify result
                       if (place.geometry === undefined || place.geometry === null) {
                         return;
                       }
             
                       //set latitude, longitude and zoom
                       this.latitude = place.geometry.location.lat();
                       this.longitude = place.geometry.location.lng();
                       this.getAddress(this.latitude, this.longitude);
                       this.zoom = 15;
                       this.searchFlag = true;
                     });
                   });
                 });
//----------autocomplete code block------------
                }
    }

我已尝试将 { static: true } 添加到 viewChild。还将自动完成代码块从 ngOnInit 移动到 ngAfterViewInit。还为自动完成代码块添加超时。但仍然报错。

如果输入字段不在ngOnInit 中的模态和自动完成代码块上,它不会给出错误。但是我有模态表单,其中有位置输入字段。出现错误。

我无法弄清楚哪种代码组合会起作用。我该如何解决这个错误?

请帮助和指导。

编辑 模态 HTML

<ng-template #formModal let-modal>
  <div class="modal-header">
    <h5 class="modal-title" id="modal-basic-title">
      Form
    </h5>
    <button
      type="button"
      class="close"
      aria-label="Close"
      (click)="modal.dismiss('Cross click')"
    >
      <span aria-hidden="true">
        <i class="fas fa-times"></i>
      </span>
    </button>
  </div>

  <div class="modal-body">
    <form [formGroup]="form">
      <div class="row edit_profile">
        <div class="col-sm-12">
          <div class="form-group">
            <label>Name<b style="color: red" *ngIf="!viewMode">*</b></label>
            <input
              type="text"
              [ngClass]="{ error_border: submitted && f.headline.errors }"
              formControlName="headline"
              class="form-control"
              [readonly]="viewMode"
            />
            <div *ngIf="submitted && f.headline.errors" class="text-danger">
              <div *ngIf="f.headline.errors.required">
                name is required
              </div>
            </div>
          </div>
        </div>
     

        <div class="col-sm-7">
          <div class="form-group">
            <label for="location">Location <b style="color: red" *ngIf="!viewMode">*</b></label>
            <div class="custome_input icons date_icon">
              <i class="fas fa-map-marker-alt"></i>
              <input
                type="text"
                [ngClass]="{ error_border: submitted && f.location.errors }"
                class="form-control"
                formControlName="location"
                [readonly]="viewMode"
                (keydown.enter)="$event.preventDefault()" 
                placeholder="Search Location" 
                autocorrect="off" 
                autocapitalize="off" 
                spellcheck="off" 
                #search
              />
            </div>
            <div *ngIf="submitted && f.location.errors" class="text-danger">
              <div *ngIf="f.location.errors.required">Location is required</div>
            </div>
          </div>
        </div>

      <div class="form-group btn-group mb-0" *ngIf="!viewMode">
        <button
          [disabled]="loading"
          class="btn"
          (click)="onSubmitForm()"
        >
          <span
            *ngIf="loading"
            class="spinner-border spinner-border-sm mr-1"
          ></span>
          Save
        </button>
      </div>
    </form>
  </div>
</ng-template>

开启模态的TS

 open(content) {
        
        this.listModalRef = this.modalService.open(content,{ size: 'lg', backdrop: 'static' });
        this.listModalRef.result.then((result) => {
          this.closeResult = `Closed with: ${result}`;
        }, (reason) => {
          this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
        });
        setTimeout(() => {
         //load Places Autocomplete
         this.mapsAPILoader.load().then(() => {
          // this.setCurrentLocation();
           this.geoCoder = new google.maps.Geocoder;
     
           let autocomplete = new google.maps.places.Autocomplete(this.searchElementRef.nativeElement);
           autocomplete.addListener("place_changed", () => {
             this.ngZone.run(() => {
               //get the place result
               let place: google.maps.places.PlaceResult = autocomplete.getPlace();
     
               //verify result
               if (place.geometry === undefined || place.geometry === null) {
                 return;
               }
     
               //set latitude, longitude and zoom
               this.latitude = place.geometry.location.lat();
               this.longitude = place.geometry.location.lng();
               this.getAddress(this.latitude, this.longitude);
               this.zoom = 15;
               this.searchFlag = true;
             });
           });
         });
        }, 0)
      }

【问题讨论】:

  • 在使用@ViewChild 时,只需添加一个小注释{ static: false} 是默认标志。
  • @Chaka15 更新问题。
  • 名称“搜索”可能已被使用,您是否尝试为该元素使用其他名称?
  • @TheFabio 是的,也尝试过更改名称。不工作
  • 你试过 searchElementRef!: ElementRef without !, as searchElementRef: ElementRef (and without static:true)?

标签: angular typescript google-maps viewchild googleplacesautocomplete


【解决方案1】:

首先,您应该删除{ static: true },否则searchElementRef 将始终未定义。

您需要做的下一个更改是将this.mapsAPILoader.load().then(() =&gt; { ... } 逻辑从ngAfterViewInit 移动到您确定模态已初始化的方法。如果您正在使用任何库组件(用于模态)并且它提供了一个事件(可能是 onShownshow 或其他)来识别模态初始化,那么您可以将您的逻辑放在那里。

简而言之,您需要确保在解决 this.mapsAPILoader.load() 承诺之前初始化模式,否则您将始终将 searchElementRef 视为未定义。

如果上述方法不起作用,那么您需要为您的模态创建一个单独的组件,而不是使用ng-template。可以参考this issue内的评论

【讨论】:

  • 我已经尝试过您的解决方案。在this.modalService.open(content,{ size: 'lg', backdrop: 'static' }); 代码之后的open 方法(打开模式)中添加了自动完成代码块仍然显示相同的错误:(
  • 也删除了静态true?如果 Google 地图已加载,load 将立即解析。您能否将在modalService.open 之后编写的自动完成代码块包装在setTimeout 中并进行测试。你也在使用 ngx-bootstrap modal 吗?
  • 设置 setTimeout1 后仍然无法正常工作。在问题中添加了TS of opening modal。我没有使用 ngx-bootstrap modal ,而是使用 NgbModal
  • @ganesh 您能否在stackblitz 中分享可重现的问题?我希望你也删除了{ static: true }
  • @ganesh 在模态中渲染后ng-template 的内容不会成为 ListComponent 视图的一部分,因此参考可能不可用。尝试为 Modal 创建一个单独的组件。也可以参考this
猜你喜欢
  • 2021-10-04
  • 2019-01-16
  • 2019-05-06
  • 1970-01-01
  • 2022-07-19
  • 1970-01-01
  • 2021-07-10
  • 2023-03-05
  • 2020-06-12
相关资源
最近更新 更多