Skip to content

Commit

Permalink
Implement tagbox question
Browse files Browse the repository at this point in the history
  • Loading branch information
dk981234 committed Jun 12, 2023
1 parent d5a9dc8 commit 2121753
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 8 deletions.
21 changes: 21 additions & 0 deletions packages/survey-vue-ui/src/Tagbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<div :class="question.renderCssRoot">
<sv-tagbox :question="question"></sv-tagbox>
<survey-other-choice v-if="question.isOtherSelected" :question="question" />
</div>
</template>

<script lang="ts">
import { QuestionTagboxModel } from "survey-core";
import { QuestionVue } from "./base";
import { defineComponent } from "vue";
export default defineComponent({
// eslint-disable-next-line
mixins: [QuestionVue],
name: "survey-tagbox",
props: {
question: QuestionTagboxModel,
},
});
</script>
9 changes: 1 addition & 8 deletions packages/survey-vue-ui/src/assets/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,7 @@
}
}

*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
position: relative;
font-weight: normal;
}


body {
min-height: 100vh;
Expand Down
101 changes: 101 additions & 0 deletions packages/survey-vue-ui/src/components/tagbox/Tagbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<template>
<div :class="question.cssClasses.selectWrapper">
<div
v-if="!question.isReadOnly"
:id="question.inputId"
:tabindex="model.inputReadOnly ? undefined : 0"
:disabled="question.isInputReadOnly ? true : null"
@click="click"
@keydown="keyhandler"
@blur="blur"
:class="question.getControlClass()"
:role="question.ariaRole"
:aria-required="question.ariaRequired"
:aria-label="question.ariaLabel"
:aria-invalid="question.ariaInvalid"
:aria-describedby="question.ariaDescribedBy"
:aria-expanded="question.ariaExpanded"
:aria-controls="model.listElementId"
:aria-activedescendant="model.ariaActivedescendant"
:required="question.isRequired"
>
<div :class="question.cssClasses.controlValue">
<sv-tagbox-item
v-for="(item, index) in question.selectedChoices"
:item="item"
:question="question"
:key="'item' + index"
></sv-tagbox-item>
<sv-tagbox-filter :model="model" :question="question"></sv-tagbox-filter>
</div>
<div
:class="question.cssClasses.cleanButton"
v-if="question.allowClear && question.cssClasses.cleanButtonIconId"
v-show="!question.isEmpty()"
@click="clear"
>
<sv-svg-icon
:class="question.cssClasses.cleanButtonSvg"
:iconName="question.cssClasses.cleanButtonIconId"
:title="question.clearCaption"
size="auto"
>
</sv-svg-icon>
</div>
</div>
<sv-popup v-if="!question.isReadOnly" :model="model.popupModel"></sv-popup>
<div disabled v-else :id="question.inputId" :class="question.getControlClass()">
<div>{{ question.readOnlyText }}</div>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { BaseVue } from "../../base";
import { DropdownMultiSelectListModel, QuestionTagboxModel } from "survey-core";
export default defineComponent({
props: {
question: QuestionTagboxModel,
},
mixins: [BaseVue],
name: "sv-tagbox",
data: (vm: any) => {
return {
inputElement: undefined,
getModel: () => {
return vm.question.dropdownListModel;
},
};
},
computed: {
model() {
return this.question.dropdownListModel;
},
},
methods: {
inputChange(event: any) {
this.model.filterString = event.target.value;
},
click(event: any) {
this.question.dropdownListModel?.onClick(event);
},
clear(event: any) {
this.question.dropdownListModel?.onClear(event);
},
keyhandler(event: any) {
this.question.dropdownListModel?.keyHandler(event);
},
blur(event: any) {
this.question.dropdownListModel?.onBlur(event);
},
},
created() {
if (!this.question.dropdownListModel) {
// eslint-disable-next-line vue/no-mutating-props
this.question.dropdownListModel = new DropdownMultiSelectListModel(this.question);
}
},
});
</script>
76 changes: 76 additions & 0 deletions packages/survey-vue-ui/src/components/tagbox/TagboxFilter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<template>
<div :class="question.cssClasses.hint">
<div v-if="model.showHintPrefix" :class="question.cssClasses.hintPrefix">
<span>{{ model.hintStringPrefix }}</span>
</div>

<div :class="question.cssClasses.hintSuffixWrapper">
<survey-string
v-if="question.showSelectedItemLocText"
:locString="question.selectedItemLocText"
/>
<div v-if="model.showHintString" :class="question.cssClasses.hintSuffix">
<span style="visibility: hidden">{{ model.inputStringRendered }}</span>
<span>{{ model.hintStringSuffix }}</span>
</div>
<input
type="text"
autocomplete="off"
v-model="model.inputStringRendered"
:class="question.cssClasses.filterStringInput"
:placeholder="model.filterStringPlaceholder"
:disabled="question.isInputReadOnly"
:inputmode="model.inputMode"
:role="model.filterStringEnabled ? question.ariaRole : null"
:aria-label="question.placeholder"
:aria-expanded="question.ariaExpanded"
:aria-controls="model.listElementId"
:aria-activedescendant="model.ariaActivedescendant"
:id="question.getInputId()"
:readonly="!model.searchEnabled ? true : null"
:size="!model.inputStringRendered ? 1 : null"
@change="inputChange"
@keydown="inputKeyHandler"
@blur="blur"
@focus="focus"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { BaseVue } from "../../base";
import { DropdownMultiSelectListModel, QuestionTagboxModel } from "survey-core";
export default defineComponent({
props: {
model: DropdownMultiSelectListModel,
question: QuestionTagboxModel,
},
mixins: [BaseVue],
name: "sv-tagbox-filter",
data: (vm: any) => {
return {
inputElement: undefined,
getModel: () => {
return vm.model;
},
};
},
methods: {
inputChange(event: any) {
// eslint-disable-next-line vue/no-mutating-props
this.model.inputStringRendered = event.target.value;
},
inputKeyHandler(event: any) {
this.model.inputKeyHandler(event);
},
blur(event: any) {
this.model.onBlur(event);
},
focus(event: any) {
this.model.onFocus(event);
},
},
});
</script>
43 changes: 43 additions & 0 deletions packages/survey-vue-ui/src/components/tagbox/TagboxItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<template>
<div class="sv-tagbox__item" :key="item.key">
<div class="sv-tagbox__item-text">
<survey-string :locString="item.locText" />
</div>
<div v-bind:class="question.cssClasses.cleanItemButton" v-on:click="removeItem">
<sv-svg-icon
v-bind:class="question.cssClasses.cleanItemButtonSvg"
:iconName="question.cssClasses.cleanItemButtonIconId"
:size="'auto'"
></sv-svg-icon>
</div>
</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { BaseVue } from "../../base";
import { ItemValue, QuestionTagboxModel } from "survey-core";
export default defineComponent({
props: {
item: ItemValue,
question: QuestionTagboxModel,
},
mixins: [BaseVue],
name: "sv-tagbox-item",
data: (vm: any) => {
return {
inputElement: undefined,
getModel: () => {
return vm.item;
},
};
},
methods: {
removeItem(event: any) {
this.question.dropdownListModel.deselectItem(this.item.value);
event.stopPropagation();
}
},
});
</script>
8 changes: 8 additions & 0 deletions packages/survey-vue-ui/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import ImagePickerItem from "./ImagepickerItem.vue";
import Comment from "./Comment.vue";
import Dropdown from "./Dropdown.vue";
import DropdownInput from "./components/dropdown/Dropdown.vue";
import Tagbox from "./Tagbox.vue";
import TagboxInput from "./components/tagbox/Tagbox.vue";
import TagboxFilter from "./components/tagbox/TagboxFilter.vue";
import TagboxItem from "./components/tagbox/TagboxItem.vue";

import Errors from "./Errors.vue";
import QuestionComment from "./QuestionComment.vue";
Expand Down Expand Up @@ -83,6 +87,10 @@ app.component("survey-imagepicker-item", ImagePickerItem);
app.component("survey-comment", Comment);
app.component("survey-dropdown", Dropdown);
app.component("sv-dropdown", DropdownInput);
app.component("survey-tagbox", Tagbox);
app.component("sv-tagbox", TagboxInput);
app.component("sv-tagbox-item", TagboxItem);
app.component("sv-tagbox-filter", TagboxFilter);

app.component("sv-components-container", Container);
app.component("sv-progress-pages", Progress);
Expand Down

0 comments on commit 2121753

Please sign in to comment.