diff --git a/js/components/checkbox_input.js b/js/components/checkbox_input.js index 2a1b0c89..16e1a9b6 100644 --- a/js/components/checkbox_input.js +++ b/js/components/checkbox_input.js @@ -25,6 +25,7 @@ export default { methods: { onInput: function(e) { + this.$parent.$emit('field-change') emitEvent('field-change', this, { value: e.target.checked, name: this.name, @@ -32,4 +33,10 @@ export default { }) }, }, + + computed: { + valid: function() { + return this.optional || this.isChecked + }, + }, } diff --git a/js/components/clin_fields.js b/js/components/clin_fields.js index 00ca9c45..212c607c 100644 --- a/js/components/clin_fields.js +++ b/js/components/clin_fields.js @@ -1,5 +1,4 @@ import { emitEvent } from '../lib/emitters' -import Modal from '../mixins/modal' import optionsinput from './options_input' import textinput from './text_input' import clindollaramount from './clin_dollar_amount' @@ -19,8 +18,6 @@ export default { PopDateRange, }, - mixins: [Modal], - props: { initialClinIndex: Number, initialTotal: { @@ -54,11 +51,13 @@ export default { totalAmount: this.initialTotal || 0, obligatedAmount: this.initialObligated || 0, fundingValid: fundingValidation, + removed: false, } }, mounted: function() { - this.$root.$on('field-change', this.handleFieldChange) + this.$on('field-change', this.handleFieldChange) + this.handleFieldChange() this.validateFunding() }, @@ -90,17 +89,16 @@ export default { }, handleFieldChange: function(event) { - if (this._uid === event.parent_uid) { - if (event.name.includes(TOTAL_AMOUNT)) { - this.totalAmount = parseFloat(event.value) - this.validateFunding() - } else if (event.name.includes(OBLIGATED_AMOUNT)) { - this.obligatedAmount = parseFloat(event.value) - this.validateFunding() - } else if (event.name.includes(NUMBER)) { - this.clinNumber = event.value - } + if (event && event.name.includes(TOTAL_AMOUNT)) { + this.totalAmount = parseFloat(event.value) + this.validateFunding() + } else if (event && event.name.includes(OBLIGATED_AMOUNT)) { + this.obligatedAmount = parseFloat(event.value) + this.validateFunding() + } else if (event && event.name.includes(NUMBER)) { + this.clinNumber = event.value } + this.$parent.$emit('field-change') }, removeClin: function() { @@ -108,6 +106,8 @@ export default { emitEvent('remove-clin', this, { clinIndex: this.clinIndex, }) + this.removed = true + this.handleFieldChange() this.closeModal('remove_clin') }, }, @@ -140,5 +140,15 @@ export default { removeModalId: function() { return `remove-clin-${this.clinIndex}` }, + + valid: function() { + if (this.removed) { + // the nested component is still mounted, so valid needs to be true or the + // save button will never become active + return true + } else { + return this.$children.every(child => child.valid) + } + }, }, } diff --git a/js/components/date_selector.js b/js/components/date_selector.js index 7209b19a..70fc8f64 100644 --- a/js/components/date_selector.js +++ b/js/components/date_selector.js @@ -210,6 +210,10 @@ export default { dateParsed: function() { return Date.UTC(this.year, this.month - 1, this.day) }, + + valid: function() { + return this.isDateValid + }, }, methods: { @@ -220,7 +224,7 @@ export default { valid: this.isDateValid, }) - this.$emit('date-change', { + this.$parent.$emit('field-change', { value: this.formattedDate, name: this.name, valid: this.isDateValid, diff --git a/js/components/forms/to_form.js b/js/components/forms/to_form.js index 804a0fa3..b041219e 100644 --- a/js/components/forms/to_form.js +++ b/js/components/forms/to_form.js @@ -2,10 +2,7 @@ import stickybits from 'stickybits' import checkboxinput from '../checkbox_input' import ClinFields from '../clin_fields' -import DateSelector from '../date_selector' -import FormMixin from '../../mixins/form' -import optionsinput from '../options_input' -import SemiCollapsibleText from '../semi_collapsible_text' +import FormMixin from '../../mixins/form_mixin' import textinput from '../text_input' import uploadinput from '../upload_input' @@ -17,9 +14,6 @@ export default { components: { checkboxinput, ClinFields, - DateSelector, - optionsinput, - SemiCollapsibleText, textinput, uploadinput, }, @@ -58,8 +52,6 @@ export default { delete this.fields[field] } } - - this.validateForm() }, }, diff --git a/js/components/options_input.js b/js/components/options_input.js index 6c82b39b..06bb73d9 100644 --- a/js/components/options_input.js +++ b/js/components/options_input.js @@ -1,11 +1,8 @@ import { emitEvent } from '../lib/emitters' -import FormMixin from '../mixins/form' export default { name: 'optionsinput', - mixins: [FormMixin], - props: { name: String, initialErrors: { @@ -48,6 +45,7 @@ export default { this.showValid = true this.value = e.target.value + this.$parent.$emit('field-change') emitEvent('field-change', this, { value: e.target.value, name: this.name, @@ -60,4 +58,10 @@ export default { return this.optional || value !== this.nullOption }, }, + + computed: { + valid: function() { + return this._isValid(this.value) + }, + }, } diff --git a/js/components/pop_date_range.js b/js/components/pop_date_range.js index e0370866..525a7cb9 100644 --- a/js/components/pop_date_range.js +++ b/js/components/pop_date_range.js @@ -50,8 +50,12 @@ export default { } }, + mounted: function() { + this.$on('field-change', this.handleFieldChange) + }, + methods: { - handleDateChange: function(event) { + handleFieldChange: function(event) { if (event.name.includes(START_DATE) && event.valid) { let date = new Date(event.value) this.minEndDate = this.calcMinEndDate(date) @@ -59,6 +63,7 @@ export default { let date = new Date(event.value) this.maxStartDate = this.calcMaxStartDate(date) } + this.$parent.$emit('field-change') }, calcMaxStartDate: function(date) { @@ -86,5 +91,9 @@ export default { minEndProp: function() { return format(this.minEndDate, 'YYYY-MM-DD') }, + + valid: function() { + return this.$children.every(child => child.valid) + }, }, } diff --git a/js/components/upload_input.js b/js/components/upload_input.js index 3e9e6d63..c2108a2f 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -1,20 +1,8 @@ -import { emitEvent } from '../lib/emitters' -import FormMixin from '../mixins/form' -import textinput from './text_input' -import optionsinput from './options_input' - import { buildUploader } from '../lib/upload' export default { name: 'uploadinput', - mixins: [FormMixin], - - components: { - textinput, - optionsinput, - }, - props: { name: String, filename: { @@ -25,15 +13,8 @@ export default { }, initialErrors: { type: Boolean, - }, - watch: { - type: Boolean, default: false, }, - optional: { - type: Boolean, - default: true, - }, portfolioId: { type: String, }, @@ -51,12 +32,6 @@ export default { }, created: async function() { - emitEvent('field-mount', this, { - optional: this.optional, - name: this.name, - valid: this.hasAttachment, - }) - if (this.hasInitialData) { this.downloadLink = await this.getDownloadLink( this.filename, @@ -93,12 +68,7 @@ export default { this.changed = true - emitEvent('field-change', this, { - value: e.target.value, - name: this.name, - watch: this.watch, - valid: this.hasAttachment, - }) + this.$parent.$emit('field-change') }, removeAttachment: function(e) { e.preventDefault() @@ -110,11 +80,7 @@ export default { this.clearErrors() this.changed = true - emitEvent('field-change', this, { - value: e.target.value, - name: this.name, - watch: this.watch, - }) + this.$parent.$emit('field-change') }, clearErrors: function() { this.uploadError = false @@ -144,9 +110,6 @@ export default { return this.attachment.split(/[\\/]/).pop() } }, - hasAttachment: function() { - return !!this.attachment - }, hideInput: function() { return this.hasInitialData && !this.changed }, @@ -157,5 +120,8 @@ export default { this.sizeError ) }, + valid: function() { + return !!this.attachment + }, }, } diff --git a/js/mixins/form.js b/js/mixins/form.js index e5f2ddbe..87f5a044 100644 --- a/js/mixins/form.js +++ b/js/mixins/form.js @@ -13,10 +13,12 @@ export default { mounted: function() { this.$root.$on('field-change', this.handleFieldChange) + this.$on('field-change', this.handleFieldChange) }, created: function() { this.$root.$on('field-mount', this.handleFieldMount) + this.$on('field-mount', this.handleFieldMount) }, methods: { diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js new file mode 100644 index 00000000..45aa6261 --- /dev/null +++ b/js/mixins/form_mixin.js @@ -0,0 +1,54 @@ +export default { + props: { + initialSelectedSection: String, + hasChanges: { + type: Boolean, + default: false, + }, + enableSave: { + type: Boolean, + default: false, + }, + }, + + data: function() { + return { + changed: this.hasChanges, + valid: false, + } + }, + + mounted: function() { + this.$on('field-change', this.handleFieldChange) + this.valid = this.validateFields() + }, + + methods: { + handleFieldChange: function(event) { + this.valid = this.validateFields() + this.changed = true + }, + + validateFields: function() { + return this.$children.every(child => child.valid) + }, + + handleSubmit: function(event) { + if (!this.valid) { + event.preventDefault() + } + }, + }, + + computed: { + canSave: function() { + if (this.changed && this.valid) { + return true + } else if (this.enableSave && this.valid) { + return true + } else { + return false + } + }, + }, +} diff --git a/js/mixins/text_input_mixin.js b/js/mixins/text_input_mixin.js index 1e728ee7..229621f9 100644 --- a/js/mixins/text_input_mixin.js +++ b/js/mixins/text_input_mixin.js @@ -53,6 +53,10 @@ export default { rawValue: function() { return this._rawValue(this.value) }, + + valid: function() { + return this._isValid(this.value) + }, }, mounted: function() { @@ -136,6 +140,10 @@ export default { } // Emit a change event + this.$parent.$emit('field-change', { + value: this._rawValue(value), + name: this.name, + }) emitEvent('field-change', this, { value: this._rawValue(value), valid: this._isValid(value), diff --git a/templates/components/pop_date_range.html b/templates/components/pop_date_range.html index 0eea2271..e376e668 100644 --- a/templates/components/pop_date_range.html +++ b/templates/components/pop_date_range.html @@ -37,7 +37,6 @@ :name-tag="'clins-' + clinIndex + '-start_date'" {% endif %} :optional='{{ optional | string | lower }}' - v-on:date-change='handleDateChange' inline-template>
@@ -136,7 +135,6 @@ :name-tag="'clins-' + clinIndex + '-end_date'" {% endif %} :optional='{{ optional | string | lower }}' - v-on:date-change='handleDateChange' inline-template>
diff --git a/templates/components/upload_input.html b/templates/components/upload_input.html index 8f5cec3c..f1cd05f0 100644 --- a/templates/components/upload_input.html +++ b/templates/components/upload_input.html @@ -1,6 +1,6 @@ {% from "components/icon.html" import Icon %} -{% macro UploadInput(field, portfolio_id, show_label=False, watch=False) -%} +{% macro UploadInput(field, portfolio_id, show_label=False) -%}
-
+
{{ Icon("ok") }} Remove
-
+
{% if show_label %} {{ field.label }} {% endif %} @@ -28,7 +26,7 @@ {{ field.description }}

-