Google Maps: cómo actualizar los marcadores

Tengo un observable que emite una lista de propiedades. Según la propiedad latitud longitud, estoy representando marcadores HTML personalizados utilizando superposiciones de mapas de Google.

La primera vez que se carga el mapa, los marcadores y los grupos se representan correctamente. A partir de la segunda vez intento quitar los marcadores anteriores y colocar los nuevos. En este punto, los marcadores antiguos no se eliminan (ya he agregado un método de eliminación) y se agregan nuevos marcadores. Además, el clúster no se muestra desde la segunda vez.

Pregunta: ¿Cómo actualizar los marcadores en los mapas de Google?

html-mapa-marcador.ts

export const createHTMLMapMarker = ({
    OverlayView = google.maps.OverlayView,
    ...args
}) => {
    class HTMLMapMarker extends google.maps.OverlayView {
        private label!: string;
        private marker!: HTMLElement | null;
        private latlng!: google.maps.LatLng;

        constructor() {
            super();
            this.latlng = args['latlng'];
            this.label = args['label'];
            this.setMap(args['map']);
        }

        public createDiv() {
            this.marker = document.createElement('div') as HTMLElement;
            this.marker.classList.add('custom-marker-box');

            if (this.label && this.marker !== null) {
                const markerInnerEl = document.createElement('div');
                markerInnerEl.classList.add('custom-marker');
                const markerInnerTextEl = document.createElement('span');
                markerInnerTextEl.innerText = this.label;
                markerInnerEl.appendChild(markerInnerTextEl);
                this.marker.appendChild(markerInnerEl);
                this.marker.style.cssText = `position: absolute; cursor: pointer;`;

                /**
                 * !Stops click or tap on the element from bubbling up to the map.
                 * !Use this to prevent the map from triggering "click" events.
                 */
                google.maps.OverlayView.preventMapHitsFrom(this.marker);
            }

            google.maps.event.addDomListener(
                this.marker,
                'click',
                (event: MouseEvent) => {
                    const targetEl = event.target as HTMLElement;
                    const ClickedMarkerEl =
                        targetEl.tagName.toLocaleLowerCase() === 'span'
                            ? targetEl.parentNode
                            : targetEl;

                    const markers =
                        document.querySelectorAll('.custom-marker-box');

                    markers.forEach((markerParent) => {
                        const markerEl = markerParent
                            .children[0] as HTMLElement;

                        if (markerEl === ClickedMarkerEl) {
                            if (
                                !markerEl.classList.contains(
                                    'custom-marker-active'
                                )
                            ) {
                                markerEl.classList.add('custom-marker-active');
                            }
                        } else {
                            markerEl.classList.remove('custom-marker-active');
                        }
                    });
                    google.maps.event.trigger(this, 'click');
                }
            );
        }

        public appendDivToOverlay() {
            const panes = this.getPanes() as google.maps.MapPanes;
            panes.floatPane.appendChild(this.marker as HTMLElement);
        }

        public positionDiv() {
            const point = this.getProjection().fromLatLngToDivPixel(
                this.latlng
            );
            if (point) {
                const markerWidth = (
                    this.marker as HTMLElement
                ).getBoundingClientRect().width;
                const marginAmount = (markerWidth / 2).toFixed();

                (this.marker as HTMLElement).style.left = `${point.x}px`;
                (this.marker as HTMLElement).style.top = `${point.y}px`;
                (
                    this.marker as HTMLElement
                ).style.marginLeft = `-${marginAmount}px`;
            }
        }

        public override draw() {
            if (!this.marker) {
                this.createDiv();
                this.appendDivToOverlay();
            }
            this.positionDiv();
        }

        public remove() {
            if (this.marker) {
                this.marker.parentNode?.removeChild(this.marker);
                this.marker = null;
            }
        }

        public getPosition() {
            return this.latlng;
        }

        public getDraggable() {
            return false;
        }
    }
    return new HTMLMapMarker();
};

google-map.component.ts

    private markers: any[] = [];
    private initialZoom!: boolean;
    private googleMap!: google.maps.Map;
    private properties: IProperty[] = [];
        
    ngOnInit(): void {
       this.initMap();
       this.getLocations();
    }
        
    initMap() {
            const mapEl = document.getElementById('map') as HTMLElement;
            const mapOptions = {
                minZoom: 6,
                zoom: 10,
                disableDefaultUI: true
            };
            this.googleMap = new google.maps.Map(mapEl, mapOptions);
            this.initialZoom = true;
   }
        
   getLocations() {
            this.locationsSource$.subscribe({
                next: (properties: IProperty[]) => {
                    this.properties = properties;
                    this.resetMapMarkers();
                    this.setMapMarkers();
                }
            })
    }
        
setMapMarkers() {
            const bounds = new google.maps.LatLngBounds();
            const infowindow = new google.maps.InfoWindow();
    
            this.markers = this.properties.map((property) => {
                const location = property.location;
                const propertyPrice = property.prices;
                const currencySymbol = getCurrenySymbol(propertyPrice.currency);
    
                const marker = createHTMLMapMarker({
                    latlng: new google.maps.LatLng(
                        Number(location.lattitude),
                        Number(location.longitude)
                    ),
                    map: this.googleMap,
                    label: `${currencySymbol}${propertyPrice.fee_value}`
                });
    
                bounds.extend(marker.getPosition());
    
                /**
                 * *Showing info window on click marker
                 */
                google.maps.event.addListener(marker, 'click', (event: Event) => {
                    const infoContent = createHTMLInfoWindow(property);
                    infowindow.setContent(infoContent);
                    infowindow.setOptions({
                        zIndex: 90
                    });
                    infowindow.open({
                        anchor: marker,
                        map: this.googleMap,
                        shouldFocus: true
                    });
                });
        
                return marker;
            });
    
            /**
             * *Adding marker cluster
             */
            const markerCluster = new MarkerClusterer(this.googleMap, this.markers, {
                zoomOnClick: true,
                maxZoom: 10,
                gridSize: 20,
                styles: [
                    {
                        width: 35,
                        height: 35,
                        anchorIcon: [35, 35],
                        backgroundPosition: '0 0',
                        className: 'custom-clustericon'
                    }
                ]
            });
    
            /**
             * *fitbounds happens asynchronously,
             * *have to wait for a bounds_changed event before setting zoom
             */
            google.maps.event.addListener(
                this.googleMap,
                'bounds_changed',
                (event: Event) => {
                    const mapZoom = this.googleMap.getZoom();
                    if (mapZoom && mapZoom > 15 && this.initialZoom) {
                        this.googleMap.setZoom(10);
                        this.initialZoom = false;
                    }
                }
            );
    
            this.googleMap.fitBounds(bounds);

}
    
resetMapMarkers() {
      for (var i = 0; i < this.markers.length; i++) {
           this.markers[i].setMap(null);
      }
      this.markers = [];
}
Answer