Skip to content

Vue ​

Das Paket @pollyou/vue bindet PollYou-Umfragen als Vue-Komponente ein. Es kapselt das Web Component <pollyou-survey> aus @pollyou/embed-core, unterstützt Vue 3.4 und neuer und funktioniert mit Server-Side Rendering (Nuxt).

Installation ​

bash
npm install @pollyou/vue
# oder
pnpm add @pollyou/vue

vue ist Peer-Abhängigkeit. @pollyou/embed-core wird automatisch mitinstalliert und erst im Browser nachgeladen. Eine Konfiguration von compilerOptions.isCustomElement ist nicht nötig: Die Komponente erzeugt das Element per Render-Funktion, der Template-Compiler bekommt <pollyou-survey> nie zu sehen.

Einbinden ​

vue
<script setup lang="ts">
import { PollYouSurvey } from '@pollyou/vue'

function onComplete(detail: { responseId: string | null }) {
  console.log('Antwort gespeichert', detail.responseId)
}
</script>

<template>
  <PollYouSurvey
    survey-id="AbC123xyz0"
    api-base="https://app.pollyou.org"
    locale="de"
    @complete="onComplete"
  />
</template>

Den passenden Code mit allen gewählten Optionen erzeugt der Einbetten-Dialog im Dashboard (Reiter „Vue“).

Plugin mit Vorgaben ​

Optional legt das Plugin app-weite Vorgaben fest (Props der Komponente haben Vorrang) und registriert <PollYouSurvey> global:

ts
import { createApp } from 'vue'
import { PollYou } from '@pollyou/vue'
import App from './App.vue'

createApp(App).use(PollYou, { apiBase: 'https://app.pollyou.org', locale: 'de' }).mount('#app')

Als Vorgabe taugt jede Prop außer surveyId und open.

Props ​

PropTypBedeutung
survey-idstring (Pflicht)Öffentliche ID der Umfrage.
embed-idstringEmbed-Konfiguration (erlaubte Domains, Vorgaben).
api-basestringOrigin der Collector-API, z. B. https://app.pollyou.org.
mode'inline' | 'popup' | 'slider' | 'fullpage'Darstellung, Standard inline; Overlays sichtbar solange open. Auslöser (Verzögerung, Scrolltiefe …) nur über die Embed-Konfiguration, siehe Overlays.
v-model:openbooleanSichtbarkeit des Popups. Weglassen, wenn usePollYou() das Popup steuert.
localestringSprache, Standard: Sprache der Seite bzw. des Browsers.
theme'auto' | 'light' | 'dark'Farbschema, Standard auto.
show-resultsbooleanfalse blendet Ergebnisse aus, auch wenn die Umfrage sie zeigt.
live-resultsbooleanAngezeigte Ergebnisse live aktualisieren.
identity-tokenstringSigniertes Identitäts-Token des angemeldeten Nutzers.
metaRecord<string, string | number | boolean>Zusatzdaten zur Antwort (max. 20 Schlüssel).
hiddenRecord<string, string | number | boolean>Versteckte Felder, z. B. { 'user-id': 42 } → hidden-user-id. Schlüssel werden kleingeschrieben.
channelstringKanal in der Auswertung, Standard vue (oder die Plugin-Vorgabe).

Weitere Attribute wie class, style oder hidden-user-id="42" landen unverändert auf dem Element. Gestalten lässt sich die Umfrage über das Theme im Dashboard und über ::part()-Selektoren (siehe Einbettung per Script).

Ereignisse ​

Die Nutzlast ist jeweils detail des ursprünglichen pollyou:*-Ereignisses.

Ereignisdetail
@ready{ surveyId, type, status }
@start{ surveyId } (erste Antwort)
@answer{ surveyId, questionKey, answer }
@complete{ surveyId, responseId, results }
@close{ surveyId, mode }
@error{ surveyId, phase: 'load' | 'submit', status }
@update:openfalse, wenn sich ein kontrolliertes Popup schließt

Mit v-model:open:

vue
<script setup lang="ts">
import { ref } from 'vue'
import { PollYouSurvey } from '@pollyou/vue'

const open = ref(false)
</script>

<template>
  <button type="button" @click="open = true">Feedback geben</button>
  <PollYouSurvey survey-id="AbC123xyz0" mode="popup" v-model:open="open" />
</template>

Oder imperativ mit dem Composable usePollYou():

vue
<script setup lang="ts">
import { PollYouSurvey, usePollYou } from '@pollyou/vue'

const { survey, open, completed, lastEvent } = usePollYou()
</script>

<template>
  <button type="button" :disabled="completed" @click="open">Feedback geben</button>
  <PollYouSurvey ref="survey" survey-id="AbC123xyz0" mode="popup" />
  <p v-if="lastEvent?.type === 'complete'">Danke!</p>
</template>

usePollYou() liefert survey (Template-Ref), element, open(), close(), isOpen, lastEvent ({ type, detail } des letzten pollyou:*-Ereignisses), completed und die Plugin-Vorgaben options.

Identitäts-Token ​

Für „eine Antwort pro Kunde“ oder Umfragen nur für angemeldete Nutzer erzeugt Ihr Server ein signiertes Identitäts-Token – das Embed-Secret gehört nie in den Browser. In Nuxt etwa über eine Server-Route:

ts
// server/api/pollyou-token.get.ts
import { SignJWT } from 'jose'

export default defineEventHandler(async (event) => {
  const user = await requireUser(event)
  return new SignJWT({})
    .setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
    .setSubject(String(user.id))
    .setExpirationTime('10m')
    .sign(new TextEncoder().encode(process.env.POLLYOU_EMBED_SECRET))
})
vue
<script setup lang="ts">
const { data: token } = await useFetch<string>('/api/pollyou-token')
</script>

<template>
  <PollYouSurvey survey-id="AbC123xyz0" :identity-token="token ?? undefined" />
</template>

SSR und Nuxt ​

  • Beim Server-Rendering greift die Komponente auf keine Browser-API zu; es entsteht nur das leere Tag <pollyou-survey> (mit durchgereichten Attributen wie class). Attribute und das Nachladen von @pollyou/embed-core passieren erst im Browser (onMounted). Ein <ClientOnly> ist nicht nötig.

  • In Nuxt lässt sich das Plugin in plugins/pollyou.ts registrieren:

    ts
    import { PollYou } from '@pollyou/vue'
    
    export default defineNuxtPlugin((nuxtApp) => {
      nuxtApp.vueApp.use(PollYou, { apiBase: 'https://app.pollyou.org' })
    })
  • Für einen festen Platz ohne Layoutsprung empfiehlt sich eine Mindesthöhe, z. B. style="min-height: 320px".

Beispiel-App ​

Ein lauffähiges Beispiel liegt im Playground: frontend/apps/playground/vue (Vue 3 + Vite, Plugin mit Vorgaben, alle Ereignisse im Protokoll).

Fehlersuche ​

  • Die Umfrage bleibt leer oder zeigt „nicht gefunden“: Nur veröffentlichte Umfragen sind öffentlich; ein Entwurf oder eine archivierte Umfrage liefert 404. Das Ereignis @error meldet { phase: 'load', status }.
  • Fehler „blocked by CORS policy“ oder 403 origin_not_allowed: Die Embed-Konfiguration erlaubt nur bestimmte Origins. Tragen Sie die Origin Ihrer Seite ein – mit Schema und Port, also auch den lokalen Dev-Server (z. B. http://localhost:5173). api-base ist die Origin der API ohne Pfad (https://app.pollyou.org, nicht …/api).
  • Content-Security-Policy: Erlauben Sie die API in connect-src (z. B. connect-src 'self' https://app.pollyou.org, für Live-Ergebnisse zusätzlich den Hub). script-src braucht keinen Eintrag: @pollyou/embed-core ist Teil Ihres Bundles und wird als eigener Chunk von Ihrer Origin nachgeladen. Die Styles setzt das Web-Component per Constructable Stylesheets und CSSOM, 'unsafe-inline' in style-src ist nicht nötig – nur eigenes Theme-CSS wird als <style> eingefügt und fehlt ohne 'unsafe-inline' (die Umfrage funktioniert trotzdem). Das Captcha kommt ohne Worker und eval aus.
  • Lokal in Chrome keine Verbindung zur API: Chrome blockiert mit Local Network Access Anfragen von öffentlichen Seiten an localhost. Die Seite muss selbst lokal laufen (localhost/127.0.0.1), wie die Apps im Playground.
  • Nuxt/SSR: leeres Element im HTML: Das ist gewollt – der Server rendert nur <pollyou-survey>, die Umfrage lädt nach dem Mounten im Browser. Für einen festen Platz ohne Layoutsprung eine Mindesthöhe setzen.
  • Hydration-Warnungen: Entstehen, wenn Props auf dem Server anders berechnet werden als im Browser, etwa aus window.location. In Nuxt die Query mit useRoute() lesen, sonst erst in onMounted setzen.
  • „Failed to resolve component: pollyou-survey“: Tritt nur auf, wenn <pollyou-survey> direkt im Template steht. Verwenden Sie <PollYouSurvey> aus dem Paket; compilerOptions.isCustomElement ist dann nicht nötig.