Published
Edited
May 25, 2021
Importers
Insert cell
Insert cell
Insert cell
viewof question = questionSelector(sheet, {startIndex: 2})
Insert cell
question
Insert cell
Insert cell
viewof s = compareQuestionSelector(sheet)
Insert cell
function questionSelector(sheet, {
startIndex = 1,
filter = null
} = {}) {
let questions = Object.values(sheet.questions)
if(filter) questions = questions.filter(filter)
const startValue = questions[startIndex];
const type = (x) => {
if(x.type == "choice") return "🔘"
if(x.type == "multi") return "✅"
if(x.type == "free") return "🖋"
return "🔘"
}
const radio = Inputs.radio(questions, {format: x => html`<div style="display:flex; justify-content:space-between;width: 100%;line-height:2em">
<div style="">${x.question}</div>
<div style="opacity: 0.3;filter:grayscale(100%)" title="${prettyType(x.type)}">${type(x)} </div>
</div>`, value: startValue});
// some custom styling
const parent = radio.getElementsByTagName("div")[0];
parent.style = "max-height: 250px; overflow-y: scroll";
const labels = radio.getElementsByTagName("label");
for (let label of labels) {
label.style = "display:flex; justify-content:space-between; margin-bottom: 5px; min-height:2em;"
}
const filterRows = (filterQuery) => {
const query = filterQuery.toUpperCase();
const labels = radio.getElementsByTagName("label");

for (let label of labels) {
label.textContent.toUpperCase().indexOf(query) > -1
? label.style.display = "flex"
: label.style.display = "none";
}
};

const filterer = html`
<input
autocomplete="off"
type="search"
style="position: sticky"
placeholder="Filter questions..."
oninput=${(e) => filterRows(e.target.value)}
>
`;
const selector = html`
${filterer}
<div style="margin-top: 10px" class="radios">${radio}</div>
<style>
.radios label {
border-bottom: 1px solid #fff;
}
.radios label:hover {
cursor: pointer;
border-bottom: 1px solid #eee;
/*background-color: #efefef;/*
}
</style>
`;
selector.value = radio.value;
selector.addEventListener("input", e => {
selector.value = radio.value;
});
return selector;
}
Insert cell
function compareQuestionSelector(sheet, options = {}) {
const {index1 = 1, index2 = 2, free2 = false} = options;
let filter = d => d.type !== "free"
const selector1 = questionSelector(sheet, {startIndex: index1, filter });
const selector2 = questionSelector(sheet, {startIndex: index2, filter: free2 ? null : filter});
const selectors =
html`<div style="grid-template-columns: 1fr 1fr; display: grid; column-gap: 1rem;">
<div>
<h3>Question 1</h3>
${selector1}
</div>
<div>
<h3>Question 2</h3>
${selector2}
</div>
</div>`;


selector1.addEventListener("input", e => {
selectors.value.q1 = selector1.value;
selectors.dispatchEvent(new CustomEvent("input", {bubbles: true}));
});

selector2.addEventListener("input", e => {
selectors.value.q2 = selector2.value;
selectors.dispatchEvent(new CustomEvent("input", {bubbles: true}));
});
selectors.value = {q1: selector1.value, q2: selector2.value};
return selectors;
}
Insert cell
prettyType = (type) => {
if(type == "free") return "Free Response"
if(type == "multi") return "Multiple Select"
if(type == "choice") return "Multiple Choice"
}
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more