Search code examples
javascriptmany-to-manyreduxredux-orm

Bootstrapping many to many relationships with redux-orm


I have aredux-orm models for Extent that look like:

const { string, number, arrayOf, oneOfType, instanceOf } = PropTypes

export default class Extent extends ValidatingModel {}

Extent.fields = {
  xmin: attr(),
  ymin: attr(),
  xmax: attr(),
  ymax: attr(),
  zoomlevel: attr(),
  tooltip: attr(),
  tooltipDelay: attr(),
  layers: many('Layer', 'extents'),
  users: fk('User', 'extents')
}

Extent.propTypes = {
  xmin: number,
  ymin: number,
  xmax: number,
  ymax: number,
  zoomlevel: number,
  tooltip: string,
  tooltipdelay: number,
  layers: oneOfType([
    arrayOf(number),
    arrayOf(
      instanceOf(Layer)
    )
  ])
}

Extent.modelName = 'Extent'

I have the related Layer model that is defined like this:

const {
  string,
  number,
  bool,
  any,
  oneOfType,
  instanceOf
} = PropTypes

export default class Layer extends ValidatingModel {}

Layer.fields = {
  objtype: fk('Bo', 'layers'),
  layertype: attr(),
  label: attr(),
  layertypevalue: attr(),
  geometrytype: attr(),
  opacity: attr(),
  token: attr(),
  url: attr(),
  readonly: attr(),
  isFetching: attr(),
  'default': fk('LayerConfiguration'),
  status: attr(),
  enabled: fk('LayerConfiguration', 'enabledLayers'),
  highlighted: fk('LayerConfiguration', 'highlightedLayers'),
  disabled: fk('LayerConfiguration', 'disabledLayers'),
  filtered: fk('LayerConfiguration', 'filteredLayers'),
  editing: fk('LayerConfiguration', 'editingLayers')
}

Layer.options = {
  idAttribute: 'layerId'
}

I bootstrap the data for them like this:

const victoriaExtent = Extent.create({
  xmin: 144.776008,
  ymin: -37.8458979,
  xmax: 145.101998,
  ymax: -37.6845001,
  zoom: 15,
  tooltip: 'Victoria',
  tooltipDelay: 0
})

const transformer = Layer.create({
  layerId: 1,
  label: 'Transformer',
  objtype: 'EQUI',
  layertype: 'PLANPLANT',
  layertypevalue: '0001',
  geometrytype: 'Point',
  opacity: 1,
  token: null,
  url: null,
  readonly: false,
  extents: [ victoriaExtent ],
  status: 'default',
  isFetching: false,
  'default': null,
  enabled: transformerEnabledConfig,
  highlighted: highlightPointConfig,
  disabled: transformerEnabledConfig,
  filtered: transformerEnabledConfig,
  editing: editingPointConfig
})

In the state, I find that the relationship is not populated despite it showing that there is a SessionBoundModel for extents in the Layer state. The ExtentsLayer relation model is not populated with the data.

Furthermore, when I access the extents, I find that the extent.layers property is undefined.


Solution

  • I do not understand why(yet) but I found that approaching the relationship from the other side ( which was how it was defined ) bore fruit. I changed the bootstrapping to look like:

    const victoriaExtent = Extent.create({
      xmin: 144.776008,
      ymin: -37.8458979,
      xmax: 145.101998,
      ymax: -37.6845001,
      zoom: 15,
      tooltip: 'Victoria',
      tooltipDelay: 0,
      user: spilli,
      layers: [
        transformer
      ]
    })
    

    With this way of definition when I use the following statement in my layers selector:

    const layers = layerGroup.layers.toModelArray().map(layer => {
          const obj2 = layer.ref
          let enabled = layer.enabled
          let extents
    
          if (enabled && enabled.icon) {
            const enabledRef = enabled.ref
            const icon = enabled.icon.ref
            enabled = Object.assign({}, enabledRef, { icon })
          }
    
          if (layer.extents) {
            extents = layer.extents.toRefArray()
          }
    
          return Object.assign({}, obj2, { enabled, extents })
        })