Skip to content

Commit e21a0de

Browse files
authored
Merge pull request #415 from zoul0813/v3-features/dynamic-html-attributes
V3: dynamic html attributes
2 parents 70d6798 + 5fdf339 commit e21a0de

16 files changed

+424
-40
lines changed

dev/projects/basic/app.vue

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,45 @@ export default {
3838
type: "input",
3939
inputType: "text",
4040
label: "First Name",
41-
model: "first_name"
41+
model: "first_name",
42+
attributes: {
43+
input: {
44+
"data-toggle": "tooltip"
45+
},
46+
wrapper: {
47+
"data-target": "input"
48+
}
49+
}
4250
},
4351
{
4452
type: "checkbox",
4553
label: "Active",
46-
model: "status"
54+
model: "status",
55+
attributes: {
56+
input: {
57+
"data-toggle": "tooltip"
58+
}
59+
}
4760
},
4861
{
4962
type: "input",
5063
inputType: "color",
5164
label: "Color",
52-
model: "color"
65+
model: "color",
66+
attributes: {
67+
input: {
68+
"data-target": "tooltip"
69+
}
70+
}
5371
},
5472
{
5573
type: "submit",
5674
buttonText: "Change Previous Type",
75+
attributes: {
76+
input: {
77+
"data-target": "toggle"
78+
}
79+
},
5780
onSubmit: () => {
5881
// this.schema.fields[2].type = "input";
5982
if (this.schema.fields[2].inputType === "color") {

src/fields/abstractField.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ function convertValidator(validator) {
1313
return validator;
1414
}
1515

16+
function attributesDirective(el, binding, vnode) {
17+
let attrs = objGet(vnode.context, "schema.attributes", {});
18+
let container = binding.value || "input";
19+
if(isString(container)) {
20+
attrs = objGet(attrs, container) || attrs;
21+
}
22+
forEach(attrs, (val, key) => {
23+
el.setAttribute(key, val);
24+
});
25+
}
26+
1627
export default {
1728
props: ["model", "schema", "formOptions", "disabled"],
1829

@@ -24,6 +35,14 @@ export default {
2435
};
2536
},
2637

38+
directives: {
39+
attributes: {
40+
bind: attributesDirective,
41+
updated: attributesDirective,
42+
componentUpdated: attributesDirective,
43+
}
44+
},
45+
2746
computed: {
2847
value: {
2948
cache: false,

src/fields/core/fieldCheckbox.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
input(:id="getFieldID(schema)", type="checkbox", v-model="value", :autocomplete="schema.autocomplete", :disabled="disabled", :name="schema.inputName", :class="schema.fieldClasses")
2+
input(:id="getFieldID(schema)", type="checkbox", v-model="value", :autocomplete="schema.autocomplete", :disabled="disabled", :name="schema.inputName", :class="schema.fieldClasses", v-attributes="'input'")
33
</template>
44

55
<script>

src/fields/core/fieldChecklist.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template lang="pug">
2-
.wrapper
2+
.wrapper(v-attributes="'wrapper'")
33
.listbox.form-control(v-if="schema.listBox", :disabled="disabled")
44
.list-row(v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
55
label
6-
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)")
6+
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
77
| {{ getItemName(item) }}
88

99
.combobox.form-control(v-if="!schema.listBox", :disabled="disabled")
@@ -14,7 +14,7 @@
1414
.dropList
1515
.list-row(v-if="comboExpanded", v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
1616
label
17-
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)")
17+
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
1818
| {{ getItemName(item) }}
1919
</template>
2020

src/fields/core/fieldInput.vue

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
.wrapper
2+
.wrapper(v-attributes="'wrapper'")
33
input.form-control(
44
:id="getFieldID(schema)",
55
:type="schema.inputType.toLowerCase()",
@@ -9,33 +9,13 @@
99
:class="schema.fieldClasses",
1010
@change="schema.onChange || null",
1111
:disabled="disabled",
12-
:accept="schema.accept",
13-
:alt="schema.alt",
14-
:autocomplete="schema.autocomplete",
15-
:checked="schema.checked",
16-
:dirname="schema.dirname",
17-
:formaction="schema.formaction",
18-
:formenctype="schema.formenctype",
19-
:formmethod="schema.formmethod",
20-
:formnovalidate="schema.formnovalidate",
21-
:formtarget="schema.formtarget",
22-
:height="schema.height",
23-
:list="schema.list",
24-
:max="schema.max",
25-
:maxlength="schema.maxlength",
26-
:min="schema.min",
27-
:minlength="schema.minlength",
28-
:multiple="schema.multiple",
2912
:name="schema.inputName",
30-
:pattern="schema.pattern",
31-
:placeholder="schema.placeholder",
3213
:readonly="schema.readonly",
3314
:required="schema.required",
34-
:size="schema.size",
3515
:src="schema.src",
36-
:step="schema.step",
37-
:width="schema.width",
38-
:files="schema.files")
16+
:files="schema.files"
17+
v-attributes="'input'")
18+
3919
span.helper(v-if="schema.inputType.toLowerCase() === 'color' || schema.inputType.toLowerCase() === 'range'") {{ value }}
4020
</template>
4121

src/fields/core/fieldLabel.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
span(:id="getFieldID(schema)", :class="schema.fieldClasses") {{ value }}
2+
span(:id="getFieldID(schema)", :class="schema.fieldClasses", v-attributes="'label'") {{ value }}
33
</template>
44

55
<script>

src/fields/core/fieldRadios.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template lang="pug">
2-
.radio-list(:disabled="disabled")
3-
label(v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
4-
input(:id="getFieldID(schema)", type="radio", :disabled="disabled", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses")
2+
.radio-list(:disabled="disabled", v-attributes="'wrapper'")
3+
label(v-for="item in items", :class="{'is-checked': isItemChecked(item)}", v-attributes="'label'")
4+
input(:id="getFieldID(schema)", type="radio", :disabled="disabled", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses", v-attributes="'input'")
55
| {{ getItemName(item) }}
66

77
</template>

src/fields/core/fieldSelect.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
select.form-control(v-model="value", :disabled="disabled", :name="schema.inputName", :id="getFieldID(schema)", :class="schema.fieldClasses")
2+
select.form-control(v-model="value", :disabled="disabled", :name="schema.inputName", :id="getFieldID(schema)", :class="schema.fieldClasses", v-attributes="'input'")
33
option(v-if="!selectOptions.hideNoneSelectedText", :disabled="schema.required", :value="null") {{ selectOptions.noneSelectedText || "&lt;Nothing selected&gt;" }}
44

55
template(v-for="item in items")

src/fields/core/fieldSubmit.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
input(:id="getFieldID(schema)", type="submit", :value="schema.buttonText", @click="onClick", :name="schema.inputName", :disabled="disabled", :class="schema.fieldClasses")
2+
input(:id="getFieldID(schema)", type="submit", :value="schema.buttonText", @click="onClick", :name="schema.inputName", :disabled="disabled", :class="schema.fieldClasses", v-attributes="'input'")
33
</template>
44

55
<script>

src/fields/core/fieldTextArea.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
:placeholder="schema.placeholder",
1010
:readonly="schema.readonly",
1111
:rows="schema.rows || 2",
12-
:name="schema.inputName")
12+
:name="schema.inputName",
13+
v-attributes="'input'")
1314
</template>
1415

1516
<script>

src/fields/core/fieldUpload.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template lang="pug">
2-
.wrapper
2+
.wrapper(v-attributes="'wrapper'")
33
input.form-control(
44
id="getFieldID(schema)",
55
type="file",
@@ -10,7 +10,8 @@
1010
:placeholder="schema.placeholder",
1111
:readonly="schema.readonly",
1212
:required="schema.required",
13-
:disabled="disabled",)
13+
:disabled="disabled",
14+
v-attributes="'input'")
1415
</template>
1516

1617
<script>

test/unit/specs/fields/fieldCheckbox.spec.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,60 @@ describe("FieldCheckbox.vue", () => {
7676
});
7777
});
7878
});
79+
80+
describe("check dynamic html attributes", () => {
81+
82+
describe("check input/wrapper attributes", () => {
83+
let schema = {
84+
type: "checkbox",
85+
label: "First Name",
86+
model: "user__model",
87+
inputName: "input_name",
88+
fieldClasses: ["applied-class", "another-class"],
89+
attributes: {
90+
wrapper: {
91+
"data-wrapper": "collapse"
92+
},
93+
input: {
94+
"data-input": "tooltip"
95+
}
96+
}
97+
};
98+
let model = {};
99+
let input, wrap;
100+
101+
before(() => {
102+
createField({ schema, model});
103+
input = wrapper.find('input');
104+
});
105+
106+
it("input should have data-* attribute", () => {
107+
expect(input.attributes()["data-input"]).to.be.equal("tooltip");
108+
});
109+
});
110+
111+
describe("check non-specific attributes", () => {
112+
let schema = {
113+
type: "checkbox",
114+
label: "First Name",
115+
model: "user__model",
116+
inputName: "input_name",
117+
fieldClasses: ["applied-class", "another-class"],
118+
attributes: {
119+
"data-input": "tooltip"
120+
}
121+
};
122+
let model = {};
123+
let input, wrap;
124+
125+
before(() => {
126+
createField({ schema, model});
127+
input = wrapper.find('input');
128+
});
129+
130+
it("input should have data-* attribute", () => {
131+
expect(input.attributes()["data-input"]).to.be.equal("tooltip");
132+
});
133+
});
134+
});
79135
});

test/unit/specs/fields/fieldChecklist.spec.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,111 @@ describe("fieldChecklist.vue", () => {
616616
});
617617
});
618618
});
619+
620+
describe("check dynamic html attributes", () => {
621+
622+
describe("check listbox input/wrapper attributes", () => {
623+
let schema = {
624+
type: "checklist",
625+
listBox: true,
626+
label: "First Name",
627+
model: "user__model",
628+
inputName: "input_name",
629+
fieldClasses: ["applied-class", "another-class"],
630+
values: ["HTML5", "Javascript", "CSS3", "CoffeeScript", "AngularJS", "ReactJS", "VueJS"],
631+
attributes: {
632+
wrapper: {
633+
"data-wrapper": "collapse"
634+
},
635+
input: {
636+
"data-input": "tooltip"
637+
}
638+
}
639+
};
640+
let model = {};
641+
let input, wrap;
642+
643+
before(() => {
644+
createField2({ schema, model});
645+
input = wrapper.find('input');
646+
wrap = wrapper.find('.wrapper');
647+
});
648+
649+
it("wrapper should have data-* attribute", () => {
650+
expect(wrap.attributes()["data-wrapper"]).to.be.equal("collapse");
651+
});
652+
653+
it("input should have data-* attribute", () => {
654+
expect(input.attributes()["data-input"]).to.be.equal("tooltip");
655+
});
656+
});
657+
658+
describe("check combobox input/wrapper attributes", () => {
659+
let schema = {
660+
type: "checklist",
661+
listBox: false,
662+
label: "First Name",
663+
model: "user__model",
664+
inputName: "input_name",
665+
fieldClasses: ["applied-class", "another-class"],
666+
values: ["HTML5", "Javascript", "CSS3", "CoffeeScript", "AngularJS", "ReactJS", "VueJS"],
667+
attributes: {
668+
wrapper: {
669+
"data-wrapper": "collapse"
670+
},
671+
input: {
672+
"data-input": "tooltip"
673+
}
674+
}
675+
};
676+
let model = {};
677+
let input, wrap;
678+
679+
before(() => {
680+
createField2({ schema, model});
681+
input = wrapper.find('input');
682+
wrap = wrapper.find('.wrapper');
683+
});
684+
685+
it("wrapper should have data-* attribute", () => {
686+
expect(wrap.attributes()["data-wrapper"]).to.be.equal("collapse");
687+
});
688+
689+
it.skip("input should have data-* attribute", (done) => {
690+
// TODO: figure out how to get this test to work
691+
wrapper.setData({ comboExpanded: true });
692+
Vue.config.errorHandler = done;
693+
Vue.nextTick(() => {
694+
expect(input.attributes()["data-input"]).to.be.equal("tooltip");
695+
done();
696+
});
697+
});
698+
});
699+
700+
describe("check non-specific attributes", () => {
701+
let schema = {
702+
type: "checklist",
703+
listBox: true,
704+
label: "First Name",
705+
model: "user__model",
706+
inputName: "input_name",
707+
fieldClasses: ["applied-class", "another-class"],
708+
values: ["HTML5", "Javascript", "CSS3", "CoffeeScript", "AngularJS", "ReactJS", "VueJS"],
709+
attributes: {
710+
"data-input": "tooltip"
711+
}
712+
};
713+
let model = {};
714+
let input, wrap;
715+
716+
before(() => {
717+
createField2({ schema, model});
718+
input = wrapper.find('input');
719+
});
720+
721+
it("input should have data-* attribute", () => {
722+
expect(input.attributes()["data-input"]).to.be.equal("tooltip");
723+
});
724+
});
725+
});
619726
});

0 commit comments

Comments
 (0)