🏠 back to Observable

Modifying a Class instance - OpenLayers map.addInteraction()


#1

Hello, I’m new to Observable and I believe that this question relates to some foundational understanding of how Observable treats class instances and their modification across cells.

I am working with this notebook: Geo Data Explorer 2.0

I am trying to add a Box Select interaction to my map instance.
The implementation looks like this, accross 3 cells:

Select = ol5.interaction.Select   //ref library function
select = new Select()             //create new instance of this interaction
map.addInteraction(select)        //apply it to my map

I created a smaller demonstration where I define a class and try to update an instance of it: Class Modification Test Cross Cells

In both cases when I try instance.update(updateValue) the cell returns undefined

Could anyone point me in the right direction or is there documentation that describes what I’m doing wrong?

Thanks!


#2

The update method doesn’t return anything, so undefined is what you should expect from that cell.

To check that update did what it was supposed to, note that if you click on the Object in the output of the data cell (to refresh its display), the url has turned into www.myExample.com. You can also create a new cell containing just data.url, and you’ll see that it also displays www.myExample.com.

Indeed, the second-to-last cell shows

The current dataset is “example” @< www.myExample.com>.

which is further evidence that the url field has been changed.


#3

Thanks bgchen, this makes total sense!

So ‘undefined’ is not necessarily cause for concern. Though I am probably still missing something to do with when a cell is reevaluated. I’ll keep exploring this in the Class Modification Test Cross Cells notebook.

Unfortunately this does not seem to be the source of my Box Select problems in OpenLayers which leaves me a bit stumped…

The console error when attempting the drag select (Ctrl+Drag) is pretty opaque to me:
TypeError: this.condition_ is not a function


#4

Have you read How Observable Runs?

If you reach into a value returned by another cell and modify it, it doesn’t typically trigger re-evaluation of any referencing cells. In general, you should try to avoid side-effects (mutation) like this, and instead treat cell values as immutable.

So instead of a cell that defines something, and another cell that modifies it…

myObj = ({key1: "whatever", key2: "whatever else"})
myObj.key1 = "Something"

You’d just define the value you want once, from the beginning:

myObj = ({key1: "Something", key2: "whatever else"})

If you want a value to be controlled interactively, then it’s generally best to define that object as a view:

For example, if you want to let the user choose because those two keys, you could say something like this:

viewof key1 = html`<select>
  <option>whatever
  <option>Something
</select>`
myObj = ({key1, key2: "whatever else"})

Now whenever the user changes the selected option in the key1 drop-down menu, it triggers a re-evaluation of myObj, and anything referencing myObj (or key1) will be automatically re-evaluated. But the important point is that myObj is not being mutated by key1—a new value is generated automatically when key1 changes, and key1 doesn’t know anything about who references it.

There are use cases for mutation across cells (as you found with Views Are Mutable Values, and Introduction to Mutable State). But in general I would caution against reaching for mutable state. Yes, it’s probably what you’re familiar with coming from JavaScript, but usually you can avoid it, and by avoiding or at least minimizing it you end up with simpler code that is easier to understand.


#5

Here’s an updated OpenLayers minimal example:

And here’s an example that uses the Select interaction, exposing the selected features as an array:

And here’s box selection:


#6

Thanks for the break down, and the OpenLayers examples!. :beers: