Code

Code D.1: userTesting.js
import { SelectComponent, pageCss } from "https://fhnw-ramonamarti.github.io/Kolibri/src/examples/select-new/selectComponent.js";
import * as Service                 from "./dataService.js";

// load styles for new component
const style = document.createElement("style");
style.textContent = pageCss;
document.querySelector("head").append(style);

/**
 * helper to replace elements to form
 * @param {*} id - id of the html element to place the projected elements in
 * @param {*} labelElement - new label to relape in the form
 * @param {*} inputElement - new input element to relape in the form
 * @example
        addSelectViewToUi("task1", lunchLabelElement, lunchInputElement);
 */
const addSelectViewToUi = (id, labelElement, inputElement) => {
    const inputContainer = document.getElementById(id);
    const labelContainer = document.getElementById(id + "-label");
    labelContainer.replaceWith(labelElement);
    inputContainer.replaceWith(inputElement);
}

// NOTE: You can read about our project in README.md file. 
// Please follow the TODO's for the five tasks.
// The tasks are structured in the UI as follows:
//      1. Demo container with the usage of an existing way to create a selection input.
//      2. Task container with TODO's placeholder is positioned in the form 
//              where the new componenent should be fit in.


// ----- TASK 1 ----------
/*
    TODO: Create a selection input using our new component.
    The label should be 'Lunch' and the name 'lunch'.
    The resulting component should provide 1 column with the data.
    The data is provided by the function `Service.getLunchTypes()` 
    and can be used to fulfill the task.
    To add the created view elements to the form you can use 
    the function `addSelectViewToUi` from the top.
    The id of the container to fill the view elements in is 'task1-lunch'.
*/

// TODO: SOLUTION TASK 1 HERE



// ----- TASK 2 ----------
// ----- TASK 2.1 --------
/*
    TODO: Create a selection input using our new component.
    The label should be 'Home region' and the name 'home-region'.
    The resulting component should provide 2 column with the value data and categories.
    The value data is provided by the function `Service.getRegionsByCountryChDeAt()`, 
    the categories are provided by the function `Service.getCountriesChDeAt()` 
    and they can be used to fulfill the task.
    To add the created view elements to the form you can use 
    the function `addSelectViewToUi` from the top.
    The id of the container to fill the data view elements is 'task2-home-region'.
*/

// TODO: SOLUTION TASK 2.1 HERE



// ----- TASK 2.2 --------
/*
    TODO: Create a selection input using our new component.
    The label should be 'Birth region' and the name 'birth-region'.
    The resulting component should provide 2 column with the value data and categories.
    The value data is provided by the function `Service.getRegionsByCountry()`, 
    the categories are provided by the function `Service.getCountries()` 
    and they can be used to fulfill the task.
    To add the created view elements to the form you can use 
    the function `addSelectViewToUi` from the top.
    The id of the container to fill the data view elements is 'task2-birth-region'.
*/

// TODO: SOLUTION TASK 2.2 HERE



// ----- TASK 2.3 --------
/*
    TODO: Create a selection input using our new component.
    The label should be 'Birth year' and the name 'birth-year'.
    The resulting component should provide 2 column with the value data and categories.
    The value data is provided by the function `Service.getYearsByDecade()`, 
    the categories are provided by the function `Service.getDecades()` 
    and they can be used to fulfill the task.
    To add the created view elements to the form you can use 
    the function `addSelectViewToUi` from the top.
    The id of the container to fill the data view elements is 'task2-birth-year'.
*/

// TODO: SOLUTION TASK 2.3 HERE




// ------------------------
// Please fill out the question form to give us feedback about how the tasks worked. 
// Please send your solution as a zip back to Ramona Marti on MS Teams.
Code D.2: userTesting.html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Auswahlkomponente User Test</title>
        <link
            rel="shortcut icon"
            type="image/png"
            href="https://fhnw-ramonamarti.github.io/Kolibri/img/logo/logo-60x54.png"
            />
        <link
            rel="stylesheet"
            href="https://fhnw-ramonamarti.github.io/Kolibri/css/kolibri-base.css"
            />
        <style>
            .newComponent {
                color: red;
                font-weight: bold;
            }
            label {
                display: flex;
                align-items: center;
            }
            select,
            input {
                border: #ccc solid 1px;
                font-size: 1rem;
                height: 2rem;
                border-radius: 4px;
            }
            .task .select-input-component {
                width: 320px;
            }
        </style>
    </head>
    <body>
        <div class="demo" id="demo1"></div>
        <div class="task" id="task1"></div>
        <div class="demo" id="demo2"></div>
        <div class="task" id="task2"></div>
        <div class="demo" id="demo3"></div>
        <div class="task" id="task3"></div>
        <script type="module" src="starter.js"></script>
        <script type="module" src="userTesting.js"></script>
    </body>
</html>
Code D.3: starter.js
import { projectForm, FORM_CSS }  from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/projector/simpleForm/simpleFormProjector.js"
import { SimpleFormController }   from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/projector/simpleForm/simpleFormController.js"
import { TEXT, CHOICE, COMBOBOX } from "https://fhnw-ramonamarti.github.io/Kolibri/src/kolibri/util/dom.js";

import * as Service               from "./dataService.js";

// load style 
const style = document.createElement("style");
style.textContent = FORM_CSS;
document.querySelector("head").append(style);

// prepare filling container
const fillContainer = (id, title, buildForm) => {
    const formHolder = document.getElementById(id);
    if (null != formHolder) {
        const [fieldset]     = buildForm();
        formHolder.innerHTML = `<h3>${title}</h3>`;
        formHolder.append(fieldset);
    }
};

// prepare containes to do the tasks in
const replaceField = (id, name) => {
    const inputElement = document.getElementById(id).querySelector(`[name=${name}]`);
    const inputId      = inputElement.id;
    const fieldset     = inputElement.closest("fieldset")
    const labelElement = fieldset.querySelector(`[for="${inputId}"]`);
    const spanElement  = fieldset.querySelector(`span[data-id="${inputId}"]`);

    const containerLabel  = document.createElement("span");
    containerLabel.id     = id + "-" + name + "-label";
    const container       = document.createElement("span");
    container.id          = id + "-" + name;
    container.textContent = "TODO";
    container.classList.add("newComponent");
    spanElement.replaceWith(container);
    labelElement.replaceWith(containerLabel);

    return [containerLabel, container];
};

// ----- DEMO 1 --------
const demo1 = () => {
    /** @type { Array<OptionType> } */
    const types = Service.getLunchTypes().map((types) => ({ value: types }));

    const formStructure = [
        { value: "", label: "Name",   name: "name",  type: TEXT },
        { value: "", label: "Lunch", name: "lunch", type: COMBOBOX, list: types },
    ];
    const controller = SimpleFormController(formStructure);
    return projectForm(controller);
};
fillContainer("demo1", "Demo 1 - Short datalist", demo1);

// ----- TASK 1 --------
const task1 = () => {
    
    const formStructure = [
        { value: "", label: "Name",  name: "name",  type: TEXT     },
        { value: "", label: "Lunch", name: "lunch", type: "hidden" },
    ];
    const controller = SimpleFormController(formStructure);
    return projectForm(controller);
};
fillContainer("task1", "Task 1 - 1 column layout", task1);
replaceField("task1", "lunch");

// ----- DEMO --------
const demo2 = () => {
    /** @type { Array<OptionType> } */
    const years = Service.getYearsByDecade().map((year) => ({ value: year }));

    /** @type { Array<OptionType> } */
    const filterRegionsChDeAt = (...countryCode) =>
        Service.getRegionsByCountryChDeAt(...countryCode).map((region) => ({ value: region }));

    /** @type { Array<OptionType> } */
    const filterRegions = (...countryCode) =>
        Service.getRegionsByCountry(...countryCode).map((region) => ({ value: region }));
    const formStructure = [
        { value: "", label: "Name",       name: "name",      type: TEXT },
        {
            value: "Aargau",
            label: "Home region",
            name: "home-region",
            type: CHOICE,
            list: filterRegionsChDeAt(),
        },
        {
            value: "",
            label: "Birth region",
            name: "birth-region",
            type: CHOICE,
            list: filterRegions(),
        },
        { value: "", label: "Birth year", name: "birth-year", type: CHOICE, list: years },
    ];
    const controller = SimpleFormController(formStructure);
    return projectForm(controller);
};
fillContainer("demo2", "Demo 2 - Long selects", demo2);

// ----- TASK 2 --------
const task2 = () => {
    
    const formStructure = [
        { value: "",   label: "Name",         name: "name",         type: TEXT     },
        { value: "",   label: "Home region",  name: "home-region",  type: "hidden" },
        { value: "",   label: "Birth region", name: "birth-region", type: "hidden" },
        { value: "",   label: "Birth year",   name: "birth-year",   type: "hidden" },
    ];
    const controller = SimpleFormController(formStructure);
    return projectForm(controller);
};
fillContainer("task2", "Task 2 - 2 column layout", task2);
replaceField("task2", "home-region");
replaceField("task2", "birth-region");
replaceField("task2", "birth-year");
Code D.4: dataService.js
export {
    getAllContinents,
    getCountries,
    getCountriesChDeAt,
    getRegionsByCountry,
    getRegionsByCountryChDeAt,
    getYearsByDecade,
    getDecades,
    getLunchTypes,
};

/** @type { () => String } */
const getAllContinents = () => {allCountriesWithContinent.map((country) => country.continent);return [
    ...new Set(allCountriesWithContinent.map((country) => country.continent)),
]};

/** @type { (...String) => String } */
const getCountries = (...continents) =>
    allCountriesWithContinent
        .filter((e) => allRegionsWithCountry.map((c) => c.country).includes(e.country))
        .filter((e) => continents.length === 0 || continents.includes(e.continent))
        .map((country) => country.country);

/** @type { (...String) => String } */
const getRegionsByCountry = (...countries) =>
    allRegionsWithCountry
        .filter((e) => countries.length === 0 || countries.includes(e.country))
        .map((region) => region.region).sort();

/** @type { () => String } */
const getCountriesChDeAt = () => ["Switzerland", "Germany", "Austria"];

/** @type { (...String) => String } */
const getRegionsByCountryChDeAt = (...countries) =>
    allRegionsWithCountry
        .filter(
            (e) => countries.length === 0 && ["CH", "DE", "AT"].includes(e.code) || countries.includes(e.country)
        )
        .map((region) => region.region).sort();

/** @type { (...String) => String } */
const getYearsByDecade = (...decades) => {
    const decadeStarts = decades.map(decade => decade.slice(0, 3));
    const data = [...Array(90).keys()].map((e) => e + 1930 + "");
    return data.filter((e) => (e) => decadeStarts.length === 0 || decadeStarts.includes(e.slice(0, 3)));
};

/** @type { () => String } */
const getDecades = () => [...Array(9).keys()].map((e) => e * 10 + 1930 + "'s");

/** @type { () => String } */
const getLunchTypes = () => ["all", "vegetarian", "vegan", "flexetarian", "gluten-free", "lactose-free"];

/* data tables for 'allCountriesWithContinent' and 'allRegionsWithCountry' */
/* Link: https://github.com/fhnw-ramonamarti/fhnw-ramonamarti.github.io/blob/main/ip6/userTest/dataService_old.js */

Last updated

© 2024 Ramona Marti & Lea Burki