Ticket #57 (closed defect: fixed)

Opened 4 years ago

Last modified 4 years ago

LayerStore and bound Map get out of sync when record is replaced through add()

Reported by: sbenthall Assigned to:
Priority: major Milestone: 0.5
Component: GeoExt.data.LayerStore Version:
Keywords: Cc:
State: Commit

Description

If you have a LayerStore with a record with some id, and you add another record with the same id, then:

  • the new record replaces the old record in the store's data collection
  • but the map does not remove the layer associated with the old record on the map.

The result is that in this case, the LayerStore and its bound Map get out of sync, which screws up things that depend on it.

A way to fix this is to listen for the data collection's *replace* event, and remove the replaced record's layer then.

Patch following shortly.

Attachments

57.patch (2.8 kB) - added by sbenthall on 05/01/09 21:21:13.
patch with regression test
57.2.patch (2.3 kB) - added by sbenthall on 05/01/09 21:22:18.
patch with regression test, without cruft
57.alternate.patch (1.7 kB) - added by sbenthall on 05/02/09 00:20:19.
alternative solution (no docs or tests)
57.3.patch (2.7 kB) - added by sbenthall on 05/06/09 20:54:54.
now with removeMapLayer method
57.4.patch (3.1 kB) - added by tschaub on 05/14/09 20:03:25.
remove layer on record replace

Change History

05/01/09 21:21:13 changed by sbenthall

  • attachment 57.patch added.

patch with regression test

05/01/09 21:22:18 changed by sbenthall

  • attachment 57.2.patch added.

patch with regression test, without cruft

05/01/09 21:23:11 changed by sbenthall

  • state changed from None to Review.

Sorry about the first bad patch. 57.2.patch is the one.

05/01/09 21:46:44 changed by tschaub

The same layer can not be added to the map twice. Two records with different layers should not have the same id. So, I think this is a problem in record.copy.

05/01/09 22:24:02 changed by tschaub

I've created #58 for the copy issue.

I still think there is something that could be done here with the replace listener. Here are my thoughts on this patch:

  • I think it is sort of sketchy to call remove in the replace listener for data. Without digging through the code, it is not obvious that this is safe to do. The tests show it works, but they could change the sequence of things so that this breaks without breaking the api (I know this is a common problem we face).
  • You could create a removeMapLayer method and have shared code between the onRemove listener and your onReplace listener. (The onRemove method does not actually need to call record.get("layer") twice there.) So the onReplace listener would call removeMapLayer instead of remove.

If #58 seems like a suitable fix, this could also wait (and the tests will need to be tweaked).

(follow-up: ↓ 5 ) 05/01/09 22:38:12 changed by sbenthall

I agree that the fact that the same layer gets added twice is weird. record.copy just calls the record constructor with the same data collection (the MixedCollection that is the record's data property) as the copied record, so as far as I can tell the layer object isn't getting duplicated or changed. Maybe there's a problem in the OpenLayers catch on duplicate layers?

But in any case, this problem is more general that just dealing with a copied record where the layer is the same. Records get replaced whenever a new one with the same id is added. But records could have the same id and not have the same layer property.

For example, this could happen:

  • a record R gets inserted into the LayerStore
  • that recorded is copied to be R' and is inserted into a different store.
  • R'.id == R.id at this point.
  • Somebody edits R' to have a different layer.
  • Somebody adds R' to the first LayerStore.

In this case R would get replaced by R'. The layer of R' would get added to the map, but the layer associated with R would not get removed.

An alternative way I considered writing this was to write in a *beforeadd* event into the LayerStore, and then provide a handler that could check to see if the record would be replaced and do something appropriate in that case. That would work at a higher level and so wouldn't respond to an event on the data collection. Do you think that would be less sketchy?

Otherwise, i agree that sharing some removeMapLayer method between onRemove and onReplace would reduce the sketchiness and be a bit cleaner.

(in reply to: ↑ 4 ) 05/01/09 22:55:02 changed by tschaub

Replying to sbenthall:

I agree that the fact that the same layer gets added twice is weird. record.copy just calls the record constructor with the same data collection (the MixedCollection that is the record's data property) as the copied record, so as far as I can tell the layer object isn't getting duplicated or changed. Maybe there's a problem in the OpenLayers catch on duplicate layers?

Ok, I think some miscommunication. I don't think it is weird that the copied layer gets added to the map. That I expect.

What I wouldn't expect is that the result of record.copy() would replace record when added to a store.

05/01/09 23:01:04 changed by sbenthall

Thanks for clearing that up, and reminding me that the layer gets cloned on copy, which I hadn't realized when I wrote that.

05/02/09 00:20:19 changed by sbenthall

  • attachment 57.alternate.patch added.

alternative solution (no docs or tests)

05/02/09 00:23:57 changed by sbenthall

57.alternate.patch is another possible solution to this problem that I mentioned above. It doesn't include docs or tests, but if it's a better strategy than 57.2.patch than I'll be happy to fill it out.

Rather than using the non-API data property, it adds a *beforeadd* event to the LayerStore, and then listens for it. If a record with the same layer id as and existing record is added, then the previous record is removed before it is replaced.

Pros:

  • LayerStore gets a *beforeadd* method that could be handy.
  • doesn't use non-API methods or propertys?

Cons:

  • Not sure if what I did to get the superclass and extend the add() method was kosher.
  • I think it's more cumbersome than the 57.2.patch solution.

Thoughts?

05/06/09 20:54:54 changed by sbenthall

  • attachment 57.3.patch added.

now with removeMapLayer method

05/06/09 20:55:52 changed by sbenthall

57.3.patch is a new version of 57.patch against current trunk with passing tests and a removeMapLayer method as per tschaub's request.

05/14/09 20:03:25 changed by tschaub

  • attachment 57.4.patch added.

remove layer on record replace

05/14/09 20:04:51 changed by tschaub

  • state changed from Review to Commit.

Thanks for the patch Seb. This looks good to go. I tweaked the tests to be future proof (for when copy does not clone layer #58). If you agree with the changes, please commit.

05/14/09 22:51:14 changed by sbenthall

  • status changed from new to closed.
  • resolution set to fixed.

(In [745]) Prevents LayerStore and Map from getting out of sync when a record is replaced. Thanks to tschaub for future-proofing tests. r=tschaub (closes #57)