离子输入值 [(ngModel)] 没有随着相对组件成员变量的变化而更新

Posted

技术标签:

【中文标题】离子输入值 [(ngModel)] 没有随着相对组件成员变量的变化而更新【英文标题】:ion-input value [(ngModel)] is not getting updated with relative component member variable change 【发布时间】:2018-07-29 08:34:54 【问题描述】:

我是新手,正在获得 Ionic 框架的经验。在使用 ionic 进行编码时,我遇到了下面给出的一个问题

离子页面/模板代码

<ion-item>
  <ion-label floating> addressLabel </ion-label>
  <ion-input name="address" id="addressField" type="text" required [(ngModel)]="address" #userAddress></ion-input>
</ion-item>
<div #locationMap id="locationMap"></div>

映射组件代码以更新标记放置时的地址值

onMarkerDrop(event) 
    let latcurr = event.latLng.lat();
    let longcurr = event.latLng.lng();
    this.initializeCurrent(latcurr, longcurr);
    let latLng = lat: event.latLng.lat(), lng: event.latLng.lng();
    let infoWindow = new google.maps.InfoWindow();
    infoWindow.open(this.map, this.marker);
    infoWindow.close();
  

  initializeCurrent(latcurr, longcurr) 
    this.currgeocoder = new google.maps.Geocoder();
    if (latcurr != '' && longcurr != '') 
        let myLatlng = new google.maps.LatLng(latcurr, longcurr);
        this.currgeocoder.geocode('location': myLatlng, (results, status) => 
          if (status == google.maps.GeocoderStatus.OK) 
              this.address = results[0].formatted_address; 

// From above I am getting new location address on marker drop but that new address is not getting reflected at address input box.

              console.log(this.address);
              setTimeout(() =>  
                this.userAddress.setFocus();
                this.keyboard.close();
              , 500);
           else 
              alert('Geocode was not successful for the following reason: ' + status);
          
      );
    
  

我没有明白我做错了什么。请引导我通过正确的方式。谢谢。

【问题讨论】:

您的控制台是否收到任何错误? 嗨@DavidR 不,我在控制台中没有收到任何错误,当我将新地址记录到控制台时,新地址正在登录到控制台中。 这里***.com/questions/42000337/… 【参考方案1】:

这是因为address 被传递给google.maps.Geocoder.prototype.geocode 的回调函数修改了。回调由 Angular 区域 outsidegeocode 方法异步分派。

Angular 使用 Angular 团队的一个副项目 zone.js 来确定跨函数调用的逻辑调用上下文,以尝试更有效地处理更改检测。通过跟踪当前 zone 一个框架特定的异步编程抽象,仅由 Angular 使用,框架减少了它需要在 95% 的快乐路径中重新渲染视图的次数。

在此上下文之外运行的代码不会触发视图更新。

这很痛苦。

要解决这个问题,您可能需要将代码包装在 Angular 区域中。这将使变更检测流经调用图。

这就是它的样子

import Component, NgZone from '@angular/core';

@Component(
  // boilerplate
)
export class MapComponent 
  constructor(readonly ngZone: NgZone) 

  initializeCurrent(latcurr, longcurr) 
    if (!latcurr || !longcurr) 
      return;
    
    
    this.currgeocoder = new google.maps.Geocoder();

    const latlng = new google.maps.LatLng(latcurr, longcurr);

    this.currgeocoder.geocode('location': latlng, ([formatted_address], status) => 
      if (status === google.maps.GeocoderStatus.OK) 
        // Create a zone right here.
        this.ngZone.run(() => 
          // changes will be detected because we are in a zone.
          this.address = formatted_address;
        );
        // The scope of a user-created zone should be as limited as possible.
        console.log(this.address);
        setTimeout(() => 
          this.userAddress.setFocus();
          this.keyboard.close();
        , 500);
       
      else 
        alert(`Geocode was not successful for the following reason: $status`);
      
    );
  

在遇到这种情况后,人们通常会开始将自己造成的各种不相关的错误归咎于区域周围的问题,而实际上它们是不相关的。

需要在上面创建显式区域的原因是框架与geocode 调用您提供的回调的机制或时间之间没有逻辑联系。

大多数时候,在编写良好的应用程序中接近 100% 时,区域会自动隐式传播,因为您的异步代码应该在 Promises 或 Observables 中。这些是框架知道的规范异步原语(它猴子修补它们以挂钩......)。 Angular 应用程序中总是有一个区域,但你通常并不关心。

要非常小心,仅当您知道需要时才故意使用区域。

如果你开始迷信地使用它们,你的应用程序会变慢,你将无法理解发生了什么,你的代码质量会急剧下降,你会发疯。

保守一点。

附录:

正如我所提到的,一个编写良好的应用程序不会经常使用显式区域,而是偏爱像 Promises 这样的标准 API 和像 Observables 这样的半标准 API。

虽然我倾向于 Promises,或者至少感觉就像我在 Angular 中所做的那样,因为大多数 Angular Observables 都应该是 Promises(XHR 任何人?),在这种情况下提高抽象级别的正确方法实际上是使用 Observables .

原因是回调被多次调用。

因此,我们实际上可以重写此代码,通过调整geocode API 来移除低级且经常容易出错的区域使用。

方法如下

import Component from '@angular/core';
import Rx from 'rxjs';
import tap from 'rxjs/operators';

@Component(
  // boilerplate
)
export class MapComponent 
  initializeCurrent(latcurr, longcurr) 
    if (!latcurr || !longcurr) 
      return;
    
    
    this.currgeocoder = new google.maps.Geocoder();

    const latlng = new google.maps.LatLng(latcurr, longcurr);
    
    const addressObservable = new Rx.Observable(observer => 
      this.currgeocoder.geocode('location': latlng, ([formatted_address], status) => 
        if (status === google.maps.GeocoderStatus.OK) 
          observer.next(formatted_address);
        
        else 
          observer.error(`Geocode was not successful for the following reason: $status`);
        
      );
    );

    addressObservable.pipe(tap(() => 
        setTimeout(() => 
          this.userAddress.setFocus();
          this.keyboard.close();
        , 500);
      ))
      .subscribe(address => 
          this.address = address;
      );
  

值得注意的是代码变得多么简单。当 observables 用于表示异步信息时,它们可以非常优雅。毕竟,它们的设计代表了什么。当它们用于表示奇异,甚至可能是同步值,或同步流时,阻抗不匹配的程度令人作呕。

框架设计师,甚至更多的规范推动者,应该听取 Rx 的创造者 Erik Meijer 的意见,并使用正确的工具来完成正确的工作,而不是通过推动 Observables 来给 Observables 一个坏名声(双关语)打算?)在代表数字1之类的任务中。 现在他们故意无视他,并像 Reactive Streams 规范一样制造绝对垃圾。

但是 Observables 在它们被设计为令人惊叹的方面令人惊叹。

临别时:

我这么说是因为我真的希望讨厌我刚刚写的 Rx 版本。

Angular,围绕 Reactive Streams 规范的可笑炒作,以及提出将技术标准化为 javascript 的方式(即 “它必须允许同步观察,因为它必须能够替换所有库和控制结构”),让我讨厌 Rx,让我不想将它用于任何事情,这是一件可悲的事情。

【讨论】:

嗨,Aluan Haddad,我会介意您对 ngZone 的评价。但是我尝试了您的答案,但仍然无法正常工作。 您好 Aluan Haddad,很抱歉您的回答有效。之前我在网络浏览器中测试过它。但之后我构建了apk文件并在android手机中对其进行了测试。它正在工作。 天啊。我只花了大约 30 分钟来验证它确实有效:D stackblitz.com/edit/ionic-yepmry。我忘记了加载地图时 API 有多么脆弱,以及我多么讨厌 nativeElement 的东西。无论如何,很高兴它对你有用! 嗨@Aluan Haddad,感谢您提供替代解决方案。

以上是关于离子输入值 [(ngModel)] 没有随着相对组件成员变量的变化而更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在离子选择上获得多个值

如何在离子无线电元件上使用 ngModel?

NG0303:无法绑定到“ngModel”,因为它不是“离子范围”的已知属性

添加离子成分

有没有办法将语音中的“文本”保存为文本离子语音识别

离子输入隐藏在键盘下方 - ionic 2