简体   繁体   English

Angular 12:ViewChild 不适用于模态中的 ElementRef

[英]Angular 12: ViewChild not working for ElementRef inside modals

I have modal on which I am searching location using google map services.我有模式,我正在使用谷歌 map 服务搜索位置。 I am getting error of TypeError: Cannot read properties of undefined (reading 'nativeElement')我收到TypeError: Cannot read properties of undefined (reading 'nativeElement')

HTML 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 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------------
                }
    }

I have tried adding { static: true } to viewChild.我尝试将{ static: true }添加到 viewChild。 Also moving autocomplete code block from ngOnInit to ngAfterViewInit .还将自动完成代码块从ngOnInit移动到ngAfterViewInit Also adding timeout for autocomplete code block.还为自动完成代码块添加超时。 But still giving that error.但仍然给出那个错误。

It does not give error if input field is not on modal and autocomplete code block in ngOnInit .如果输入字段不在ngOnInit的模态和自动完成代码块上,它不会给出错误。 But I have form on modal in which I have that input field of location.但是我有模态表单,其中有位置输入字段。 There it is giving error.它在那里给出错误。

I am not able to figure it out which combination of code will work.我无法弄清楚哪种代码组合会起作用。 How can I resolve that error?我该如何解决该错误?

Please help and guide.请帮助和指导。

Edit modal HTML编辑模态 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 of opening modal打开模态的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)
      }

First, you should remove { static: true } , else searchElementRef will always be undefined.首先,您应该删除{ static: true } ,否则searchElementRef将始终未定义。

Next change you would need to do, is to move this.mapsAPILoader.load().then(() => {... } logic from ngAfterViewInit to a method wherein you are sure that the modal has been initialized. If you are using any library component (for modal) and if it provides an event (maybe onShown or show or whatever) to identify modal initialization, then you can put your logic there.您需要做的下一个更改是将this.mapsAPILoader.load().then(() => {... }逻辑从ngAfterViewInit到您确定模态已初始化的方法。如果您使用任何库组件(用于模态)并且如果它提供了一个事件(可能onShownshow或其他)来识别模态初始化,那么您可以将逻辑放在那里。

In short, you need to ensure that the modal is initialized before this.mapsAPILoader.load() promise is resolved, else you will always get searchElementRef as undefined.简而言之,您需要确保在this.mapsAPILoader.load() promise 解析之前初始化模态,否则您将始终将searchElementRef视为未定义。

put your code located inside your modal -> in a new component.将您的代码放在您的模态中-> 在一个新组件中。

In this new component you can use @ViewChild to get an element value or native html element.在这个新组件中,您可以使用 @ViewChild 获取元素值或原生 html 元素。 Access the native element in ngAfterViewInit() (of your new component).在 ngAfterViewInit() (您的新组件)中访问本机元素。 It won't be undefined.它不会是未定义的。

If you want to communicate with the parent component (component which holds the modal), use @Input/@Output, or use the ngrxStore (dispatch actions).如果您想与父组件(包含模态的组件)通信,请使用@Input/@Output,或使用ngrxStore(调度操作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM