Skip to content

Conversation

crisbeto
Copy link
Member

@crisbeto crisbeto commented Nov 5, 2020

Currently the various Google Maps sub-components are set up so that each input has a setter, a BehaviorSubject and a method to watch it for changes. This doesn't scale very well on components with lots of inputs so these changes use an alternate one where we synchronously update the marker state whenever an input changes.

Note: This PR is meant to be a proof-of-concept so that we can discuss the approach. If we agree that it's the way forward, it can be applied to the other map components.

@crisbeto crisbeto added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent target: patch This PR is targeted for the next patch release labels Nov 5, 2020
@crisbeto crisbeto requested a review from a team as a code owner November 5, 2020 20:27
@google-cla google-cla bot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Nov 5, 2020
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this approach looks good to me

* Options used to configure the marker.
* See: developers.google.com/maps/documentation/javascript/reference/marker#MarkerOptions
*/
@Input() options: google.maps.MarkerOptions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@Input() options: google.maps.MarkerOptions;
@Input() options: Readonly<google.maps.MarkerOptions>;

We could enforce that the whole object needs to be set

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, this might break some users who are using this incorrectly (or just not carefully) though.

@jelbourn jelbourn requested a review from mbehrlich November 6, 2020 21:19
@crisbeto
Copy link
Member Author

The setters have been re-added. @mbehrlich, can you take another look?

this._assertInitialized();
this.marker.setTitle(title);
if (marker) {
marker.setOptions(this._combineOptions());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to use the "changes" object in ngOnChanges to prevent these methods from running if their particular input has not changed. The reason is that we don't necessarily want to re-set all of the options when we're changing one particular input. Imagine a situation where the developer sets an initial set of options for a marker. Then the user drags the marker across the map. Then they trigger a change to the title. This way of doing it will set all of the initial inputs that have not been updated yet, including the initial position, causing the marker to return to its original position.

If we use the changes object to see what input is actually being changed, we can just run that setter method and avoid this problem (similar to how I originally watched for various changes instead of running setOptions for every change).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about that, but my assumption was that the Google Maps API would know not to update the map if the values haven't changed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that's correct, but in the situation I outlined, it would appear that the values had changed to the internal Marker class. Basically, if we initialize a marker with these options:

  [position]="{lat: 23, lng: 10}"
  [title]="'new marker'"
  [draggable]="true"

Since draggable is true, users can drag the marker anywhere they want. This will update the position on the internal marker, but it won't mutate the object that the develop input. So, let's say they drag it to {lat: 16, lng: -2}.

Then, let's say a user clicks on something that triggers an update to the title. This code will call setOptions with

{
  position: {lat: 23, lng: 10},
  title: 'updated title',
  draggable: true,
}

This snaps the marker out of the spot the user dragged it to, even though we would it expect to only update the title.

By relying on the "changes" object, we can check what input is actually being changed and then just run the appropriate setter, in this case "setTitle" which will update the title and not change the position.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Changing...

Currently the various Google Maps sub-components are set up so that each
input has a setter, a `BehaviorSubject` and a method to watch it for changes.
This doesn't scale very well on components with lots of inputs so these changes
use an alternate one where we synchronously update the marker state whenever
an input changes.
Copy link
Member

@josephperrott josephperrott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM for dev-infra

@crisbeto crisbeto added the action: merge The PR is ready for merge by the caretaker label Nov 12, 2020
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wagnermaciel wagnermaciel merged commit 0e88125 into angular:master Nov 17, 2020
wagnermaciel pushed a commit that referenced this pull request Nov 17, 2020
Currently the various Google Maps sub-components are set up so that each
input has a setter, a `BehaviorSubject` and a method to watch it for changes.
This doesn't scale very well on components with lots of inputs so these changes
use an alternate one where we synchronously update the marker state whenever
an input changes.

(cherry picked from commit 0e88125)
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants