From 0f48c304d52353f2edd58024c6353971416102f8 Mon Sep 17 00:00:00 2001 From: Lionel Bijaoui Date: Fri, 10 Mar 2017 15:56:37 +0100 Subject: [PATCH 1/3] `radios` field now support array of string or array of objects (with `name` and `value` properties) by default. If `radiosOptions` is defined, these key can be replaced by other name, but this is no longer mandatory to use the array of object notation. --- src/fields/core/fieldRadios.vue | 49 +++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/fields/core/fieldRadios.vue b/src/fields/core/fieldRadios.vue index 7b1a5809..0acd5269 100644 --- a/src/fields/core/fieldRadios.vue +++ b/src/fields/core/fieldRadios.vue @@ -28,34 +28,41 @@ }, methods: { - onSelection(item) { - if (isObject(item) && this.schema.radiosOptions.value && item[this.schema.radiosOptions.value]){ - this.value = item[this.schema.radiosOptions.value]; - } else{ - this.value = item; - } - }, getItemValue(item) { - if (isObject(item) && this.schema.radiosOptions.value && item[this.schema.radiosOptions.value]){ - return item[this.schema.radiosOptions.value]; + if (isObject(item)){ + if (typeof this.schema["radiosOptions"] !== "undefined" && typeof this.schema["radiosOptions"]["value"] !== "undefined") { + return item[this.schema.radiosOptions.value]; + } else { + if (typeof item["value"] !== "undefined") { + return item.value + } else { + throw "value is not defined.\r If you want to use another key name, add a `value` property under `radiosOptions` in the schema.\r https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; + } + } + } else { + return item; } - - return item; }, getItemName(item) { - if (isObject(item) && this.schema.radiosOptions.name && item[this.schema.radiosOptions.name]){ - return item[this.schema.radiosOptions.name]; + if (isObject(item)){ + if (typeof this.schema["radiosOptions"] !== "undefined" && typeof this.schema["radiosOptions"]["name"] !== "undefined") { + return item[this.schema.radiosOptions.name]; + } else { + if (typeof item["name"] !== "undefined") { + return item.name + } else { + throw "name is not defined.\r If you want to use another key name, add a `name` property under `radiosOptions` in the schema.\r https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; + } + } + } else { + return item; } - - return item; + }, + onSelection(item) { + this.value = this.getItemValue(item); }, isItemChecked(item) { - let currentValue; - if (isObject(item) && this.schema.radiosOptions.value && item[this.schema.radiosOptions.value]){ - currentValue = item[this.schema.radiosOptions.value]; - } else{ - currentValue = item; - } + let currentValue = this.getItemValue(item); return (currentValue === this.value); }, } From be09146fdb3dd5d2709c068fff30874f1ed3fd76 Mon Sep 17 00:00:00 2001 From: Lionel Bijaoui Date: Fri, 10 Mar 2017 16:11:03 +0100 Subject: [PATCH 2/3] `checklist` field now support array of string or array of objects (with `name` and `value` properties instead of `name` and `id`) by default. If `checklistOptions` is defined, these key can be replaced by other name. Little change to the error message in `radios` fields. Both fields are harmonized. --- src/fields/core/fieldChecklist.vue | 53 ++++++++++++++++++++---------- src/fields/core/fieldRadios.vue | 4 +-- 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/fields/core/fieldChecklist.vue b/src/fields/core/fieldChecklist.vue index beab4172..866e4b8a 100644 --- a/src/fields/core/fieldChecklist.vue +++ b/src/fields/core/fieldChecklist.vue @@ -1,9 +1,9 @@ @@ -49,22 +49,39 @@ }, methods: { - getItemID(item) { - if (isObject(item) && item.id) - return item.id; - - return item; + getItemValue(item) { + if (isObject(item)){ + if (typeof this.schema["checklistOptions"] !== "undefined" && typeof this.schema["checklistOptions"]["value"] !== "undefined") { + return item[this.schema.checklistOptions.value]; + } else { + if (typeof item["value"] !== "undefined") { + return item.value + } else { + throw "value is not defined. If you want to use another key name, add a `value` property under `checklistOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/checklist.html#checklist-field-with-object-values"; + } + } + } else { + return item; + } }, - getItemName(item) { - if (isObject(item) && item.name) - return item.name; - - return item; + if (isObject(item)){ + if (typeof this.schema["checklistOptions"] !== "undefined" && typeof this.schema["checklistOptions"]["name"] !== "undefined") { + return item[this.schema.checklistOptions.name]; + } else { + if (typeof item["name"] !== "undefined") { + return item.name + } else { + throw "name is not defined. If you want to use another key name, add a `name` property under `checklistOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/checklist.html#checklist-field-with-object-values"; + } + } + } else { + return item; + } }, - getItemIsChecked(item) { - return (this.value && this.value.indexOf(this.getItemID(item)) != -1); + isItemChecked(item) { + return (this.value && this.value.indexOf(this.getItemValue(item)) != -1); }, onChanged(event, item) { @@ -73,9 +90,9 @@ } if (event.target.checked) { - this.value.push(this.getItemID(item)); + this.value.push(this.getItemValue(item)); } else { - this.value.splice(this.value.indexOf(this.getItemID(item)), 1); + this.value.splice(this.value.indexOf(this.getItemValue(item)), 1); } }, diff --git a/src/fields/core/fieldRadios.vue b/src/fields/core/fieldRadios.vue index 0acd5269..ff01c68d 100644 --- a/src/fields/core/fieldRadios.vue +++ b/src/fields/core/fieldRadios.vue @@ -36,7 +36,7 @@ if (typeof item["value"] !== "undefined") { return item.value } else { - throw "value is not defined.\r If you want to use another key name, add a `value` property under `radiosOptions` in the schema.\r https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; + throw "value is not defined. If you want to use another key name, add a `value` property under `radiosOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; } } } else { @@ -51,7 +51,7 @@ if (typeof item["name"] !== "undefined") { return item.name } else { - throw "name is not defined.\r If you want to use another key name, add a `name` property under `radiosOptions` in the schema.\r https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; + throw "name is not defined. If you want to use another key name, add a `name` property under `radiosOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; } } } else { From 1f6150f95258fb8b5dc4d74d2e33e74121538dce Mon Sep 17 00:00:00 2001 From: Lionel Bijaoui Date: Fri, 10 Mar 2017 16:33:50 +0100 Subject: [PATCH 3/3] Update the unit test to reflect the changes and test for the new behavior. Fix lint error. --- src/fields/core/fieldChecklist.vue | 4 +- src/fields/core/fieldRadios.vue | 4 +- test/unit/specs/fields/fieldChecklist.spec.js | 158 ++++++++++++++++-- test/unit/specs/fields/fieldRadios.spec.js | 127 +++++++++++++- 4 files changed, 271 insertions(+), 22 deletions(-) diff --git a/src/fields/core/fieldChecklist.vue b/src/fields/core/fieldChecklist.vue index 866e4b8a..6f7de22a 100644 --- a/src/fields/core/fieldChecklist.vue +++ b/src/fields/core/fieldChecklist.vue @@ -55,7 +55,7 @@ return item[this.schema.checklistOptions.value]; } else { if (typeof item["value"] !== "undefined") { - return item.value + return item.value; } else { throw "value is not defined. If you want to use another key name, add a `value` property under `checklistOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/checklist.html#checklist-field-with-object-values"; } @@ -70,7 +70,7 @@ return item[this.schema.checklistOptions.name]; } else { if (typeof item["name"] !== "undefined") { - return item.name + return item.name; } else { throw "name is not defined. If you want to use another key name, add a `name` property under `checklistOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/checklist.html#checklist-field-with-object-values"; } diff --git a/src/fields/core/fieldRadios.vue b/src/fields/core/fieldRadios.vue index ff01c68d..0ce23131 100644 --- a/src/fields/core/fieldRadios.vue +++ b/src/fields/core/fieldRadios.vue @@ -34,7 +34,7 @@ return item[this.schema.radiosOptions.value]; } else { if (typeof item["value"] !== "undefined") { - return item.value + return item.value; } else { throw "value is not defined. If you want to use another key name, add a `value` property under `radiosOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; } @@ -49,7 +49,7 @@ return item[this.schema.radiosOptions.name]; } else { if (typeof item["name"] !== "undefined") { - return item.name + return item.name; } else { throw "name is not defined. If you want to use another key name, add a `name` property under `radiosOptions` in the schema. https://icebob.gitbooks.io/vueformgenerator/content/fields/radios.html#radios-field-with-object-values"; } diff --git a/test/unit/specs/fields/fieldChecklist.spec.js b/test/unit/specs/fields/fieldChecklist.spec.js index c7ed470d..e6bb6cf5 100644 --- a/test/unit/specs/fields/fieldChecklist.spec.js +++ b/test/unit/specs/fields/fieldChecklist.spec.js @@ -141,20 +141,20 @@ describe("fieldChecklist.vue", function() { }); - describe("check static values with { id, name } objects", () => { + describe("check static values with { value, name } objects (default key name)", () => { let schema = { type: "checklist", label: "Skills", model: "skills", listBox: true, values: [ - { id: 1, name: "HTML5" }, - { id: 2, name: "Javascript" }, - { id: 3, name: "CSS3" }, - { id: 4, name: "CoffeeScript" }, - { id: 5, name: "AngularJS" }, - { id: 6, name: "ReactJS" }, - { id: 7, name: "VueJS" } + { value: 1, name: "HTML5" }, + { value: 2, name: "Javascript" }, + { value: 3, name: "CSS3" }, + { value: 4, name: "CoffeeScript" }, + { value: 5, name: "AngularJS" }, + { value: 6, name: "ReactJS" }, + { value: 7, name: "VueJS" } ] }; let model = { skills: [2, 7] }; @@ -265,6 +265,134 @@ describe("fieldChecklist.vue", function() { }); + describe("check static values with { id, label } objects (custom key name with `checklistOptions`)", () => { + let schema = { + type: "checklist", + label: "Skills", + model: "skills", + listBox: true, + values: [ + { id: 1, label: "HTML5" }, + { id: 2, label: "Javascript" }, + { id: 3, label: "CSS3" }, + { id: 4, label: "CoffeeScript" }, + { id: 5, label: "AngularJS" }, + { id: 6, label: "ReactJS" }, + { id: 7, label: "VueJS" } + ], + checklistOptions: { + value: "id", + name: "label" + } + }; + let model = { skills: [2, 7] }; + let listbox; + let checkboxes; + let listRowList; + + function isChecked(idx) { + return(checkboxes[idx].checked); + } + + before( () => { + createField(this, schema, model, false); + listbox = el.querySelector(".listbox"); + checkboxes = listbox.querySelectorAll("input[type=checkbox]"); + listRowList = listbox.querySelectorAll(".list-row"); + }); + + it("should contain items", () => { + expect(checkboxes.length).to.be.equal(7); + }); + + it("should checked the values", () => { + expect(isChecked(0)).to.be.false; + expect(isChecked(1)).to.be.true; + expect(isChecked(2)).to.be.false; + expect(isChecked(3)).to.be.false; + expect(isChecked(4)).to.be.false; + expect(isChecked(5)).to.be.false; + expect(isChecked(6)).to.be.true; + }); + + describe("test values reactivity to changes", () => { + + it("listbox value should be the model value after changed", (done) => { + model.skills = [3]; + vm.$nextTick( () => { + expect(isChecked(0)).to.be.false; + expect(isChecked(1)).to.be.false; + expect(isChecked(2)).to.be.true; + expect(isChecked(3)).to.be.false; + expect(isChecked(4)).to.be.false; + expect(isChecked(5)).to.be.false; + expect(isChecked(6)).to.be.false; + done(); + }); + + }); + + it("model value should be the listbox value if changed", (done) => { + checkboxes[0].checked = true; + trigger(checkboxes[0], "input"); + + vm.$nextTick( () => { + expect(model.skills).to.be.deep.equal([3, 1]); + done(); + }); + + }); + + }); + + describe("test 'is-checked' class attribution reactivity to changes", () => { + + it(".list-row with checked input should have a 'is-checked' class", () => { + expect(listRowList[0].classList.contains("is-checked")).to.be.true; + expect(listRowList[1].classList.contains("is-checked")).to.be.false; + expect(listRowList[2].classList.contains("is-checked")).to.be.true; + expect(listRowList[3].classList.contains("is-checked")).to.be.false; + expect(listRowList[4].classList.contains("is-checked")).to.be.false; + expect(listRowList[5].classList.contains("is-checked")).to.be.false; + expect(listRowList[6].classList.contains("is-checked")).to.be.false; + }); + + it(".list-row with checked input should have a 'is-checked' class after model value is changed", (done) => { + model.skills = [4]; + vm.$nextTick( () => { + expect(listRowList[0].classList.contains("is-checked")).to.be.false; + expect(listRowList[1].classList.contains("is-checked")).to.be.false; + expect(listRowList[2].classList.contains("is-checked")).to.be.false; + expect(listRowList[3].classList.contains("is-checked")).to.be.true; + expect(listRowList[4].classList.contains("is-checked")).to.be.false; + expect(listRowList[5].classList.contains("is-checked")).to.be.false; + expect(listRowList[6].classList.contains("is-checked")).to.be.false; + done(); + }); + + }); + + it(".list-row with checked input should have a 'is-checked' class after listbox value is changed", (done) => { + checkboxes[0].checked = true; + trigger(checkboxes[0], "input"); + + vm.$nextTick( () => { + expect(listRowList[0].classList.contains("is-checked")).to.be.true; + expect(listRowList[1].classList.contains("is-checked")).to.be.false; + expect(listRowList[2].classList.contains("is-checked")).to.be.false; + expect(listRowList[3].classList.contains("is-checked")).to.be.true; + expect(listRowList[4].classList.contains("is-checked")).to.be.false; + expect(listRowList[5].classList.contains("is-checked")).to.be.false; + expect(listRowList[6].classList.contains("is-checked")).to.be.false; + done(); + }); + + }); + + }); + + }); + describe("check function values", () => { let schema = { type: "checklist", @@ -273,13 +401,13 @@ describe("fieldChecklist.vue", function() { listBox: true, values() { return [ - { id: 1, name: "HTML5" }, - { id: 2, name: "Javascript" }, - { id: 3, name: "CSS3" }, - { id: 4, name: "CoffeeScript" }, - { id: 5, name: "AngularJS" }, - { id: 6, name: "ReactJS" }, - { id: 7, name: "VueJS" } + { value: 1, name: "HTML5" }, + { value: 2, name: "Javascript" }, + { value: 3, name: "CSS3" }, + { value: 4, name: "CoffeeScript" }, + { value: 5, name: "AngularJS" }, + { value: 6, name: "ReactJS" }, + { value: 7, name: "VueJS" } ]; } }; diff --git a/test/unit/specs/fields/fieldRadios.spec.js b/test/unit/specs/fields/fieldRadios.spec.js index c4fc899a..da119a07 100644 --- a/test/unit/specs/fields/fieldRadios.spec.js +++ b/test/unit/specs/fields/fieldRadios.spec.js @@ -139,7 +139,7 @@ describe("FieldRadios.vue", function() { }); - describe("check template with object array", () => { + describe("check static values with { value, name } objects (default key name)", () => { let schema = { type: "radios", label: "radios", @@ -152,10 +152,131 @@ describe("FieldRadios.vue", function() { {name: "AngularJS", value:"AngularJS-123"}, {name: "ReactJS", value:"ReactJS-123"}, {name: "VueJS", value:"VueJS-123"} + ] + }; + let model = { skills: "CSS3-123" }; + let radioList; + let radios; + let labelList; + + function isChecked(idx) { + return(radios[idx].checked); + } + + before( () => { + createField(this, schema, model, false); + radioList = el.querySelector(".radio-list"); + radios = radioList.querySelectorAll("input[type=radio]"); + labelList = radioList.querySelectorAll("label"); + }); + + it("should contain a checkbox element", () => { + expect(field).to.be.exist; + expect(field.$el).to.be.exist; + + expect(radioList).to.be.defined; + }); + + it("should contain 7 items", () => { + expect(radios.length).to.be.equal(7); + }); + + it("should checked the values", () => { + expect(isChecked(0)).to.be.false; + expect(isChecked(1)).to.be.false; + expect(isChecked(2)).to.be.true; + expect(isChecked(3)).to.be.false; + expect(isChecked(4)).to.be.false; + expect(isChecked(5)).to.be.false; + expect(isChecked(6)).to.be.false; + }); + + it("label with checked input should have a 'is-checked' class", () =>{ + expect(labelList[0].classList.contains("is-checked")).to.be.false; + expect(labelList[1].classList.contains("is-checked")).to.be.false; + expect(labelList[2].classList.contains("is-checked")).to.be.true; + expect(labelList[3].classList.contains("is-checked")).to.be.false; + expect(labelList[4].classList.contains("is-checked")).to.be.false; + expect(labelList[5].classList.contains("is-checked")).to.be.false; + expect(labelList[6].classList.contains("is-checked")).to.be.false; + }); + describe("test values reactivity to changes", () => { + + it("radioList value should be the model value after changed", (done) => { + model.skills = "ReactJS-123"; + vm.$nextTick( () => { + expect(isChecked(0)).to.be.false; + expect(isChecked(1)).to.be.false; + expect(isChecked(2)).to.be.false; + expect(isChecked(3)).to.be.false; + expect(isChecked(4)).to.be.false; + expect(isChecked(5)).to.be.true; + expect(isChecked(6)).to.be.false; + done(); + }); + }); + + it("model value should be the radioList value if changed", (done) => { + radios[0].click(); + + vm.$nextTick( () => { + expect(model.skills).to.be.equal("HTML5-123"); + done(); + }); + }); + }); + + describe("test 'is-checked' class attribution reactivity to changes", () => { + + it("label with checked input should have a 'is-checked' class after model value is changed", (done) =>{ + model.skills = "ReactJS-123"; + vm.$nextTick( () => { + expect(labelList[0].classList.contains("is-checked")).to.be.false; + expect(labelList[1].classList.contains("is-checked")).to.be.false; + expect(labelList[2].classList.contains("is-checked")).to.be.false; + expect(labelList[3].classList.contains("is-checked")).to.be.false; + expect(labelList[4].classList.contains("is-checked")).to.be.false; + expect(labelList[5].classList.contains("is-checked")).to.be.true; + expect(labelList[6].classList.contains("is-checked")).to.be.false; + done(); + }); + }); + + it("label with checked input should have a 'is-checked' class after radioList value is changed", (done) =>{ + radios[2].click(); + + vm.$nextTick( () => { + expect(labelList[0].classList.contains("is-checked")).to.be.false; + expect(labelList[1].classList.contains("is-checked")).to.be.false; + expect(labelList[2].classList.contains("is-checked")).to.be.true; + expect(labelList[3].classList.contains("is-checked")).to.be.false; + expect(labelList[4].classList.contains("is-checked")).to.be.false; + expect(labelList[5].classList.contains("is-checked")).to.be.false; + expect(labelList[6].classList.contains("is-checked")).to.be.false; + done(); + }); + }); + }); + + }); + + describe("check static values with { id, label } objects (custom key name with `radiosOptions`)", () => { + let schema = { + type: "radios", + label: "radios", + model: "skills", + values: [ + {label: "HTML5", id:"HTML5-123"}, + {label: "Javascript", id:{id:"Javascript-123", deep:true}}, + {label: "CSS3", id:"CSS3-123"}, + {label: "CoffeeScript", id:"CoffeeScript-123"}, + {label: "AngularJS", id:"AngularJS-123"}, + {label: "ReactJS", id:"ReactJS-123"}, + {label: "VueJS", id:"VueJS-123"} ], radiosOptions: { - value:"value", - name:"name" + value: "id", + name: "label" } }; let model = { skills: "CSS3-123" };