diff --git a/README.md b/README.md
index ec5de6dd..b1bc27ee 100644
--- a/README.md
+++ b/README.md
@@ -123,6 +123,12 @@ export default class EmeisOptionsService extends Service {
{
slug: "test-input-2",
label: "some.translation.key",
+ options: [ // insert a static list of options (value, label), or a (async) function which resolves to a list of options
+ {
+ value: "option-1",
+ label: "Option one"
+ }
+ ],
type: "choice",
visible: () => true,
readOnly: false
@@ -134,15 +140,19 @@ export default class EmeisOptionsService extends Service {
_Watch out_ - the translation key has to be present in your local translation files.
-There are special options available for `type` and `visible` properties.
+There are special options available for `options`, `type` and `visible` properties.
#### **type** - meta field
Defines the type of the output component and can either be a _text_ or a _choice_.
+#### **options** - meta field
+
+In combination with `type:"choice"` the options can be a list of options (`{value, label}`) or a (async) function which resolves to a list of options.
+
#### **visible** & **readOnly** meta field
-Accepts a boolean value for static visibility or a function which evaluates to a boolean value. Submitted functions will evaluate live while rendering.
+Accepts a boolean value for static visibility or a (async) function which evaluates to a boolean value. Submitted functions will evaluate live while rendering.
The evaluation function will receive the current model as argument. For instance if you are on the scope route, you will receive the [scope model](addon/models/scope.js) as first argument. Same for [user](addon/models/user.js) | [role](addon/models/role.js) | [permission](addon/models/permission.js)
diff --git a/addon/components/meta-field.hbs b/addon/components/meta-field.hbs
new file mode 100644
index 00000000..dbaced46
--- /dev/null
+++ b/addon/components/meta-field.hbs
@@ -0,0 +1,32 @@
+{{#if this.visible.value}}
+
+ {{#if (eq @field.type "choice")}}
+ {{#if this.options.isRunning}}
+
+ {{else}}
+
+ {{optional-translate option.label}}
+
+ {{/if}}
+ {{/if}}
+ {{#if (eq @field.type "text")}}
+
+ {{/if}}
+
+{{/if}}
\ No newline at end of file
diff --git a/addon/components/meta-field.js b/addon/components/meta-field.js
new file mode 100644
index 00000000..dafd4bb9
--- /dev/null
+++ b/addon/components/meta-field.js
@@ -0,0 +1,60 @@
+import { assert } from "@ember/debug";
+import { action } from "@ember/object";
+import { inject as service } from "@ember/service";
+import Component from "@glimmer/component";
+import { task } from "ember-concurrency";
+import { useTask } from "ember-resources";
+
+export default class MetaFieldComponent extends Component {
+ @service intl;
+
+ constructor(...args) {
+ super(...args);
+
+ assert("Must pass a valid field argument", this.args.field);
+ assert("Must pass a valid model argument", this.args.model);
+ }
+
+ async evaluateToBoolean(expression) {
+ if (typeof expression === "boolean") {
+ return expression;
+ }
+ if (typeof expression === "function") {
+ return await expression(this.args.model);
+ }
+ if (typeof expression === "string") {
+ return expression === "true";
+ }
+ return false;
+ }
+
+ visible = useTask(this, this.evalVisible, () => [this.args.field.visible]);
+ readOnly = useTask(this, this.evalReadOnly, () => [this.args.field.readOnly]);
+ options = useTask(this, this.evalOptions, () => [this.args.field.options]);
+
+ @task
+ *evalVisible(visible) {
+ return yield this.evaluateToBoolean(visible);
+ }
+
+ @task
+ *evalReadOnly(readOnly) {
+ return yield this.evaluateToBoolean(readOnly);
+ }
+
+ @task
+ *evalOptions(options) {
+ // options may be a (async) function or a complex property
+ if (typeof options !== "function") {
+ return options;
+ }
+ return yield options(this.args.model);
+ }
+
+ @action
+ updateMetaField(field, model, optionOrEvent) {
+ const value = optionOrEvent?.target?.value ?? optionOrEvent?.value;
+ model.metainfo = { ...model.metainfo, [field.slug]: value };
+ model.notifyPropertyChange("metainfo");
+ }
+}
diff --git a/addon/components/meta-fields.hbs b/addon/components/meta-fields.hbs
deleted file mode 100644
index fb4421c8..00000000
--- a/addon/components/meta-fields.hbs
+++ /dev/null
@@ -1,30 +0,0 @@
-{{#each @fields as |field|}}
- {{#if (eval-meta field.visible @model)}}
-
- {{#if (eq field.type "choice")}}
-
- {{optional-translate option.label}}
-
- {{/if}}
- {{#if (eq field.type "text")}}
-
- {{/if}}
-
- {{/if}}
-{{/each}}
diff --git a/addon/components/meta-fields.js b/addon/components/meta-fields.js
deleted file mode 100644
index a7bba2ea..00000000
--- a/addon/components/meta-fields.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { action } from "@ember/object";
-import { inject as service } from "@ember/service";
-import Component from "@glimmer/component";
-
-export default class EditFormComponent extends Component {
- @service intl;
-
- @action
- updateMetaField(field, model, optionOrEvent) {
- const value = optionOrEvent?.target?.value ?? optionOrEvent?.value;
- model.metainfo = { ...model.metainfo, [field.slug]: value };
- model.notifyPropertyChange("metainfo");
- }
-}
diff --git a/addon/helpers/eval-meta.js b/addon/helpers/eval-meta.js
deleted file mode 100644
index 4f746d0a..00000000
--- a/addon/helpers/eval-meta.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { helper } from "@ember/component/helper";
-
-export default helper(function evalMeta([expression, model]) {
- if (typeof expression === "boolean") return expression;
- if (typeof expression === "function") return expression(model);
- if (typeof expression === "string") return expression === "true";
- return false;
-});
diff --git a/addon/templates/scopes/edit.hbs b/addon/templates/scopes/edit.hbs
index c6c7686f..8c9d8c36 100644
--- a/addon/templates/scopes/edit.hbs
+++ b/addon/templates/scopes/edit.hbs
@@ -38,10 +38,10 @@
-
+ {{#each this.metaFields as |field|}}
+
+ {{/each}}
+