ember-validated-form 5.1.0 → 5.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [5.2.2](https://github.com/adfinis-sygroup/ember-validated-form/compare/v5.2.1...v5.2.2) (2022-02-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * select support for plain options ([#747](https://github.com/adfinis-sygroup/ember-validated-form/issues/747)) ([a58e26d](https://github.com/adfinis-sygroup/ember-validated-form/commit/a58e26ddcd46ec5328c3bb5351bafc7781eacdbd))
7
+
8
+ ## [5.2.1](https://github.com/adfinis-sygroup/ember-validated-form/compare/v5.2.0...v5.2.1) (2022-02-09)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * respect scrollErrorIntoView for validated buttons as well ([#743](https://github.com/adfinis-sygroup/ember-validated-form/issues/743)) ([fd6be2a](https://github.com/adfinis-sygroup/ember-validated-form/commit/fd6be2a49c5f947bfcf5eb3f7ab61a23ac00064a))
14
+
15
+ # [5.2.0](https://github.com/adfinis-sygroup/ember-validated-form/compare/v5.1.1...v5.2.0) (2022-02-03)
16
+
17
+
18
+ ### Features
19
+
20
+ * scroll first invalid element into view ([#733](https://github.com/adfinis-sygroup/ember-validated-form/issues/733)) ([ae7c8b2](https://github.com/adfinis-sygroup/ember-validated-form/commit/ae7c8b2b160307646adf90cd09a091effa549238))
21
+ * **validated-button:** add `triggerValidations` flag ([#721](https://github.com/adfinis-sygroup/ember-validated-form/issues/721)) ([765f5f4](https://github.com/adfinis-sygroup/ember-validated-form/commit/765f5f40c9d2e5ccfca7129fb701ff3bb0ed661e))
22
+
1
23
  # [5.0.0](https://github.com/adfinis-sygroup/ember-validated-form/compare/v4.1.0...v5.0.0) (2021-10-08)
2
24
 
3
25
 
@@ -1,3 +1,4 @@
1
+ import { getOwner } from "@ember/application";
1
2
  import { action } from "@ember/object";
2
3
  import Component from "@glimmer/component";
3
4
  import { tracked } from "@glimmer/tracking";
@@ -12,6 +13,14 @@ export default class ValidatedButtonComponent extends Component {
12
13
 
13
14
  @tracked _loading;
14
15
 
16
+ constructor(...args) {
17
+ super(...args);
18
+ this.config =
19
+ getOwner(this).resolveRegistration("config:environment")[
20
+ "ember-validated-form"
21
+ ];
22
+ }
23
+
15
24
  get loading() {
16
25
  return this.args.loading || this._loading;
17
26
  }
@@ -25,6 +34,11 @@ export default class ValidatedButtonComponent extends Component {
25
34
  }
26
35
 
27
36
  event.preventDefault();
37
+
38
+ if (this.args.triggerValidations) {
39
+ this.args.markAsDirty();
40
+ }
41
+
28
42
  const model = this.args.model;
29
43
 
30
44
  if (!model || !model.validate) {
@@ -34,6 +48,12 @@ export default class ValidatedButtonComponent extends Component {
34
48
 
35
49
  await model.validate();
36
50
 
51
+ if (this.config?.features?.scrollErrorIntoView && model.errors[0]?.key) {
52
+ document
53
+ .querySelector(`[name=${model.errors[0].key}]`)
54
+ ?.scrollIntoView({ behavior: "smooth" });
55
+ }
56
+
37
57
  if (model.get("isInvalid")) {
38
58
  this.runCallback(ON_INVALID_CLICK);
39
59
  } else {
@@ -22,6 +22,7 @@
22
22
  loading=this.loading
23
23
  label="Action"
24
24
  model=@model
25
+ markAsDirty=this.markAsDirty
25
26
  )
26
27
  )
27
28
  }}
@@ -1,3 +1,4 @@
1
+ import { getOwner } from "@ember/application";
1
2
  import { action } from "@ember/object";
2
3
  import { scheduleOnce } from "@ember/runloop";
3
4
  import Component from "@glimmer/component";
@@ -14,6 +15,10 @@ export default class ValidatedFormComponent extends Component {
14
15
 
15
16
  constructor(...args) {
16
17
  super(...args);
18
+ this.config =
19
+ getOwner(this).resolveRegistration("config:environment")[
20
+ "ember-validated-form"
21
+ ];
17
22
 
18
23
  if (this.args.model && this.args.model.validate) {
19
24
  scheduleOnce("actions", this, "validateModel", this.args.model);
@@ -24,6 +29,11 @@ export default class ValidatedFormComponent extends Component {
24
29
  model.validate();
25
30
  }
26
31
 
32
+ @action
33
+ markAsDirty() {
34
+ this.submitted = true;
35
+ }
36
+
27
37
  @action
28
38
  async submit(event) {
29
39
  event.preventDefault();
@@ -39,6 +49,11 @@ export default class ValidatedFormComponent extends Component {
39
49
  await model.validate();
40
50
 
41
51
  if (model.get("isInvalid")) {
52
+ if (this.config?.features?.scrollErrorIntoView && model.errors[0]?.key) {
53
+ document
54
+ .querySelector(`[name=${model.errors[0].key}]`)
55
+ ?.scrollIntoView({ behavior: "smooth" });
56
+ }
42
57
  this.runCallback(PROP_ON_INVALID_SUBMIT);
43
58
  } else {
44
59
  this.runCallback(PROP_ON_SUBMIT);
@@ -3,8 +3,8 @@
3
3
  <input
4
4
  type="checkbox"
5
5
  class="custom-control-input
6
- {{if @isValid "is-valid"}}
7
- {{if @isInvalid "is-invalid"}}"
6
+ {{if @isValid 'is-valid'}}
7
+ {{if @isInvalid 'is-invalid'}}"
8
8
  checked={{includes option.key @value}}
9
9
  name={{@name}}
10
10
  id="{{@inputId}}-{{i}}"
@@ -1,8 +1,8 @@
1
1
  <div class="custom-control custom-checkbox">
2
2
  <input
3
3
  class="custom-control-input
4
- {{if @isValid "is-valid"}}
5
- {{if @isInvalid "is-invalid"}}"
4
+ {{if @isValid 'is-valid'}}
5
+ {{if @isInvalid 'is-invalid'}}"
6
6
  type="checkbox"
7
7
  name={{@name}}
8
8
  id={{@inputId}}
@@ -3,8 +3,8 @@
3
3
  <input
4
4
  type="radio"
5
5
  class="custom-control-input
6
- {{if @isValid "is-valid"}}
7
- {{if @isInvalid "is-invalid"}}"
6
+ {{if @isValid 'is-valid'}}
7
+ {{if @isInvalid 'is-invalid'}}"
8
8
  checked={{eq @value option.key}}
9
9
  value={{option.key}}
10
10
  name={{@name}}
@@ -2,8 +2,8 @@
2
2
  {{#if (not-eq i 0)}}<br />{{/if}}
3
3
  <label
4
4
  class="uk-form-label
5
- {{if @isValid "uk-text-success"}}
6
- {{if @isInvalid "uk-text-danger"}}"
5
+ {{if @isValid 'uk-text-success'}}
6
+ {{if @isInvalid 'uk-text-danger'}}"
7
7
  >
8
8
  <input
9
9
  type="checkbox"
@@ -1,6 +1,6 @@
1
1
  {{#let (component @labelComponent) as |Label|}}
2
2
  <Label
3
- class="{{if @isValid "uk-text-success"}} {{if @isInvalid "uk-text-danger"}}"
3
+ class="{{if @isValid 'uk-text-success'}} {{if @isInvalid 'uk-text-danger'}}"
4
4
  >
5
5
  <input
6
6
  class="uk-checkbox uk-margin-small-right"
@@ -2,8 +2,8 @@
2
2
  {{#if (not-eq i 0)}}<br />{{/if}}
3
3
  <label
4
4
  class="uk-form-label
5
- {{if @isValid "uk-text-success"}}
6
- {{if @isInvalid "uk-text-danger"}}"
5
+ {{if @isValid 'uk-text-success'}}
6
+ {{if @isInvalid 'uk-text-danger'}}"
7
7
  >
8
8
  <input
9
9
  type="radio"
@@ -20,30 +20,17 @@
20
20
  {{#each this.optionGroups as |optionGroup|}}
21
21
  <optgroup label={{optionGroup.groupName}}>
22
22
  {{#each optionGroup.options as |opt|}}
23
- {{#let
24
- (if @optionValuePath (get opt @optionValuePath) opt)
25
- as |optionValue|
26
- }}
27
- <option
28
- selected={{eq optionValue @value}}
29
- value={{optionValue}}
30
- >{{if @optionLabelPath (get opt @optionLabelPath) opt}}</option>
31
- {{/let}}
23
+ <option selected={{eq opt.id @value}} value={{opt.id}}>
24
+ {{opt.label}}
25
+ </option>
32
26
  {{/each}}
33
27
  </optgroup>
34
28
  {{/each}}
35
29
  {{else}}
36
- {{#each @options as |opt|}}
37
- {{#let
38
- (if @optionValuePath (get opt @optionValuePath) opt)
39
- as |optionValue|
40
- }}
41
- <option selected={{eq optionValue @value}} value={{optionValue}}>{{if
42
- @optionLabelPath
43
- (get opt @optionLabelPath)
44
- opt
45
- }}</option>
46
- {{/let}}
30
+ {{#each this.normalizedOptions as |opt|}}
31
+ <option selected={{eq opt.id @value}} value={{opt.id}}>
32
+ {{opt.label}}
33
+ </option>
47
34
  {{/each}}
48
35
  {{/if}}
49
36
  </select>
@@ -38,6 +38,23 @@ export default class SelectComponent extends Component {
38
38
  return this.hasPreGroupedOptions || this.args.groupLabelPath;
39
39
  }
40
40
 
41
+ get normalizedOptions() {
42
+ // normalize options to common data structure, only for rendering
43
+ return this.args.options.map((opt) => this.normalize(opt));
44
+ }
45
+
46
+ normalize(option) {
47
+ if (typeof option !== "object") {
48
+ return { id: option, label: option };
49
+ }
50
+ const valuePath = this.args.optionValuePath ?? this.args.optionTargetPath;
51
+ const labelPath = this.args.optionLabelPath;
52
+ return {
53
+ id: valuePath ? option[valuePath] : option.id,
54
+ label: labelPath ? option[labelPath] : option.label,
55
+ };
56
+ }
57
+
41
58
  get optionGroups() {
42
59
  const groupLabelPath = this.args.groupLabelPath;
43
60
  if (!groupLabelPath) {
@@ -60,7 +77,7 @@ export default class SelectComponent extends Component {
60
77
  groups.pushObject(group);
61
78
  }
62
79
 
63
- group.options.pushObject(item);
80
+ group.options.pushObject(this.normalize(item));
64
81
  } else {
65
82
  groups.pushObject(item);
66
83
  }
@@ -69,10 +86,54 @@ export default class SelectComponent extends Component {
69
86
  return groups;
70
87
  }
71
88
 
89
+ findOption(target) {
90
+ const targetPath = this.args.optionTargetPath;
91
+ const valuePath = this.args.optionValuePath || targetPath;
92
+
93
+ const getValue = (item) => {
94
+ if (valuePath) {
95
+ return String(item[valuePath]);
96
+ }
97
+ if (typeof item === "object") {
98
+ return String(item.id);
99
+ }
100
+ return String(item);
101
+ };
102
+
103
+ let options = this.args.options;
104
+
105
+ //flatten pre grouped options
106
+ if (this.hasPreGroupedOptions) {
107
+ options = options.flatMap((group) => group.options);
108
+ }
109
+
110
+ // multi select
111
+ if (this.args.multiple) {
112
+ const selectedValues = Array.prototype.filter
113
+ .call(target.options, (option) => option.selected)
114
+ .map((option) => option.value);
115
+
116
+ const foundOptions = options.filter((item) => {
117
+ return selectedValues.includes(getValue(item));
118
+ });
119
+ if (targetPath) {
120
+ return foundOptions.map((item) => item[targetPath]);
121
+ }
122
+ return foundOptions;
123
+ }
124
+
125
+ //single select
126
+ const foundOption = options.find((item) => getValue(item) === target.value);
127
+ if (targetPath) {
128
+ return foundOption[targetPath];
129
+ }
130
+ return foundOption;
131
+ }
132
+
72
133
  @action
73
134
  onUpdate(event) {
74
135
  if (this.args.update) {
75
- this.args.update(event.target.value);
136
+ this.args.update(this.findOption(event.target));
76
137
  }
77
138
  }
78
139
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-validated-form",
3
- "version": "5.1.0",
3
+ "version": "5.2.2",
4
4
  "description": "Easily create forms with client-side validations",
5
5
  "keywords": [
6
6
  "ember-addon",
@@ -33,49 +33,42 @@
33
33
  "prepare": "husky install"
34
34
  },
35
35
  "dependencies": {
36
- "ember-auto-import": "^2.2.0",
36
+ "ember-auto-import": "^2.4.0",
37
37
  "ember-cli-babel": "^7.26.6",
38
38
  "ember-cli-htmlbars": "^5.7.1",
39
39
  "ember-truth-helpers": "^3.0.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@adfinis-sygroup/eslint-config": "1.5.0",
43
- "@adfinis-sygroup/semantic-release-config": "3.2.1",
44
- "@babel/core": "7.16.5",
45
- "@babel/helper-create-regexp-features-plugin": "^7.16.7",
46
- "@babel/helper-environment-visitor": "^7.16.5",
47
- "@babel/plugin-proposal-decorators": "^7.16.7",
48
- "@babel/plugin-transform-modules-amd": "^7.16.7",
49
- "@babel/preset-env": "^7.16.7",
43
+ "@adfinis-sygroup/semantic-release-config": "3.4.0",
50
44
  "@ember/optional-features": "2.0.0",
51
45
  "@ember/test-helpers": "2.6.0",
52
- "@embroider/test-setup": "0.45.0",
53
- "@fortawesome/ember-fontawesome": "0.2.3",
46
+ "@embroider/test-setup": "1.1.0",
47
+ "@fortawesome/ember-fontawesome": "0.3.1",
54
48
  "@fortawesome/free-solid-svg-icons": "5.15.4",
55
49
  "@glimmer/component": "1.0.4",
56
50
  "@glimmer/tracking": "1.0.4",
57
51
  "babel-eslint": "10.1.0",
58
52
  "broccoli-asset-rev": "3.0.0",
59
- "ember-changeset": "3.15.0",
60
- "ember-changeset-validations": "3.16.0",
53
+ "ember-changeset": "4.0.0-beta.2",
54
+ "ember-changeset-validations": "4.0.0-beta.2",
61
55
  "ember-cli": "3.28.1",
62
- "ember-cli-addon-docs": "4.2.1",
56
+ "ember-cli-addon-docs": "4.2.2",
63
57
  "ember-cli-dependency-checker": "3.2.0",
64
58
  "ember-cli-deploy": "1.0.2",
65
59
  "ember-cli-deploy-build": "2.0.0",
66
60
  "ember-cli-deploy-git": "1.3.4",
67
61
  "ember-cli-deploy-git-ci": "1.0.1",
68
62
  "ember-cli-inject-live-reload": "2.1.0",
69
- "ember-cli-release": "1.0.0-beta.2",
70
63
  "ember-cli-sri": "2.1.1",
71
64
  "ember-cli-terser": "4.0.2",
72
65
  "ember-cli-test-loader": "3.0.0",
73
- "ember-concurrency": "2.2.0",
66
+ "ember-concurrency": "2.2.1",
74
67
  "ember-data": "3.28.3",
75
68
  "ember-disable-prototype-extensions": "1.1.3",
76
69
  "ember-load-initializers": "2.1.2",
77
70
  "ember-maybe-import-regenerator": "1.0.0",
78
- "ember-power-select": "4.1.6",
71
+ "ember-power-select": "5.0.3",
79
72
  "ember-qunit": "5.1.5",
80
73
  "ember-resolver": "8.0.3",
81
74
  "ember-source": "3.28.1",
@@ -86,21 +79,22 @@
86
79
  "eslint": "7.32.0",
87
80
  "eslint-config-prettier": "8.3.0",
88
81
  "eslint-plugin-ember": "10.5.8",
89
- "eslint-plugin-import": "2.25.3",
82
+ "eslint-plugin-import": "2.25.4",
90
83
  "eslint-plugin-node": "11.1.0",
91
84
  "eslint-plugin-prettier": "4.0.0",
92
85
  "eslint-plugin-qunit": "6.2.0",
93
86
  "husky": "7.0.4",
94
- "lint-staged": "11.2.0",
87
+ "lint-staged": "12.3.3",
95
88
  "loader.js": "4.7.0",
96
89
  "npm-run-all": "4.1.5",
97
- "prettier": "2.4.1",
90
+ "prettier": "2.5.1",
98
91
  "qunit": "2.17.2",
99
92
  "qunit-dom": "2.0.0",
100
- "webpack": "5.58.0"
93
+ "webpack": "5.68.0"
101
94
  },
102
95
  "resolutions": {
103
- "graceful-fs": ">=4.2.0"
96
+ "@embroider/macros": "^1.1.0",
97
+ "@embroider/util": "^1.1.0"
104
98
  },
105
99
  "engines": {
106
100
  "node": "12.* || 14.* || >= 16"