diff --git a/aleksis/apps/chronos/frontend/components/LessonEventLinkIterator.vue b/aleksis/apps/chronos/frontend/components/LessonEventLinkIterator.vue
index a6a737298d496c3a8b7acdcd7fe4d485c77cace2..2a53a497772191544df5cd65a8c2f14cde897c1a 100644
--- a/aleksis/apps/chronos/frontend/components/LessonEventLinkIterator.vue
+++ b/aleksis/apps/chronos/frontend/components/LessonEventLinkIterator.vue
@@ -11,6 +11,18 @@ export default {
       required: false,
       default: "name",
     },
+    alternativeAttr: {
+      type: String,
+      required: false,
+      default: null,
+    },
+  },
+  methods: {
+    getAttr(item) {
+      let val = item[this.attr];
+      if (val) return val;
+      return this.alternativeAttr ? item[this.alternativeAttr] : val;
+    },
   },
 };
 </script>
@@ -19,7 +31,7 @@ export default {
   <span v-bind="$attrs">
     <span v-for="(item, idx) in items" :key="idx">
       <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
-      {{ item[attr] }}{{ idx + 1 < items.length ? "," : "" }}
+      {{ getAttr(item) }}{{ idx + 1 < items.length ? "," : "" }}
     </span>
   </span>
 </template>
diff --git a/aleksis/apps/chronos/frontend/components/Substitutions.vue b/aleksis/apps/chronos/frontend/components/Substitutions.vue
index 5482c40f0a875562c2f837db105f788abd9fc038..0dafca35aed4a2f49770a54ffdca15ffe83fcfa1 100644
--- a/aleksis/apps/chronos/frontend/components/Substitutions.vue
+++ b/aleksis/apps/chronos/frontend/components/Substitutions.vue
@@ -99,14 +99,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
     <!-- component and reuse? -->
     <template #groups="{ item: { oldGroups, newGroups } }">
       <span v-if="newGroups.length > 0">
-        <span class="strike-through" v-for="g in oldGroups" :key="g.id">{{
-          g.shortName
-        }}</span>
+        <span class="strike-through">
+          <lesson-event-link-iterator
+            :items="oldGroups"
+            attr="shortName"
+            alternative-attr="name"
+          />
+        </span>
         <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
         <span>&nbsp;→&nbsp;</span>
-        <strong v-for="g in newGroups" :key="g.id">{{ g.shortName }}</strong>
+        <strong>
+          <lesson-event-link-iterator
+            :items="newGroups"
+            attr="shortName"
+            alternative-attr="name"
+          />
+        </strong>
+      </span>
+      <span v-else>
+        <lesson-event-link-iterator
+          :items="oldGroups"
+          attr="shortName"
+          alternative-attr="name"
+        />
       </span>
-      <span v-else v-for="g in oldGroups" :key="g.id">{{ g.shortName }}</span>
     </template>
     <template #time="{ item: { startSlot, endSlot, startTime, endTime } }">
       <span v-if="startSlot && endSlot && startSlot === endSlot">
@@ -124,17 +140,29 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
     </template>
     <template #teachers="{ item: { oldTeachers, newTeachers } }">
       <span v-if="newTeachers.length > 0">
-        <span class="strike-through" v-for="t in oldTeachers" :key="t.id">
-          {{ t.shortName || t.fullName }}
+        <span class="strike-through">
+          <lesson-event-link-iterator
+            :items="oldTeachers"
+            attr="shortName"
+            alternative-attr="fullName"
+          />
         </span>
         <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
         <span>&nbsp;→&nbsp;</span>
-        <strong v-for="t in newTeachers" :key="t.id">
-          {{ t.shortName || t.fullName }}
+        <strong>
+          <lesson-event-link-iterator
+            :items="newTeachers"
+            attr="shortName"
+            alternative-attr="fullName"
+          />
         </strong>
       </span>
-      <span v-else v-for="t in oldTeachers" :key="t.id">
-        {{ t.shortName || t.fullName }}
+      <span v-else>
+        <lesson-event-link-iterator
+          :items="oldTeachers"
+          attr="shortName"
+          alternative-attr="fullName"
+        />
       </span>
     </template>
     <template #subject="{ item: { oldSubject, newSubject } }">
@@ -151,18 +179,30 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
     </template>
     <template #rooms="{ item: { oldRooms, newRooms } }">
       <span v-if="newRooms.length > 0">
-        <span class="strike-through" v-for="r in oldRooms" :key="r.id">{{
-          r.shortName || r.name
-        }}</span>
+        <span class="strike-through">
+          <lesson-event-link-iterator
+            :items="oldRooms"
+            attr="shortName"
+            alternative-attr="name"
+          />
+        </span>
         <!-- eslint-disable-next-line @intlify/vue-i18n/no-raw-text -->
         <span>&nbsp;→&nbsp;</span>
-        <strong v-for="r in newRooms" :key="r.id">{{
-          r.shortName || r.name
-        }}</strong>
+        <strong>
+          <lesson-event-link-iterator
+            :items="newRooms"
+            attr="shortName"
+            alternative-attr="name"
+          />
+        </strong>
+      </span>
+      <span v-else>
+        <lesson-event-link-iterator
+          :items="oldRooms"
+          attr="shortName"
+          alternative-attr="name"
+        />
       </span>
-      <span v-else v-for="r in oldRooms" :key="r.id">{{
-        r.shortName || r.name
-      }}</span>
     </template>
     <template #notes="{ item: { cancelled, notes } }">
       <v-chip v-if="cancelled" color="green" text-color="white" small>
@@ -189,8 +229,11 @@ import DateSelectFooter from "aleksis.core/components/generic/DateSelectFooter.v
 import { substitutionsForDate } from "./substitutions.graphql";
 import { DateTime } from "luxon";
 
+import LessonEventLinkIterator from "./LessonEventLinkIterator.vue";
+
 export default {
   name: "Substitutions",
+  components: { LessonEventLinkIterator },
   props: {
     date: {
       type: String,