@projectcaluma/ember-form 10.0.2 → 11.0.0-beta.3

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +1112 -0
  2. package/addon/components/cf-content.hbs +36 -39
  3. package/addon/components/cf-content.js +48 -29
  4. package/addon/components/cf-field/info.hbs +1 -1
  5. package/addon/components/cf-field/input/action-button.hbs +1 -1
  6. package/addon/components/cf-field/input/action-button.js +9 -7
  7. package/addon/components/cf-field/input/checkbox.hbs +6 -2
  8. package/addon/components/cf-field/input/checkbox.js +9 -29
  9. package/addon/components/cf-field/input/file.hbs +1 -1
  10. package/addon/components/cf-field/input/file.js +8 -9
  11. package/addon/components/cf-field/input/float.hbs +4 -4
  12. package/addon/components/cf-field/input/integer.hbs +5 -5
  13. package/addon/components/cf-field/input/radio.hbs +4 -1
  14. package/addon/components/cf-field/input/table.hbs +7 -7
  15. package/addon/components/cf-field/input/table.js +12 -10
  16. package/addon/components/cf-field/input/text.hbs +5 -5
  17. package/addon/components/cf-field/input/textarea.hbs +6 -5
  18. package/addon/components/cf-field/input.hbs +10 -1
  19. package/addon/components/cf-field/input.js +1 -1
  20. package/addon/components/cf-field/label.hbs +1 -1
  21. package/addon/components/cf-field-value.hbs +1 -1
  22. package/addon/components/cf-field-value.js +8 -13
  23. package/addon/components/cf-field.hbs +2 -2
  24. package/addon/components/cf-field.js +2 -3
  25. package/addon/components/cf-navigation-item.hbs +2 -2
  26. package/addon/components/cf-navigation.hbs +4 -1
  27. package/addon/components/document-validity.js +1 -1
  28. package/addon/gql/fragments/field.graphql +22 -0
  29. package/addon/gql/mutations/save-document-table-answer.graphql +1 -1
  30. package/addon/gql/mutations/save-document.graphql +1 -0
  31. package/addon/gql/queries/{get-document-answers.graphql → document-answers.graphql} +2 -1
  32. package/addon/gql/queries/{get-document-forms.graphql → document-forms.graphql} +2 -1
  33. package/addon/gql/queries/{get-document-used-dynamic-options.graphql → document-used-dynamic-options.graphql} +2 -1
  34. package/addon/gql/queries/{get-dynamic-options.graphql → dynamic-options.graphql} +2 -1
  35. package/addon/gql/queries/{get-fileanswer-info.graphql → fileanswer-info.graphql} +2 -1
  36. package/addon/helpers/get-widget.js +50 -0
  37. package/addon/lib/answer.js +108 -72
  38. package/addon/lib/base.js +32 -23
  39. package/addon/lib/dependencies.js +36 -71
  40. package/addon/lib/document.js +92 -96
  41. package/addon/lib/field.js +334 -401
  42. package/addon/lib/fieldset.js +46 -47
  43. package/addon/lib/form.js +27 -15
  44. package/addon/lib/navigation.js +211 -192
  45. package/addon/lib/question.js +103 -94
  46. package/addon/services/caluma-store.js +10 -6
  47. package/app/helpers/get-widget.js +4 -0
  48. package/blueprints/@projectcaluma/ember-form/index.js +1 -0
  49. package/package.json +27 -23
  50. package/addon/components/cf-navigation.js +0 -9
@@ -3,7 +3,7 @@ import Component from "@glimmer/component";
3
3
  import { queryManager } from "ember-apollo-client";
4
4
  import moment from "moment";
5
5
 
6
- import getFileAnswerInfoQuery from "@projectcaluma/ember-form/gql/queries/get-fileanswer-info.graphql";
6
+ import getFileAnswerInfoQuery from "@projectcaluma/ember-form/gql/queries/fileanswer-info.graphql";
7
7
 
8
8
  export default class CfFieldValueComponent extends Component {
9
9
  @queryManager apollo;
@@ -11,7 +11,7 @@ export default class CfFieldValueComponent extends Component {
11
11
  get value() {
12
12
  const field = this.args.field;
13
13
 
14
- switch (field.question.__typename) {
14
+ switch (field.questionType) {
15
15
  case "ChoiceQuestion":
16
16
  case "DynamicChoiceQuestion": {
17
17
  return field.selected;
@@ -23,8 +23,8 @@ export default class CfFieldValueComponent extends Component {
23
23
  case "FileQuestion": {
24
24
  const answerValue = field.answer.value;
25
25
  return {
26
- fileAnswerId: answerValue && field.answer.id,
27
- label: answerValue && answerValue.name,
26
+ fileAnswerId: answerValue && field.answer.raw.id,
27
+ label: answerValue?.name,
28
28
  };
29
29
  }
30
30
  case "DateQuestion": {
@@ -34,22 +34,17 @@ export default class CfFieldValueComponent extends Component {
34
34
  }
35
35
 
36
36
  default:
37
- return {
38
- label: field.answer.value,
39
- };
37
+ return { label: field.answer.value };
40
38
  }
41
39
  }
42
40
 
43
41
  @action
44
- async download(fileAnswerId) {
42
+ async download(id) {
45
43
  const { downloadUrl } = await this.apollo.query(
46
- {
47
- query: getFileAnswerInfoQuery,
48
- variables: { id: fileAnswerId },
49
- fetchPolicy: "cache-and-network",
50
- },
44
+ { query: getFileAnswerInfoQuery, variables: { id } },
51
45
  "node.fileValue"
52
46
  );
47
+
53
48
  window.open(downloadUrl, "_blank");
54
49
  }
55
50
  }
@@ -16,8 +16,8 @@
16
16
  {{/let}}
17
17
  </div>
18
18
 
19
- {{#if (and @field.question.infoText this.infoTextVisible)}}
20
- <CfField::info @text={{@field.question.infoText}} />
19
+ {{#if (and @field.question.raw.infoText this.infoTextVisible)}}
20
+ <CfField::info @text={{@field.question.raw.infoText}} />
21
21
  {{/if}}
22
22
 
23
23
  {{#if this.saveIndicatorVisible}}
@@ -1,8 +1,7 @@
1
1
  import { getOwner } from "@ember/application";
2
2
  import { set } from "@ember/object";
3
3
  import Component from "@glimmer/component";
4
- import { timeout } from "ember-concurrency";
5
- import { restartableTask } from "ember-concurrency-decorators";
4
+ import { timeout, restartableTask } from "ember-concurrency";
6
5
 
7
6
  import { hasQuestionType } from "@projectcaluma/ember-core/helpers/has-question-type";
8
7
 
@@ -28,7 +27,7 @@ export default class CfFieldComponent extends Component {
28
27
 
29
28
  get labelVisible() {
30
29
  return (
31
- !this.args.field?.question.meta.hideLabel &&
30
+ !this.args.field?.question.raw.meta.hideLabel &&
32
31
  !hasQuestionType(this.args.field?.question, "static", "action-button")
33
32
  );
34
33
  }
@@ -1,6 +1,6 @@
1
1
  <li
2
2
  class="cf-navigation__item uk-width-auto
3
- {{if (or @item.active @item.childrenActive) "uk-active"}}"
3
+ {{if (or @item.active @item.childrenActive) 'uk-active'}}"
4
4
  >
5
5
  <LinkTo @query={{hash displayedForm=@item.slug}}>
6
6
  {{#if (and @useAsHeading this.active)}}
@@ -19,7 +19,7 @@
19
19
  {{/if}}
20
20
  <span
21
21
  class="cf-navigation__item__icon cf-navigation__item__icon--{{@item.state}}
22
- {{if @item.dirty "cf-navigation__item__icon--dirty"}}"
22
+ {{if @item.dirty 'cf-navigation__item__icon--dirty'}}"
23
23
  ></span>
24
24
  </LinkTo>
25
25
 
@@ -1,4 +1,7 @@
1
- <ul class="uk-tab uk-tab-left uk-width-auto" {{did-insert this.goToNextItem}}>
1
+ <ul
2
+ class="uk-tab uk-tab-left uk-width-auto"
3
+ {{did-insert @navigation.goToNextItemIfNonNavigable}}
4
+ >
2
5
  {{#each @navigation.rootItems as |item|}}
3
6
  <CfNavigationItem
4
7
  @item={{item}}
@@ -1,6 +1,6 @@
1
1
  import { action } from "@ember/object";
2
2
  import Component from "@glimmer/component";
3
- import { restartableTask } from "ember-concurrency-decorators";
3
+ import { restartableTask } from "ember-concurrency";
4
4
 
5
5
  /**
6
6
  * Component to check the validity of a document
@@ -4,6 +4,7 @@
4
4
  # When changing this file the other must also receive the same changes.
5
5
 
6
6
  fragment SimpleQuestion on Question {
7
+ id
7
8
  slug
8
9
  label
9
10
  isRequired
@@ -14,6 +15,7 @@ fragment SimpleQuestion on Question {
14
15
  textMinLength: minLength
15
16
  textMaxLength: maxLength
16
17
  textDefaultAnswer: defaultAnswer {
18
+ id
17
19
  value
18
20
  }
19
21
  placeholder
@@ -22,6 +24,7 @@ fragment SimpleQuestion on Question {
22
24
  textareaMinLength: minLength
23
25
  textareaMaxLength: maxLength
24
26
  textareaDefaultAnswer: defaultAnswer {
27
+ id
25
28
  value
26
29
  }
27
30
  placeholder
@@ -30,6 +33,7 @@ fragment SimpleQuestion on Question {
30
33
  integerMinValue: minValue
31
34
  integerMaxValue: maxValue
32
35
  integerDefaultAnswer: defaultAnswer {
36
+ id
33
37
  value
34
38
  }
35
39
  placeholder
@@ -38,6 +42,7 @@ fragment SimpleQuestion on Question {
38
42
  floatMinValue: minValue
39
43
  floatMaxValue: maxValue
40
44
  floatDefaultAnswer: defaultAnswer {
45
+ id
41
46
  value
42
47
  }
43
48
  placeholder
@@ -46,6 +51,7 @@ fragment SimpleQuestion on Question {
46
51
  choiceOptions: options {
47
52
  edges {
48
53
  node {
54
+ id
49
55
  slug
50
56
  label
51
57
  isArchived
@@ -53,6 +59,7 @@ fragment SimpleQuestion on Question {
53
59
  }
54
60
  }
55
61
  choiceDefaultAnswer: defaultAnswer {
62
+ id
56
63
  value
57
64
  }
58
65
  }
@@ -60,6 +67,7 @@ fragment SimpleQuestion on Question {
60
67
  multipleChoiceOptions: options {
61
68
  edges {
62
69
  node {
70
+ id
63
71
  slug
64
72
  label
65
73
  isArchived
@@ -67,11 +75,13 @@ fragment SimpleQuestion on Question {
67
75
  }
68
76
  }
69
77
  multipleChoiceDefaultAnswer: defaultAnswer {
78
+ id
70
79
  value
71
80
  }
72
81
  }
73
82
  ... on DateQuestion {
74
83
  dateDefaultAnswer: defaultAnswer {
84
+ id
75
85
  value
76
86
  }
77
87
  }
@@ -89,8 +99,10 @@ fragment SimpleQuestion on Question {
89
99
  }
90
100
 
91
101
  fragment FieldTableQuestion on Question {
102
+ id
92
103
  ... on TableQuestion {
93
104
  rowForm {
105
+ id
94
106
  slug
95
107
  questions {
96
108
  edges {
@@ -101,6 +113,7 @@ fragment FieldTableQuestion on Question {
101
113
  }
102
114
  }
103
115
  tableDefaultAnswer: defaultAnswer {
116
+ id
104
117
  value {
105
118
  id
106
119
  answers {
@@ -108,6 +121,7 @@ fragment FieldTableQuestion on Question {
108
121
  node {
109
122
  id
110
123
  question {
124
+ id
111
125
  slug
112
126
  }
113
127
  ... on StringAnswer {
@@ -134,10 +148,12 @@ fragment FieldTableQuestion on Question {
134
148
  }
135
149
 
136
150
  fragment FieldQuestion on Question {
151
+ id
137
152
  ...SimpleQuestion
138
153
  ...FieldTableQuestion
139
154
  ... on FormQuestion {
140
155
  subForm {
156
+ id
141
157
  slug
142
158
  name
143
159
  questions {
@@ -145,10 +161,12 @@ fragment FieldQuestion on Question {
145
161
  node {
146
162
  # This part here limits our query to 2 level deep nested forms. This
147
163
  # has to be solved in another way!
164
+ id
148
165
  ...SimpleQuestion
149
166
  ...FieldTableQuestion
150
167
  ... on FormQuestion {
151
168
  subForm {
169
+ id
152
170
  slug
153
171
  name
154
172
  questions {
@@ -171,6 +189,7 @@ fragment FieldQuestion on Question {
171
189
  fragment SimpleAnswer on Answer {
172
190
  id
173
191
  question {
192
+ id
174
193
  slug
175
194
  }
176
195
  ... on StringAnswer {
@@ -187,6 +206,7 @@ fragment SimpleAnswer on Answer {
187
206
  }
188
207
  ... on FileAnswer {
189
208
  fileValue: value {
209
+ id
190
210
  uploadUrl
191
211
  downloadUrl
192
212
  metadata
@@ -199,11 +219,13 @@ fragment SimpleAnswer on Answer {
199
219
  }
200
220
 
201
221
  fragment FieldAnswer on Answer {
222
+ id
202
223
  ...SimpleAnswer
203
224
  ... on TableAnswer {
204
225
  tableValue: value {
205
226
  id
206
227
  form {
228
+ id
207
229
  slug
208
230
  questions {
209
231
  edges {
@@ -1,6 +1,6 @@
1
1
  #import * from '../fragments/field.graphql'
2
2
 
3
- mutation saveDocumentTableAnswer($input: SaveDocumentTableAnswerInput!) {
3
+ mutation SaveDocumentTableAnswer($input: SaveDocumentTableAnswerInput!) {
4
4
  saveDocumentTableAnswer(input: $input) {
5
5
  answer {
6
6
  ...FieldAnswer
@@ -12,6 +12,7 @@ mutation SaveDocument($input: SaveDocumentInput!) {
12
12
  }
13
13
  }
14
14
  form {
15
+ id
15
16
  slug
16
17
  questions {
17
18
  edges {
@@ -1,11 +1,12 @@
1
1
  #import * from '../fragments/field.graphql'
2
2
 
3
- query GetDocumentAnswers($id: ID!) {
3
+ query DocumentAnswers($id: ID!) {
4
4
  allDocuments(filter: [{ id: $id }]) {
5
5
  edges {
6
6
  node {
7
7
  id
8
8
  form {
9
+ id
9
10
  slug
10
11
  }
11
12
  workItem {
@@ -1,9 +1,10 @@
1
1
  #import FieldQuestion, FieldTableQuestion, SimpleQuestion from '../fragments/field.graphql'
2
2
 
3
- query GetDocumentForms($slug: String!) {
3
+ query DocumentForms($slug: String!) {
4
4
  allForms(filter: [{ slug: $slug }]) {
5
5
  edges {
6
6
  node {
7
+ id
7
8
  slug
8
9
  name
9
10
  meta
@@ -1,9 +1,10 @@
1
- query GetDocumentUsedDynamicOptions($document: ID!, $question: ID!) {
1
+ query DocumentUsedDynamicOptions($document: ID!, $question: ID!) {
2
2
  allUsedDynamicOptions(
3
3
  filter: [{ document: $document }, { question: $question }]
4
4
  ) {
5
5
  edges {
6
6
  node {
7
+ id
7
8
  slug
8
9
  label
9
10
  }
@@ -1,7 +1,8 @@
1
- query GetDynamicOptions($question: String!) {
1
+ query DynamicOptions($question: String!) {
2
2
  allQuestions(filter: [{ slug: $question }], first: 1) {
3
3
  edges {
4
4
  node {
5
+ id
5
6
  slug
6
7
  ... on DynamicChoiceQuestion {
7
8
  dynamicChoiceOptions: options {
@@ -1,8 +1,9 @@
1
- query GetFileAnswerInfo($id: ID!) {
1
+ query FileAnswerInfo($id: ID!) {
2
2
  node(id: $id) {
3
3
  id
4
4
  ... on FileAnswer {
5
5
  fileValue: value {
6
+ id
6
7
  uploadUrl
7
8
  downloadUrl
8
9
  metadata
@@ -0,0 +1,50 @@
1
+ import Helper from "@ember/component/helper";
2
+ import { warn } from "@ember/debug";
3
+ import { inject as service } from "@ember/service";
4
+
5
+ /**
6
+ * Helper for getting the right widget.
7
+ *
8
+ * This helper expects n objects as positional parameters. It checks if the
9
+ * object has a widget override in it's metadata. If one exists it checks if
10
+ * said widget was registered in the caluma options service and then returns
11
+ * the widget name. If it doesn't have a valid widget, the next object will be
12
+ * checked. If no object returns a valid widget, the passed default widget will
13
+ * be used.
14
+ *
15
+ * ```hbs
16
+ * {{component (get-widget field.question someobject default="cf-form") foo=bar}}
17
+ * ```
18
+ *
19
+ * @function getWidget
20
+ * @param {Array} params
21
+ * @param {Object} [options]
22
+ * @param {String} [options.default]
23
+ */
24
+ export default class GetWidgetHelper extends Helper {
25
+ @service calumaOptions;
26
+
27
+ compute(params, { default: defaultWidget = "cf-field/input" }) {
28
+ for (const obj of params) {
29
+ const widget = obj?.raw?.meta?.widgetOverride;
30
+ if (!widget) {
31
+ continue;
32
+ }
33
+ const override =
34
+ widget &&
35
+ this.calumaOptions
36
+ .getComponentOverrides()
37
+ .find(({ component }) => component === widget);
38
+
39
+ warn(
40
+ `Widget override "${widget}" is not registered. Please register it by calling \`calumaOptions.registerComponentOverride\``,
41
+ override,
42
+ { id: "ember-caluma.unregistered-override" }
43
+ );
44
+
45
+ if (override) return widget;
46
+ }
47
+
48
+ return defaultWidget;
49
+ }
50
+ }
@@ -1,130 +1,166 @@
1
1
  import { getOwner } from "@ember/application";
2
2
  import { assert } from "@ember/debug";
3
- import { computed } from "@ember/object";
4
- import { inject as service } from "@ember/service";
5
3
  import { camelize } from "@ember/string";
6
4
  import { isEmpty } from "@ember/utils";
5
+ import { dedupeTracked, cached } from "tracked-toolbox";
7
6
 
8
7
  import { decodeId } from "@projectcaluma/ember-core/helpers/decode-id";
9
8
  import Base from "@projectcaluma/ember-form/lib/base";
10
9
  import { parseDocument } from "@projectcaluma/ember-form/lib/parsers";
11
10
 
11
+ /**
12
+ * Class that automatically defines all keys of the passed object as deduped
13
+ * tracked property and assigns the initial value.
14
+ *
15
+ * @class DedupedTrackedObject
16
+ * @private
17
+ */
18
+ class DedupedTrackedObject {
19
+ constructor(obj) {
20
+ Object.entries(obj).forEach(([key, value]) => {
21
+ Object.defineProperty(
22
+ this,
23
+ key,
24
+ dedupeTracked(this, key, { initializer: () => value })
25
+ );
26
+ });
27
+ }
28
+ }
29
+
12
30
  /**
13
31
  * Object which represents an answer in context of a field
14
32
  *
15
33
  * @class Answer
16
34
  */
17
- export default Base.extend({
18
- calumaStore: service(),
35
+ export default class Answer extends Base {
36
+ constructor({ raw, field, ...args }) {
37
+ assert("`field` must be passed as an argument", field);
19
38
 
20
- init(...args) {
21
39
  assert(
22
40
  "A graphql answer `raw` must be passed",
23
- this.raw && /Answer$/.test(this.raw.__typename)
41
+ /Answer$/.test(raw?.__typename)
24
42
  );
25
43
 
26
- if (this.raw.id) {
27
- this.set("pk", `Answer:${decodeId(this.raw.id)}`);
28
- }
44
+ super({ raw, ...args });
45
+
46
+ this.field = field;
47
+ this.raw = new DedupedTrackedObject(raw);
29
48
 
30
- this._super(...args);
49
+ this.pushIntoStore();
50
+ }
51
+
52
+ /**
53
+ * The field this answer originates from
54
+ *
55
+ * @property {Field} field
56
+ */
57
+ field = null;
58
+
59
+ /**
60
+ * The raw data of the answer. This is the only `raw` property that is tracked
61
+ * since only the answers properties are changed while rendering the form.
62
+ *
63
+ * @property {DedupedTrackedObject} raw
64
+ */
65
+ raw = {};
31
66
 
32
- this.setProperties(this.raw);
33
- },
67
+ /**
68
+ * The primary key of the answer.
69
+ *
70
+ * @property {String} pk
71
+ */
72
+ @cached
73
+ get pk() {
74
+ return this.uuid && `Answer:${this.uuid}`;
75
+ }
34
76
 
35
77
  /**
36
78
  * The uuid of the answer
37
79
  *
38
80
  * @property {String} uuid
39
- * @accessor
40
81
  */
41
- uuid: computed("raw.id", function () {
82
+ @cached
83
+ get uuid() {
42
84
  return this.raw.id ? decodeId(this.raw.id) : null;
43
- }),
85
+ }
44
86
 
45
- isNew: computed("uuid", "value", function () {
87
+ /**
88
+ * Whether the answer is new. This is true when there is no object from the
89
+ * backend or the value is empty.
90
+ *
91
+ * @property {Boolean} isNew
92
+ */
93
+ @cached
94
+ get isNew() {
46
95
  return !this.uuid || isEmpty(this.value);
47
- }),
96
+ }
48
97
 
49
98
  /**
50
99
  * The name of the property in which the value is stored. This depends on the
51
100
  * type of the answer.
52
101
  *
53
- *
54
102
  * @property {String} _valueKey
55
- * @accessor
56
103
  * @private
57
104
  */
58
- _valueKey: computed("__typename", function () {
105
+ @cached
106
+ get _valueKey() {
59
107
  return (
60
- this.__typename && camelize(this.__typename.replace(/Answer$/, "Value"))
108
+ this.raw.__typename &&
109
+ camelize(this.raw.__typename.replace(/Answer$/, "Value"))
61
110
  );
62
- }),
111
+ }
63
112
 
64
113
  /**
65
114
  * The value of the answer, the type of this value depends on the type of the
66
115
  * answer. For table answers this returns an array of documents.
67
116
  *
68
117
  * @property {String|Number|String[]|Document[]} value
69
- * @computed
70
118
  */
71
- value: computed(
72
- "field.document",
73
- "_valueKey",
74
- "dateValue",
75
- "fileValue",
76
- "floatValue",
77
- "integerValue",
78
- "listValue.[]",
79
- "stringValue",
80
- "tableValue.[]",
81
- {
82
- get() {
83
- const value = this.get(this._valueKey);
84
-
85
- if (this._valueKey === "tableValue" && value) {
86
- return value.map((document) => {
87
- const existing = this.calumaStore.find(
88
- `Document:${decodeId(document.id)}`
89
- );
90
-
91
- return (
92
- existing ||
93
- getOwner(this)
94
- .factoryFor("caluma-model:document")
95
- .create({
96
- raw: parseDocument(document),
97
- parentDocument: this.field.document,
98
- })
99
- );
100
- });
101
- }
102
-
103
- return value;
104
- },
105
- set(_, value) {
106
- value = [undefined, ""].includes(value) ? null : value;
107
-
108
- if (this._valueKey) {
109
- this.set(this._valueKey, value);
110
- }
111
-
112
- return value;
113
- },
119
+ @cached
120
+ get value() {
121
+ const value = this.raw[this._valueKey];
122
+
123
+ if (this._valueKey === "tableValue" && value) {
124
+ const owner = getOwner(this);
125
+ const Document = owner.factoryFor("caluma-model:document").class;
126
+
127
+ return value.map((document) => {
128
+ if (document instanceof Document) return document;
129
+
130
+ const existing = this.calumaStore.find(
131
+ `Document:${decodeId(document.id)}`
132
+ );
133
+
134
+ return (
135
+ existing ||
136
+ new Document({
137
+ raw: parseDocument(document),
138
+ parentDocument: this.field.document,
139
+ owner,
140
+ })
141
+ );
142
+ });
143
+ }
144
+
145
+ return value;
146
+ }
147
+
148
+ set value(value) {
149
+ if (this._valueKey) {
150
+ this.raw[this._valueKey] = [undefined, ""].includes(value) ? null : value;
114
151
  }
115
- ),
152
+ }
116
153
 
117
154
  /**
118
155
  * The value serialized for a backend request.
119
156
  *
120
157
  * @property {String|Number|String[]} serializedValue
121
- * @accessor
122
158
  */
123
- serializedValue: computed("__typename", "value", function () {
124
- if (this.__typename === "TableAnswer") {
159
+ get serializedValue() {
160
+ if (this.raw.__typename === "TableAnswer") {
125
161
  return (this.value || []).map(({ uuid }) => uuid);
126
162
  }
127
163
 
128
164
  return this.value;
129
- }),
130
- });
165
+ }
166
+ }