diff --git a/addon/lib/document.js b/addon/lib/document.js index db0213189..4ba850df0 100644 --- a/addon/lib/document.js +++ b/addon/lib/document.js @@ -95,6 +95,12 @@ export default EmberObject.extend({ } ), + rootDocument: computed("parentDocument.rootDocument", function() { + if (!this.parentDocument) return null; + + return this.parentDocument.rootDocument || this.parentDocument; + }), + questionJexl: computed(function() { const questionJexl = new jexl.Jexl(); @@ -109,6 +115,18 @@ export default EmberObject.extend({ return questionJexl; }), + questionJexlContext: computed( + "raw.form.slug", + "rootDocument.raw.form.slug", + function() { + return { + rootForm: this.rootDocument + ? this.rootDocument.raw.form.slug + : this.raw.form.slug + }; + } + ), + findAnswer(slugWithPath) { const field = this.findField(slugWithPath); if (!field || !field.answer) { diff --git a/addon/lib/question.js b/addon/lib/question.js index e534aa904..46dd685a1 100644 --- a/addon/lib/question.js +++ b/addon/lib/question.js @@ -78,7 +78,11 @@ export default EmberObject.extend({ ); hidden = - hidden || (yield this.field.document.questionJexl.eval(this.isHidden)); + hidden || + (yield this.field.document.questionJexl.eval( + this.isHidden, + this.field.document.questionJexlContext + )); if (this.get("hiddenTask.lastSuccessful.value") !== hidden) { next(this, () => this.field.trigger("hiddenChanged")); @@ -114,6 +118,12 @@ export default EmberObject.extend({ (field.answer.value === null || field.answer.value === undefined)) ); - return hidden || !(yield this.document.questionJexl.eval(this.isRequired)); + return ( + hidden || + !(yield this.document.questionJexl.eval( + this.isRequired, + this.field.document.questionJexlContext + )) + ); }) }); diff --git a/tests/unit/lib/document-test.js b/tests/unit/lib/document-test.js index 74c535e54..40862f67b 100644 --- a/tests/unit/lib/document-test.js +++ b/tests/unit/lib/document-test.js @@ -158,4 +158,30 @@ module("Unit | Library | document", function(hooks) { ); } }); + + test("computes the correct root document", async function(assert) { + assert.expect(3); + + const level1 = this.nestedDocument; + const level2 = this.nestedDocument.childDocuments[0]; + const level3 = this.nestedDocument.childDocuments[0].childDocuments[0]; + + assert.equal(level3.rootDocument.id, level1.id); + assert.equal(level2.rootDocument.id, level1.id); + assert.equal(level1.rootDocument, null); + }); + + test("computes the correct jexl context", async function(assert) { + assert.expect(3); + + const level1 = this.nestedDocument; + const level2 = this.nestedDocument.childDocuments[0]; + const level3 = this.nestedDocument.childDocuments[0].childDocuments[0]; + + const rootForm = level1.raw.form.slug; + + assert.deepEqual(level3.questionJexlContext, { rootForm }); + assert.deepEqual(level2.questionJexlContext, { rootForm }); + assert.deepEqual(level1.questionJexlContext, { rootForm }); + }); }); diff --git a/tests/unit/lib/question-test.js b/tests/unit/lib/question-test.js index 0a997d4d2..0f5ab533c 100644 --- a/tests/unit/lib/question-test.js +++ b/tests/unit/lib/question-test.js @@ -157,4 +157,29 @@ module("Unit | Library | question", function(hooks) { this.question1.field.off("hiddenChanged", handler); }); + + test("form and rootForm can be used in jexl expressions", async function(assert) { + assert.expect(4); + + const rootDocument = this.nestedDocument; + const document = rootDocument.childDocuments[0].childDocuments[0]; + const question = document.fields[0].question; + + const trueExpression = `rootForm == '${rootDocument.raw.form.slug}'`; + const falseExpression = "rootForm == 'thisisalsonottheslug'"; + + question.setProperties({ + isHidden: trueExpression, + isRequired: trueExpression + }); + assert.equal(await question.hiddenTask.perform(), true); + assert.equal(await question.optionalTask.perform(), false); // optional is inverted required! + + question.setProperties({ + isHidden: falseExpression, + isRequired: falseExpression + }); + assert.equal(await question.hiddenTask.perform(), false); + assert.equal(await question.optionalTask.perform(), true); // optional is inverted required! + }); });