Det här exemplet använder det ramverksoberoende biblioteket
JSON Editor
(MIT-licens, inget React eller Angular krävs) som bas, kompletterat med
tilläggsfilen vitec-questionnaire.js som hanterar de Vitec-specifika
mönster i JSON-schemat som inte fungerar automatiskt.
Vad filen vitec-questionnaire.js hanterar automatiskt:
-
boolean+oneOf→ renderas som radioknappar med titlarna från schemat (t.ex. Ja / Nej). Property-namn exponeras aldrig för slutanvändaren – använd alltidtitleochdescriptionför etiketter och hjälptexter. -
if/then/else→ följdfrågor visas och döljs dynamiskt. Dolda fält exkluderas automatiskt från validering och från det data-objekt som skickas till Connect. -
ui:order→ fältordning respekteras. -
Sektioner (
type: "object") renderas som visuella grupper. Sektioner utantitlevisar enbart sitt innehåll utan rubrik.
Validering på svenska (eller annat språk):
Filen vitec-questionnaire.js innehåller en färdig svensk översättning av
alla valideringsmeddelanden. Aktivera den genom att skicka med alternativet
language: 'sv' till konstruktorn:
const questionnaire = new VitecQuestionnaire(
document.getElementById('questionnaire'),
schemaFromApi,
{ language: 'sv' } // aktiverar svenska felmeddelanden
);
Utan detta alternativ används engelska (JSON Editors standardspråk). Vill ni använda ett annat språk kan ni registrera en egen översättning innan ni skapar formuläret:
// Registrera ett eget språk (alla nycklar är valfria – saknade nycklar
// faller tillbaka på engelska)
JSONEditor.defaults.languages.fi = {
error_notset: 'Kenttä on pakollinen',
error_notempty: 'Arvo vaaditaan',
// ... övriga nycklar
};
const questionnaire = new VitecQuestionnaire(el, schema, { language: 'fi' });
Inkludera biblioteken:
<!-- JSON Editor (ramverksoberoende bas) -->
<script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script>
<!-- Vitec-extension -->
<script src="https://connect.maklare.vitec.net/Scripts/vitec-questionnaire.js"></script>
HTML-struktur:
<!-- Kontaktväljare -->
<label for="contact-select">Kontakt som svarar</label>
<select id="contact-select"></select>
<!-- Formuläret renderas här -->
<div id="questionnaire"></div>
<button id="btn-send" type="button">Skicka</button>
Komplett JavaScript-exempel:
// schemaFromApi – JSON Schema hämtad via GET .../JsonSchema
// contactsFromApi – array med { id, firstName, lastName } från GET .../Contacts
// 1. Populera kontaktväljaren
const contactSelect = document.getElementById('contact-select');
contactsFromApi.forEach(c => {
const opt = document.createElement('option');
opt.value = c.id;
opt.textContent = c.firstName + ' ' + c.lastName;
contactSelect.appendChild(opt);
});
// 2. Rendera formuläret
// VitecQuestionnaire hanterar automatiskt:
// - boolean+oneOf → Ja/Nej-radioknappar (titlar från schemat)
// - if/then/else → visa/dölj följdfrågor dynamiskt
// - ui:order → fältordning
// - tomma titlar på sektioner → ingen rubrik visas
const questionnaire = new VitecQuestionnaire(
document.getElementById('questionnaire'),
schemaFromApi,
{
onChange: data => {
// valfritt: reagera på ändringar i realtid
}
}
);
// 3. Skicka svar
document.getElementById('btn-send').addEventListener('click', () => {
const errors = questionnaire.validate();
if (errors.length > 0) {
// Visa valideringsfel för användaren
alert(errors.map(e => e.message).join('\n'));
return;
}
const contactId = contactSelect.value;
const customerId = 'M123'; // er kund-id
const estateId = 'OBJ123_...'; // aktuell bostad
const schemaId = schemaFromApi.$id; // formulärets id
fetch(
`/Service/MyPages/${customerId}/Estate/${estateId}/Document/Questionnaire/${schemaId}/Contact/${contactId}/Answers/Json`,
{
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('username:password'),
'Content-Type': 'application/json'
},
// getData() returnerar bara synliga fält – dolda följdfrågor exkluderas
body: JSON.stringify(questionnaire.getData())
}
)
.then(res => {
if (res.status === 204) {
alert('Svaren skickades!');
} else {
return res.json().then(body => {
// HTTP 400 – visa valideringsmeddelanden från Connect
const msgs = (body.errors || []).map(e => e.displayedMessage || e.errorMessage);
alert('Valideringsfel:\n' + msgs.join('\n'));
});
}
})
.catch(() => alert('Nätverksfel – försök igen.'));
});
Notera om boolean-fält: När schemat innehåller kombinationen
type: "boolean" och oneOf ska fältet renderas som ett
explicit Ja/Nej-val (eller de titlar som definieras i oneOf) snarare
än en traditionell kryssruta. vitec-questionnaire.js hanterar detta
automatiskt.
Notera om följdfrågor: Fält som styrs av
if / then / else ska
döljas visuellt och undantas från validering tills villkoret är uppfyllt.
Property-namn (t.ex. hasRenovationsText) är tekniska identifierare och
ska aldrig visas för slutanvändaren – använd alltid title och
description från schemat.