-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #39: select controls for ui-vue
- Loading branch information
1 parent
959419b
commit 514f18f
Showing
7 changed files
with
238 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<script setup lang="ts"> | ||
import type { SelectItem, SelectNode } from '@odk-web-forms/xforms-engine'; | ||
import PrimeVueCheckbox from 'primevue/checkbox'; | ||
import PrimeVueRadioButton from 'primevue/radiobutton'; | ||
import { computed } from 'vue'; | ||
import ControlLabel from '../ControlLabel.vue'; | ||
const props = defineProps<{question: SelectNode}>(); | ||
const setSelect1Value = (item: SelectItem) => { | ||
props.question.select(item); | ||
}; | ||
const setSelectNValue = (e: Event, item: SelectItem) => { | ||
const checkbox = e.target as HTMLInputElement; | ||
if(checkbox.checked) { | ||
props.question.select(item); | ||
} | ||
else{ | ||
props.question.deselect(item); | ||
} | ||
} | ||
const value = computed(() => { | ||
const [item] = props.question.currentState.value; | ||
return item?.value ?? null | ||
}) | ||
</script> | ||
|
||
<template> | ||
<ControlLabel :question="question" /> | ||
|
||
<template v-if="question.definition.bodyElement.type === 'select1'"> | ||
<div | ||
v-for="option in question.currentState.valueOptions" | ||
:key="option.value" | ||
:class="[{disabled: question.currentState.readonly}, 'select1']" | ||
> | ||
<PrimeVueRadioButton | ||
:input-id="question.nodeId + '_' + option.value" | ||
:name="question.nodeId" | ||
:value="option.value" | ||
:disabled="question.currentState.readonly" | ||
:model-value="value" | ||
@update:model-value="setSelect1Value(option)" | ||
/> | ||
<label :for="question.nodeId + '_' + option.value">{{ option.label?.asString }}</label> | ||
</div> | ||
</template> | ||
|
||
<template v-else> | ||
<div | ||
v-for="option of question.currentState.valueOptions" | ||
:key="option.value" | ||
:class="[{disabled: question.currentState.readonly}, 'selectN']" | ||
> | ||
<PrimeVueCheckbox | ||
:input-id="question.nodeId + '_' + option.value" | ||
:name="question.nodeId" | ||
:value="option.value" | ||
:disabled="question.currentState.readonly" | ||
:model-value="question.currentState.value.map(v => v.value)" | ||
@change="setSelectNValue($event, option)" | ||
/> | ||
<label :for="question.nodeId + '_' + option.value">{{ option.label?.asString }}</label> | ||
</div> | ||
</template> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { DOMWrapper, mount } from '@vue/test-utils'; | ||
import { describe, expect, it } from 'vitest'; | ||
import SelectControl from '@/components/controls/SelectControl.vue'; | ||
import { getReactiveForm, globalMountOptions } from '../helpers'; | ||
import type { SelectNode } from '@odk-web-forms/xforms-engine'; | ||
|
||
const mountComponent = async (questionNumber: number) => { | ||
const xform = await getReactiveForm('select/1-static-selects.xml'); | ||
|
||
return mount(SelectControl, { | ||
props: { | ||
question: xform.currentState.children[questionNumber] as SelectNode, | ||
}, | ||
global: globalMountOptions, | ||
}); | ||
}; | ||
|
||
describe('SelectControl', () => { | ||
it('shows radio buttons for select1', async () => { | ||
const component = await mountComponent(0); | ||
const cherry: DOMWrapper<HTMLInputElement> = component.find('input[value="cherry"]'); | ||
const mango: DOMWrapper<HTMLInputElement> = component.find('input[value="mango"]'); | ||
|
||
expect(cherry.element.type).to.be.eql('radio'); | ||
expect(cherry.element.checked).to.be.true; | ||
|
||
await mango.trigger('click'); | ||
|
||
expect(cherry.element.checked).to.be.false; | ||
expect(mango.element.checked).to.be.true; | ||
}); | ||
|
||
it('shows checkboxes for select many', async () => { | ||
const component = await mountComponent(1); | ||
|
||
const watermelon: DOMWrapper<HTMLInputElement> = component.find('input[value="watermelon"]'); | ||
const peach: DOMWrapper<HTMLInputElement> = component.find('input[value="peach"]'); | ||
|
||
expect(watermelon.element.type).to.be.eql('checkbox'); | ||
expect(watermelon.element.checked).to.be.false; | ||
expect(peach.element.checked).to.be.true; | ||
|
||
await watermelon.trigger('click'); | ||
await peach.trigger('click'); | ||
|
||
expect(watermelon.element.checked).to.be.true; | ||
expect(peach.element.checked).to.be.false; | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { initializeForm, type RootNode } from '@odk-web-forms/xforms-engine'; | ||
// eslint-disable-next-line no-restricted-imports -- in test environemnt | ||
import { readFile } from 'fs/promises'; | ||
import { reactive } from 'vue'; | ||
import PrimeVue from 'primevue/config'; | ||
import type { MountingOptions } from '@vue/test-utils'; | ||
|
||
export const getReactiveForm = async (formPath: string): Promise<RootNode> => { | ||
const formXml = await readFile(`../ui-solid/fixtures/xforms/${formPath}`, 'utf8'); | ||
|
||
return await initializeForm(formXml, { | ||
config: { | ||
stateFactory: <T extends object>(o: T) => { | ||
return reactive(o) as T; | ||
}, | ||
}, | ||
}); | ||
}; | ||
|
||
type GlobalMountOptions = Required<MountingOptions<unknown>>['global']; | ||
|
||
export const globalMountOptions: GlobalMountOptions = { | ||
plugins: [[PrimeVue, { ripple: false }]], | ||
stubs: { | ||
teleport: true, | ||
}, | ||
}; |