Skip to content

Commit 3a25325

Browse files
committed
feat: array is now also nillable
1 parent 1aa7ebf commit 3a25325

File tree

3 files changed

+105
-187
lines changed

3 files changed

+105
-187
lines changed

api-property-form-item.js

Lines changed: 66 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,15 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
8787
}
8888

8989
_enumTemplate() {
90-
const { model, name, readOnly, disabled, value, outlined, legacy } = this;
90+
const { model, name, readOnly, disabled, value, outlined, legacy, _nilEnabled } = this;
9191
const values = model.schema.enum || [];
9292
return html`
9393
<anypoint-dropdown-menu
9494
name="${name}"
95-
?required="${model.required}"
95+
?required="${!_nilEnabled && model.required}"
9696
autovalidate
9797
data-type="enum"
98-
?disabled="${readOnly || disabled}"
98+
?disabled="${readOnly || disabled || _nilEnabled}"
9999
?outlined="${outlined}"
100100
?legacy="${legacy}">
101101
<label slot="label">${model.schema.inputLabel}</label>
@@ -111,15 +111,15 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
111111
}
112112

113113
_booleanTemplate() {
114-
const { model, name, readOnly, disabled, value, outlined, legacy } = this;
114+
const { model, name, readOnly, disabled, value, outlined, legacy, _nilEnabled } = this;
115115
const bindValue = (value === true || value === 'true') ? 'true' : 'false';
116116
return html`
117117
<anypoint-dropdown-menu
118118
name="${name}"
119-
?required="${model.required}"
119+
?required="${!_nilEnabled && model.required}"
120120
autovalidate
121121
data-type="boolean"
122-
?disabled="${readOnly || disabled}"
122+
?disabled="${readOnly || disabled || _nilEnabled}"
123123
?outlined="${outlined}"
124124
?legacy="${legacy}">
125125
<label slot="label">${model.schema.inputLabel}</label>
@@ -136,7 +136,7 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
136136
}
137137

138138
_inputTemplate() {
139-
const { model, name, noLabelFloat, readOnly, disabled, value, outlined, legacy } = this;
139+
const { model, name, noLabelFloat, readOnly, disabled, value, outlined, legacy, _nilEnabled } = this;
140140
if (!model) {
141141
return;
142142
}
@@ -145,7 +145,7 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
145145
}
146146
return html`<anypoint-input
147147
.value="${value}"
148-
?required="${model.required}"
148+
?required="${!_nilEnabled && model.required}"
149149
.pattern="${model.schema.pattern}"
150150
.name="${name}"
151151
autovalidate
@@ -157,17 +157,18 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
157157
.placeholder="${model.schema.inputPlaceholder}"
158158
?nolabelfloat="${noLabelFloat}"
159159
?readonly="${readOnly}"
160-
?disabled="${disabled}"
160+
?disabled="${disabled || _nilEnabled}"
161161
?outlined="${outlined}"
162162
?legacy="${legacy}"
163163
data-type="input"
164-
@input="${this._inputHandler}">
164+
@input="${this._inputHandler}"
165+
invalidmessage="${`${name} did not pass validation`}">
165166
<label slot="label">${model.schema.inputLabel}</label>
166167
</anypoint-input>`;
167168
}
168169

169170
_arrayTemplate() {
170-
const { model, name, readOnly, disabled, _arrayValue, outlined, legacy } = this;
171+
const { model, name, readOnly, disabled, _arrayValue, outlined, legacy, _nilEnabled } = this;
171172
const values = _arrayValue || [];
172173
const itemLabel = model.schema.inputLabel || 'Parameter value';
173174
return html`
@@ -177,7 +178,7 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
177178
<div class="array-item">
178179
<anypoint-input
179180
.value="${item.value}"
180-
?required="${model.required}"
181+
?required="${!_nilEnabled && model.required}"
181182
.pattern="${model.schema.pattern}"
182183
.name="${name}"
183184
autovalidate
@@ -188,12 +189,13 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
188189
.minLength="${model.schema.minLength}"
189190
nolabelfloat
190191
?readonly="${readOnly}"
191-
?disabled="${disabled}"
192+
?disabled="${disabled || _nilEnabled}"
192193
?outlined="${outlined}"
193194
?legacy="${legacy}"
194195
data-type="array"
195196
data-index="${index}"
196-
@input="${this._arrayValueHandler}">
197+
@input="${this._arrayValueHandler}"
198+
invalidmessage="${`${name} did not pass validation`}">
197199
<label slot="label">${itemLabel}<label>
198200
</anypoint-input>
199201
${index ? html`<anypoint-icon-button
@@ -222,15 +224,15 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
222224
}
223225

224226
render() {
225-
const { readOnly, disabled, _isEnum, _isBoolean, _isInput, _isArray, _renderNillable } = this;
227+
const { readOnly, disabled, _isEnum, _isBoolean, _isInput, _isArray, _isNillable } = this;
226228
return html`
227229
<div class="content">
228230
${_isEnum ? this._enumTemplate() : undefined}
229231
${_isBoolean ? this._booleanTemplate() : undefined}
230232
${_isInput ? this._inputTemplate() : undefined}
231233
${_isArray ? this._arrayTemplate() : undefined}
232234
233-
${_renderNillable ? html`<anypoint-checkbox
235+
${_isNillable ? html`<anypoint-checkbox
234236
?disabled="${readOnly || disabled}"
235237
class="nil-option"
236238
@checked-changed="${this._nillableChanged}">Nil</anypoint-checkbox>` : undefined}
@@ -272,10 +274,8 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
272274
// Computed value, True if current item is an array object
273275
_isArray: { type: Boolean },
274276
// Computed value, True if current item is an union with nill value.
275-
_isNillable: {
276-
type: Boolean,
277-
reflectToAttribute: true
278-
},
277+
_isNillable: { type: Boolean },
278+
_nilEnabled: { type: Boolean },
279279
// Computed value, True if current item is a boolean value
280280
_isBoolean: { type: Boolean },
281281
// A value of an array item (only if `isArray` is set)
@@ -291,9 +291,7 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
291291
/**
292292
* When set the editor renders form controls disabled.
293293
*/
294-
disabled: { type: Boolean },
295-
// Computed value, renders nillable switch when needed.
296-
_renderNillable: { type: Boolean }
294+
disabled: { type: Boolean }
297295
};
298296
}
299297

@@ -347,7 +345,6 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
347345
return;
348346
}
349347
this.__isArray = value;
350-
this._renderNillable = this._computeRenderNillable(this._isNillable, value);
351348
this._isArrayChanged(value, this.value);
352349
if (value) {
353350
this.setAttribute('isarray', '');
@@ -367,7 +364,6 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
367364
return;
368365
}
369366
this.__isNillable = value;
370-
this._renderNillable = this._computeRenderNillable(value, this._isArray);
371367
if (value) {
372368
this.setAttribute('isnillable', '');
373369
} else {
@@ -525,62 +521,64 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
525521
}
526522
return !!m.value;
527523
}
528-
524+
/**
525+
* Returns input(s) depending on model type.
526+
* @return {Element|NodeList|undefined} Returns an element for input, enum, and
527+
* boolean types. Returns NodeList for array type. Returns undefined when model is not set
528+
* or DOM is not ready.
529+
*/
530+
_getInputElement() {
531+
if (this._isInput) {
532+
return this.shadowRoot.querySelector('anypoint-input[data-type="input"]');
533+
}
534+
if (this._isBoolean) {
535+
return this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="boolean"]');
536+
}
537+
if (this._isEnum) {
538+
return this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="enum"]');
539+
}
540+
if (this._isArray) {
541+
return this.shadowRoot.querySelectorAll('anypoint-input[data-type="array"]');
542+
}
543+
}
544+
/**
545+
* Overrides `ValidatableMixin._getValidity`.
546+
* If the element is set to be `NIL` value it always returns true.
547+
* Otherwise it calls `_getInputsValidity()` for input validation result.
548+
* @return {Boolean} Validation result
549+
*/
529550
_getValidity() {
530551
if (this._nilEnabled) {
531552
return true;
532553
}
533-
switch (true) {
534-
case this._isInput:
535-
{
536-
const input = this.shadowRoot.querySelector('anypoint-input[data-type="input"]');
537-
return input ? input.validate() : this._defaultValidator();
538-
}
539-
case this._isBoolean:
540-
{
541-
const bool = this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="boolean"]');
542-
return bool ? bool.validate() : this._defaultValidator();
543-
}
544-
case this._isEnum:
545-
{
546-
const en = this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="enum"]');
547-
return en ? en.validate() : this._defaultValidator();
548-
}
549-
case this._isArray:
550-
{
551-
const inputs = this.shadowRoot.querySelectorAll('anypoint-input[data-type="array"]');
552-
for (let i = 0; i < inputs.length; i++) {
553-
if (!inputs[i].validate()) {
554-
return false;
555-
}
556-
}
557-
return true;
558-
}
559-
default:
560-
return this._defaultValidator();
561-
}
554+
return this._getInputsValidity();
562555
}
563556
/**
564-
* Computes value for `_renderNillable` property.
565-
*
566-
* @param {Boolean} isNillable
567-
* @param {Boolean} isArray
557+
* Validates the inputs and returns validation state.
568558
* @return {Boolean}
569559
*/
570-
_computeRenderNillable(isNillable, isArray) {
571-
return !!isNillable && !isArray;
560+
_getInputsValidity() {
561+
const node = this._getInputElement();
562+
if (!node) {
563+
return this._defaultValidator();
564+
}
565+
if (this._isArray) {
566+
for (let i = 0; i < node.length; i++) {
567+
if (!node[i].validate()) {
568+
return false;
569+
}
570+
}
571+
return true;
572+
}
573+
return node.validate();
572574
}
573575
/**
574576
* Controls value and input state when "nil" checkbox's value change.
575577
* @param {CustomEvent} e
576578
*/
577-
_nillableChanged(e) {
579+
async _nillableChanged(e) {
578580
const { value } = e.detail;
579581
this._nilEnabled = value;
580-
const input = this._getInput();
581-
if (input) {
582-
input.disabled = value;
583-
}
584582
if (value) {
585583
this._oldNilValue = this.value;
586584
this.value = 'nil';
@@ -592,37 +590,8 @@ class ApiPropertyFormItem extends ValidatableMixin(LitElement) {
592590
this.value = '';
593591
}
594592
}
595-
}
596-
/**
597-
* Finds input element in the DOM
598-
* @return {Element|undefined} An element that represents the main UI input
599-
* element or undefined for array types.
600-
*/
601-
_getInput() {
602-
if (this._isEnum) {
603-
return this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="enum"]');
604-
}
605-
if (this._isBoolean) {
606-
return this.shadowRoot.querySelector('anypoint-dropdown-menu[data-type="boolean"]');
607-
}
608-
if (this._isInput) {
609-
return this.shadowRoot.querySelector('anypoint-input[data-type="input"]');
610-
}
611-
}
612-
/**
613-
* Computes value for anypoint-input's always-float-label attribute.
614-
* It forces label float for some types of inputs.
615-
* @param {Boolean} inputFloatLabel
616-
* @param {String} inputType
617-
* @return {Boolean}
618-
*/
619-
_computeAlwaysFloatLabel(inputFloatLabel, inputType) {
620-
if (inputFloatLabel) {
621-
return inputFloatLabel;
622-
}
623-
return [
624-
'date', 'datetime', 'datetime-local', 'month', 'time', 'week', 'file'
625-
].indexOf(inputType) !== -1;
593+
await this.updateComplete;
594+
this._getInputsValidity();
626595
}
627596

628597
_listSelectionHandler(e) {

demo/index.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ class ComponentDemo extends ArcDemoPage {
1919

2020
this.readOnly = false;
2121
this.v1 = 'Value';
22-
this.m1 = {schema: {inputLabel: 'Enter value'}};
23-
this.m2 = {schema: {inputLabel: 'Enter value', pattern: '[a-zA-Z0-9_]*'}};
24-
this.m3 = {schema: {inputLabel: 'Enter value'}, required: true};
25-
this.m4 = {schema: {
22+
this.m1 = { schema: { inputLabel: 'Enter value' } };
23+
this.m2 = { schema: { inputLabel: 'Enter value', pattern: '[a-zA-Z0-9_]*' } };
24+
this.m3 = { schema: { inputLabel: 'Enter value' }, required: true };
25+
this.m4 = { schema: {
2626
inputLabel: 'Enter value',
2727
inputPlaceholder: 'This is the placeholder',
2828
inputFloatLabel: true
29-
}};
30-
this.m5 = {schema: {
29+
} };
30+
this.m5 = { schema: {
3131
inputLabel: 'Enter number value',
3232
inputType: 'number',
3333
minimum: 1,
3434
maximum: 100
35-
}};
36-
this.m6 = {schema: {inputLabel: 'Select date', inputType: 'date'}};
35+
} };
36+
this.m6 = { schema: { inputLabel: 'Select date', inputType: 'date' } };
3737
this.m7 = {
3838
required: true,
3939
schema: {
@@ -42,15 +42,16 @@ class ComponentDemo extends ArcDemoPage {
4242
enum: ['apple', 'banana', 'cherries', 'grapes', 'lemon', 'orange', 'pear', 'watermelon']
4343
}
4444
};
45-
this.m8 = {required: true, schema: {inputLabel: 'Select boolean value', isBool: true}};
45+
this.m8 = { required: true, schema: { inputLabel: 'Select boolean value', isBool: true } };
4646
this.m9 = {
4747
required: true,
4848
schema: {
4949
inputLabel: 'Enter values',
5050
isArray: true,
5151
inputType: 'text',
5252
minLength: 2,
53-
maxLength: 20
53+
maxLength: 20,
54+
isNillable: true
5455
}
5556
};
5657
this.m10 = {

0 commit comments

Comments
 (0)