Skip to content

"[Vue3-OpenLayers Error] OlInteractionModify: Modify interactions needs either a source or features to work. Please provide either the props 'source' or 'feature' or use the component with an '<OlSourceVector>' component." #432

@MatthieuGomes

Description

@MatthieuGomes

Describe the bug
"[Vue3-OpenLayers Error] OlInteractionModify: Modify interactions needs either a source or features to work. Please provide either the props 'source' or 'feature' or use the component with an '' component."

While using inside or outside .

However, recent test showed me that, if I wait for the features to be loaded with a v-if on the interaction layer and specifying the source, fixes it... But as soon as don't specify source, same error.

Affected version(s)

To Reproduce
Place a in a without specifying any source nor features, or outside even when specifying source.

Expected behavior
No errors.

Desktop (please complete the following information):

  • OS: Alpine (docker) hosted by Arch
  • Browser: Chromium & Firefox

Additional context
Here's the code used :

OpenLayersMap.vue

<template>
  <OlMap ref="mapRef" tabindex="0" id="map" @singleclick="mapClicked" @keydown.escape="clickedPosition = [NaN, NaN]">
    <OlView :center="center" :zoom="zoom" :maxZoom="props.maxZoom" projection="EPSG:4326" />
    <OlTileLayer>
      <OlSourceXyz url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
    </OlTileLayer>
    <OlVectorLayer :zIndex="2">
      <OlSourceVector ref="vectorSourceRef">
        <MapMarker v-for="marker in markerList" :position="marker.position" :marker-id="marker.markerId"
          :scale="marker.scale" :key="marker.markerId" />
        <OlInteractionModify v-if="markerLoaded" :source="vectorSource" />
      </OlSourceVector>

    </OlVectorLayer>

    <AdditionPopup v-if="!isNaN(clickedPosition[0]) && !isNaN(clickedPosition[1])"
      :clicked-position="clickedPosition" />
    <!-- <OlInteractionPointer @drag="isMarkerClicked" /> -->
  </OlMap>
</template>

<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
import AdditionPopup from './PopUps/AdditionPopup.vue';
import MapMarker from './MapMarker.vue';
// import store from '@/store';
import eventListener from '@/technicals/eventBus';
// import OlInteractionModify from 'vue3-openlayers';


// props
const props = defineProps({
  startPosition: {
    type: Array,
    default: () => [51.505, -0.09] // Default to London coordinates
  },
  startZoom: {
    type: Number,
    default: () => 13
  },
  maxZoom: {
    type: Number,
    default: () => 19
  }
});
// data
//// Template refs
const mapRef = ref("mapRef");
const vectorSourceRef = ref('vectorSourceRef');
//// Data properties
const markerLoaded = ref(false);
const center = ref(props.startPosition);
const zoom = ref(props.startZoom)
const markerList = ref([
  {
    position: [center.value[0], center.value[1]],
    markerId: 'marker1',
    scale: 2
  },
  {
    position: [center.value[0] + 0.002, center.value[1] + 0.0003],
    markerId: 'marker2'
  }
]);
const clickedPosition = ref([NaN, NaN]);

// computed
const map = computed(() => mapRef.value ? mapRef.value.map : null);
const vectorSource = computed(() => vectorSourceRef.value ? vectorSourceRef.value.source : null);
const features = computed(() => vectorSource.value ? vectorSource.value.getFeatures() : []);
// lifecycle hooks
onMounted(() => {
  console.log("Map mounted:", map.value);

  eventListener.$on('closePopup', popupClosed);
  eventListener.$on('addMarker', addMarker);

  markerLoaded.value = true;

  console.log("vectorSource:", vectorSourceRef.value.source);
  console.log("vectorSource:", vectorSourceRef.value.source.getFeatures());
});

onUnmounted(() => {
  eventListener.$off('closePopup');
});

// methods
function popupClosed() {
  clickedPosition.value = [NaN, NaN];
}

function mapClicked(event) {
  console.log("Map clicked at:", event.coordinate);
  console.log("features on map:", vectorSource.value.getFeatures());
  const hasFeature = map.value.hasFeatureAtPixel(event.pixel);
  if (hasFeature) {
    map.value.forEachFeatureAtPixel(event.pixel, (feature) => {
      feature.dispatchEvent('click');
    });
  } else {
    // If no feature is clicked, we set the clicked position
    clickedPosition.value = event.coordinate;
  }
}
//
function isMarkerClicked(event) {
  const hasFeature = map.value.hasFeatureAtPixel(event.pixel);
  console.log("Has feature at pixel:", hasFeature);
}

function addMarker() {
  console.log("Adding marker at position:", clickedPosition.value);
}
</script>

<style scoped>
#map {
  height: 100dvh;
  flex: 1;
  z-index: 0;
}
</style>

MapMarker.vue

<template>
  <ol-feature ref="markerRef">
    <ol-geom-point :coordinates="props.position"></ol-geom-point>
    <ol-style>
      <ol-style-icon :src="props.icon" :scale="props.scale"></ol-style-icon>
    </ol-style>
  </ol-feature>
</template>

<script setup>
import { defineProps, onMounted, onUnmounted } from 'vue';
import eventListener from '@/technicals/eventBus';
import { ref, computed } from 'vue';

// props
const props = defineProps({
  position: {
    type: Array,
    default: () => [0, 0]
  },
  icon: {
    type: String,
    default: 'https://openlayers.org/en/latest/examples/data/icon.png'
  },
  scale: {
    type: Number,
    default: 1
  },
  actionRadius: {
    type: Number,
    default: NaN
  },
  isDraggable: {
    type: Boolean,
    default: true
  },
  markerId: {
    type: String,
    default: ''
  }
});
// data
const markerRef = ref(null);
const marker = computed(() => markerRef.value ? markerRef.value.feature : null);
// computed
const visiblePosition = ref([NaN, NaN])
// lifecycle hooks
onMounted(() => {
  console.log("Marker mounted:", props.markerId, props.position);
  visiblePosition.value = props.position;
  eventListener.$on('markerClicked', markerClicked);
  marker.value.on('click', () => console.log("Marker clicked ?", props.markerId));
  marker.value.on('pointerdrag', (event) => {
    console.log("Marker move start:", props.markerId, event);
  });
})

onUnmounted(() => {

  eventListener.$off('markerClicked');
})
// methods
function markerClicked(event) {
  // console.log("Marker,", marker.value)
  // console.log("Marker Ref:", markerRef.value);
  // console.log("Marker clicked event:", event);
  // console.log("Marker clicked:", props.markerId)
}


</script>

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions