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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MatthieuGomes opened this issue Jun 8, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@MatthieuGomes
Copy link

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>
@MatthieuGomes MatthieuGomes added the bug Something isn't working label Jun 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant