123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- <template>
- <div class="cube-form-item border-bottom-1px" ref="formItem" :class="itemClass">
- <template v-if="!isBtnField">
- <slot name="label">
- <div class="cube-form-label" v-show="fieldValue.label"><span>{{fieldValue.label}}</span></div>
- </slot>
- <cube-validator
- class="cube-form-field"
- v-if="hasRules"
- ref="validator"
- v-model="originValid"
- :disabled="validatorDisabled"
- :model="validatorModel"
- :model-key="validatorModelKey"
- :rules="fieldValue.rules"
- :messages="fieldValue.messages"
- @input="validatorChangeHandler"
- @validating="validatingHandler"
- @validated="validatedHandler"
- @msg-click="msgClick"
- >
- <slot>
- <component :is="componentName" v-model="modelValue" v-bind="fieldValue.props" v-on="fieldValue.events"></component>
- </slot>
- </cube-validator>
- <div class="cube-form-field" v-else>
- <slot>
- <component :is="componentName" v-model="modelValue" v-bind="fieldValue.props" v-on="fieldValue.events"></component>
- </slot>
- </div>
- </template>
- <cube-button v-bind="fieldValue.props" v-else>{{fieldValue.label}}</cube-button>
- </div>
- </template>
- <script>
- import { processField } from './fields/index'
- import { resetTypeValue, cb2PromiseWithResolve, debounce } from '../../common/helpers/util'
- import CubeValidator from '../validator/validator.vue'
- import LAYOUTS from './layouts'
- import { getResetValueByType } from './fields/reset'
- import mixin from './mixin'
- import components from './components'
- components.CubeValidator = CubeValidator
- const COMPONENT_NAME = 'cube-form-item'
- const EVENT_FOCUSIN = 'focusin'
- const EVENT_FOCUSOUT = 'focusout'
- export default {
- name: COMPONENT_NAME,
- mixins: [mixin],
- props: {
- field: {
- type: Object,
- default() {
- /* istanbul ignore next */
- return {}
- }
- }
- },
- data() {
- const validatorModelKey = 'value'
- const modelKey = this.field.modelKey
- const modelValue = modelKey ? this.form.model[modelKey] : null
- return {
- validatorDisabled: false,
- validatorModelKey,
- modelValue: modelValue,
- validatorModel: {
- [validatorModelKey]: modelValue
- }
- }
- },
- computed: {
- fieldValue() {
- return processField(this.field)
- },
- hasRules() {
- return Object.keys(this.fieldValue.rules || {}).length > 0
- },
- isBtnField() {
- return this.fieldValue.type === 'button'
- },
- itemClass() {
- const rules = this.fieldValue.rules
- return {
- // only handle required rule for now
- 'cube-form-item_required': rules && rules.required,
- 'cube-form-item_btn': this.isBtnField,
- 'cube-form-item_validating': this.validating,
- 'cube-form-item_pending': this.pending,
- 'cube-form-item_valid': this.valid,
- 'cube-form-item_invalid': this.invalid
- }
- },
- modelVal() {
- return this.form.model[this.fieldValue.modelKey]
- },
- componentName() {
- const fieldValue = this.fieldValue
- const component = fieldValue.component
- if (component) {
- return component
- }
- const type = fieldValue.type
- const cubeType = `cube-${type}`
- if (components[cubeType]) {
- return cubeType
- }
- return type
- }
- },
- watch: {
- modelVal(newModel) {
- if (this.modelValue !== newModel) {
- this.modelValue = newModel
- }
- },
- modelValue: {
- handler(newModel) {
- // update form model
- this.form.model[this.fieldValue.modelKey] = newModel
- this.updateValidatorModel()
- },
- sync: true
- },
- originValid(newVal) {
- this.lastOriginValid = newVal
- }
- },
- beforeCreate() {
- this.form = this.$parent.form
- },
- created() {
- this.form.addField(this)
- this.getValidatorModel = (modelValue) => {
- this.pending = false
- return modelValue
- }
- },
- mounted() {
- this.initDebounce()
- this.initFocusEvents()
- },
- methods: {
- initDebounce() {
- let debounceTime = this.fieldValue.debounce
- if (debounceTime === true) {
- debounceTime = 200
- }
- if ((!debounceTime && debounceTime !== 0) || debounceTime < 0 || this.fieldValue.trigger === 'blur') return
- this.getValidatorModel = debounce((modelValue) => {
- this.pending = false
- this.validatorModel[this.validatorModelKey] = modelValue
- this.form.updatePending()
- this.validate()
- return modelValue
- }, debounceTime, false, this.validatorModel[this.validatorModelKey])
- },
- focusInHandler() {
- this.focused = true
- },
- focusOutHandler() {
- this.focused = false
- this.updateValidatorModel()
- this.validate()
- },
- initFocusEvents() {
- if (this.fieldValue.trigger === 'blur') {
- const formItem = this.$refs.formItem
- formItem.addEventListener(EVENT_FOCUSIN, this.focusInHandler, false)
- formItem.addEventListener(EVENT_FOCUSOUT, this.focusOutHandler, false)
- this.getValidatorModel = (modelValue) => {
- if (this.focused) {
- return this.validatorModel[this.validatorModelKey]
- } else {
- this.pending = false
- this.form.updatePending()
- return modelValue
- }
- }
- }
- },
- removeFocusEvents() {
- const formItem = this.$refs.formItem
- formItem.removeEventListener(EVENT_FOCUSIN, this.focusInHandler, false)
- formItem.removeEventListener(EVENT_FOCUSOUT, this.focusOutHandler, false)
- },
- updateValidatorModel() {
- this.pending = true
- this.validatorModel[this.validatorModelKey] = this.getValidatorModel(this.modelValue)
- if (this.pending) {
- this.form.setPending(this.pending)
- this.originValid = undefined
- }
- },
- validatorChangeHandler() {
- // disabled or true to true no update validity
- if (this.validatorDisabled || (this.originValid && this.lastOriginValid)) {
- return
- }
- this.updateValidity()
- },
- validatingHandler() {
- this.validating = true
- this.form.setValidating(true)
- },
- validatedHandler() {
- this.validating = false
- this.form.updateValidating()
- },
- updateValidity() {
- const validator = this.$refs.validator
- if (validator) {
- // sync update validaty
- this.form.updateValidity(this.fieldValue.modelKey, validator.valid, validator.result, validator.dirty)
- }
- },
- validate(cb) {
- const promise = cb2PromiseWithResolve(cb)
- if (promise) {
- cb = promise.resolve
- }
- const validator = this.$refs.validator
- if (validator) {
- validator.validate(() => {
- this.validatorDisabled = true
- this.updateValidity()
- cb && cb()
- this.$nextTick(() => {
- this.validatorDisabled = false
- })
- })
- } else {
- cb && cb()
- }
- return promise
- },
- reset() {
- const fieldValue = this.fieldValue
- if (fieldValue.modelKey) {
- const defValue = getResetValueByType(fieldValue.type)
- this.validatorDisabled = true
- resetTypeValue(this, 'modelValue', defValue)
- this.$refs.validator && this.$refs.validator.reset()
- this.$nextTick(() => {
- this.validatorDisabled = false
- })
- }
- this.validating = false
- this.pending = false
- },
- msgClick() {
- /* istanbul ignore if */
- if (this.form.layout !== LAYOUTS.STANDARD) {
- return
- }
- /* istanbul ignore next */
- this.$createToast && this.$createToast({
- type: 'warn',
- txt: this.$refs.validator.msg,
- time: 1000
- }).show()
- }
- },
- beforeDestroy() {
- this.removeFocusEvents()
- this.form.destroyField(this)
- this.form = null
- },
- components
- }
- </script>
- <style lang="stylus" rel="stylesheet/stylus">
- @require "../../common/stylus/variable.styl"
- @require "../../common/stylus/mixin.styl"
- .cube-form-item
- position: relative
- display: flex
- align-items: center
- padding: 0 15px
- &:last-child
- &::after
- display: none
- .cube-checkbox-group, .cube-radio-group
- background-color: transparent
- .cube-checkbox, .cube-radio
- padding-left: 0
- padding-right: 0
- .cube-form-item_btn
- margin: 15px 0
- &::after
- display: none
- .cube-form-label
- display: flex
- align-items: center
- word-wrap: break-word
- word-break: break-word
- flex-shrink: 0
- .cube-form-item_required
- .cube-form-label
- &::before
- content: "*"
- display: block
- margin-top: 1px
- margin-right: .3em
- color: $form-label-required-color
- </style>
|