Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/450.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Angular8跟踪未正确更新_Javascript_Angular_Typescript_Agm Map - Fatal编程技术网

Javascript Angular8跟踪未正确更新

Javascript Angular8跟踪未正确更新,javascript,angular,typescript,agm-map,Javascript,Angular,Typescript,Agm Map,首先是一点背景知识。我正在开发一个应用程序,它使用agm地图实时显示多个用户的位置。我最近一直在努力提高性能,因为可以有数千个用户,每个用户代表一个地图标记或dom元素。我已经将父组件和子组件都更改为使用onpush策略,子组件使用ngFor循环渲染地图标记,我还将trackBy添加到此循环。位置更新通过信号器接收,对象已正确更新,但即使在运行更改检测后,标记位置也未在地图上正确更新 以下两个组件是简化版本,有助于识别问题 首先是父映射组件 @Component({ sel

首先是一点背景知识。我正在开发一个应用程序,它使用agm地图实时显示多个用户的位置。我最近一直在努力提高性能,因为可以有数千个用户,每个用户代表一个地图标记或dom元素。我已经将父组件和子组件都更改为使用onpush策略,子组件使用ngFor循环渲染地图标记,我还将trackBy添加到此循环。位置更新通过信号器接收,对象已正确更新,但即使在运行更改检测后,标记位置也未在地图上正确更新

以下两个组件是简化版本,有助于识别问题

首先是父映射组件

     @Component({
      selector: 'app-map',
      template: '<agm-map>
                    <app-map-markers #mapMarkers [users]="users"></app-map-markers>
                </agm-map>',
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class MapComponent implements OnInit, OnDestroy {
        users: MapUser[];

        private handleLocationUpdate(updatedUser: any) {
           const user = this.users.find(this.findIndexToUpdate, updatedUser.Id);

           if (user !== null && user !== undefined) {
              user.lat = updatedUser.Lat;
              user.lng = updatedUser.Lng;
              user.lastSeen = updatedUser.LastSeen;

              const userIndex = this.handledUsers.indexOf(user);
              this.handledUsers[userIndex] = user;
           }
        }

        findIndexToUpdate(newItem) {
           return newItem.id === this;
        }
    }
users数组是通过将子缓存到http服务来填充的,但由于工作正常,我忽略了这一点。当接收到位置更新时,它由父级处理,我留下函数来显示这一点,但该函数再次通过订阅信号服务来调用

现在是地图标记组件

 @Component({
  selector: 'app-map-markers',
  template: '<agm-marker *ngFor="let user of users; let i = index; trackBy: trackByUser"  [latitude]="user.lat" [longitude]="user.lng" [title]="user.firstName">
             </agm-marker>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MapMarkersComponent {
    @Input() users: MapUser[];

    constructor() {}

    public trackByUser(indx: number, value: MapUser) {
        let identifier: string = indx.toString();

        if ('lat' in value && 'lng' in value) {
          identifier = identifier.concat(value.lastSeen.toString());
        }

        return identifier;
      }
}

我怀疑问题在于,由于onpush没有检测到更改,但是出于性能原因,onpush似乎是这种情况下的最佳策略。我只需要更新元素,而不是重新绘制整个用户列表。但是,也许我还是个新手,所以我有点不对劲。感谢您提供的帮助或建议。

尝试调用更改检测“markForCheck”,这将使您能够在下一个周期中运行更改检测

@Component({
  selector: 'app-map-markers',
  template: '<agm-marker *ngFor="let user of users; let i = index; trackBy: trackByUser"  [latitude]="user.lat" [longitude]="user.lng" [title]="user.firstName">
             </agm-marker>',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MapMarkersComponent {
    public users: MapUser[]
    @Input() 
    set users(values: any[]){
      this.users = values;
      this.cdr.markForCheck();
    }

    constructor(private cdr: changeDetectorRef) {}

    public trackByUser(indx: number, value: MapUser) {
        let identifier: string = indx.toString();

        if ('lat' in value && 'lng' in value) {
          identifier = identifier.concat(value.lastSeen.toString());
        }

        return identifier;
      }
}

在角度上,传递数组作为输入指向同一实例。尝试使用Array.slice或JSON.parseJSON.Stringify创建。@SureshKumarAriya谢谢,我会尝试一下。但这不会导致整个标记重新绘制吗?或者trackby会停止吗?我们可以使用markforCheck手动触发CD。将更新answer@Tony_89用户数组应该有一个新的引用,以确保OnPush正常工作。trackBy将负责不重新提交同一用户。它将确保刷新相同的DOM元素数据。请试一试。