简体   繁体   中英

Angular interpolation lags rendering some values & how to remove one item from the array of typescript objects

I am working on an ASP.NET Core - Angular web app where I can choose a customer as the origin and find distance & duration to others using Google maps distance matrix service . I am getting the values fine ( I think console log proves that the lag is not because of google maps API calls/accessing values from an array of objects ) but when I am binding data to the template using angular interpolation, it lags to render the distance & duration values. Also to mention, the table only displays once the button is clicked - when isFindButtonClicked becomes true .

  1. Can you help me find the cause and fix it?

在此处输入图片说明

customers: Array<Customer> = [];
nearbyCustomers: Array<Customer> = [];

getCustomers() {
        this.customerService.getAll()
            .subscribe( result => {
                this.customers = result;
            }, error => {
                this.alertService.error(error._body);
                this.router.navigate(['/home']);
            });
}

ngOnInit() {
        this.getCustomers();
}

Typescript function to find and assign distance/duration values:

findNearbyCustomers(selectedId: number) {
    this.isFindButtonClicked = true;
    this.nearbyCustomers = this.customers;
    var origin = this.customers.find(c => c.id == selectedId);
    var originLatLng = origin.latitude.toString()+","+origin.longitude.toString();
    var service = new google.maps.DistanceMatrixService();

    for (let x = 0; x < this.customers.length; x++) {
            console.log(this.customers[x].id);
            var destinationLatLng = this.customers[x].latitude.toString()+","+this.customers[x].longitude.toString();

            service.getDistanceMatrix({
                origins: [originLatLng],
                destinations: [destinationLatLng],
                travelMode: google.maps.TravelMode.DRIVING
            }, (response, status) => {
                if (status.toString() == 'OK') {
                    console.log('Distance: '+response.rows[0].elements[0].distance.text+', Duration: '+response.rows[0].elements[0].duration.text);
                    this.nearbyCustomers[x].distance = response.rows[0].elements[0].distance.text;
                    this.nearbyCustomers[x].duration = response.rows[0].elements[0].duration.text;
                    console.log('DURATION: '+this.nearbyCustomers[x].duration+', DISTANCE:'+this.nearbyCustomers[x].distance);
                }
            })
    }
}

Partial markups from angular template:

<tbody>
       <tr *ngFor="let nearbyCustomer of nearbyCustomers">
            <td>{{ nearbyCustomer.businessName }}</td>
            <td>
                <p>{{ nearbyCustomer.streetNumber + ' ' + nearbyCustomer.streetName + ', ' + nearbyCustomer.suburb }}</p>
                <p>{{ nearbyCustomer.city + ' ' + nearbyCustomer.postCode + ', ' + nearbyCustomer.country }}</p>
            </td>
            <td>{{ nearbyCustomer.contactPerson }}</td>
            <td>{{ nearbyCustomer.contactNumber }}</td>
            <td>{{ nearbyCustomer.email }}</td>
            <td>{{ nearbyCustomer.distance }}</td>
            <td>{{ nearbyCustomer.duration }}</td>
      </tr>
 </tbody>
  1. Also Previously, I've tried with an if statement if (this.customers[x].id != this.selectedDeliveryDestinationId) and only pushed customers excluding the selected one (as origin) this.nearbyCustomers.push(this.customers[x]); and then when I tried to assign a value to object property & render it gave me Cannot set property 'distance' of undefined errors - seems I was messing with the index values. What should be the best way to exclude one item from the array for this purpose? Or, if I just can hide one specific row from HTML that would work as well.

Thanks.

You need ngZone in this case to update your table.

import { NgZone } from '@angular/core';

in constructor add: private _ngZone: NgZone then in your getDistanceMatrix success:

this._ngZone.run(() => {
                this.nearbyCustomers[x].distance = response.rows[0].elements[0].distance.text;
                    this.nearbyCustomers[x].duration = response.rows[0].elements[0].duration.text;
            });

About the second question I'll check it later and edit the answer

Thanks for your answers. NgZone helped with the change detection lagging issue. And for the second part of my question, here is how I fixed it (Not sure if this is the best solution but works fine for me)

I've filtered the customers and only assigned values except the selected one like this: this.nearbyCustomers = this.customers.filter(c => c.id != this.selectedDeliveryDestinationId); . This way, I only had to loop through the array of nearbyCustomers excluding the origin -saving one API call waste in each loop :-)

findNearbyCustomers() {
        this.isFindButtonClicked = true;
        this.nearbyCustomers = this.customers.filter(c => c.id != this.selectedDeliveryDestinationId);
        var origin = this.customers.find(c => c.id == this.selectedDeliveryDestinationId);
        var originLatLng = origin.latitude.toString()+","+origin.longitude.toString();
        var service = new google.maps.DistanceMatrixService();
        for (let x = 0; x < this.nearbyCustomers.length; x++) {
            var destinationLatLng = this.nearbyCustomers[x].latitude.toString()+","+this.nearbyCustomers[x].longitude.toString();        
            service.getDistanceMatrix({
                origins: [originLatLng],
                destinations: [destinationLatLng],
                travelMode: google.maps.TravelMode.DRIVING
            }, (response, status) => {
                if (status.toString() == 'OK') {
                    this._ngZone.run(() => {
                        this.nearbyCustomers[x].distance = response.rows[0].elements[0].distance.text;
                        this.nearbyCustomers[x].duration = response.rows[0].elements[0].duration.text;
                    })
                }
            })
        }
    }

I'd suggest to use a Pipe to filter the currently selected nearbyCustomer.

<tbody>
    <tr *ngFor="let nearbyCustomer of nearbyCustomers | nearbyCustomerFilter">
        <td>{{ nearbyCustomer.businessName }}</td>
        <td>
            <p>{{ nearbyCustomer.streetNumber + ' ' + nearbyCustomer.streetName + ', ' + nearbyCustomer.suburb }}</p>
            <p>{{ nearbyCustomer.city + ' ' + nearbyCustomer.postCode + ', ' + nearbyCustomer.country }}</p>
        </td>
        <td>{{ nearbyCustomer.contactPerson }}</td>
        <td>{{ nearbyCustomer.contactNumber }}</td>
        <td>{{ nearbyCustomer.email }}</td>
        <td>{{ nearbyCustomer.distance }}</td>
        <td>{{ nearbyCustomer.duration }}</td>
    </tr>
</tbody>

Create a Service which provides the information about the currently selected nearbyCustomer to the Pipe.

Then, whenever you choose another customer, your List gets updated an the Pipe kicks this particular entry out of the current view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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