Skip to content

Grouping fields #209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 31, 2017
78 changes: 78 additions & 0 deletions dev/grouping/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<template lang="html">
<form>
<vue-form-generator :schema="schema" :model="model" :options="formOptions" tag="section"></vue-form-generator>
<pre>{{ model }}</pre>
</form>
</template>

<script>
import Vue from "vue";

export default {
data () {
return {
model: {
name: 'Brian Blessed',
email: "[email protected]",
others: {
more: "More",
things: "Things"
},
single: 'blah'
},

schema: {
groups:[{
legend: "Contact Details",
fields: [
{
type: "input",
inputType: "text",
label: "Name",
model: "name"
},
{
type: "input",
inputType: "email",
label: "Email",
model: "email"
}
]
},{
legend: "Other Details",
fields: [
{
type: "input",
inputType: "text",
label: "More",
model: "others.more"
},
{
type: "input",
inputType: "text",
label: "Things",
model: "others.things"
}
]
}],
fields: [
{
type: "input",
inputType: "text",
label: "Single field (without group)",
model: "single"
}
]
},

formOptions: {
fieldIdPrefix: 'frm1-'
}
}
},

created() {
window.app = this;
}
}
</script>
12 changes: 12 additions & 0 deletions dev/grouping/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-form-generator multiple forms demo</title>
</head>
<body>
<div class="container-fluid"></div>
<div id="app"></div>
<script src="/grouping.js"></script>
</body>
</html>
9 changes: 9 additions & 0 deletions dev/grouping/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Vue from "vue";
import VueFormGenerator from "../../src";
Vue.use(VueFormGenerator);

import App from './app.vue';

new Vue({
...App
}).$mount('#app');
27 changes: 4 additions & 23 deletions src/fields/abstractField.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { get as objGet, each, isFunction, isString, isArray } from "lodash";
import validators from "../utils/validators";
import { slugifyFormID } from "../utils/schema";

function convertValidator(validator) {
if (isString(validator)) {
Expand All @@ -17,6 +18,7 @@ export default {
props: [
"model",
"schema",
"formOptions",
"disabled"
],

Expand Down Expand Up @@ -163,29 +165,8 @@ export default {
},

getFieldID(schema) {
// Try to get a reasonable default id from the schema,
// then slugify it.
if (typeof schema.id !== "undefined") {
// If an ID's been explicitly set, use it unchanged
return schema.id;
} else {
// Return the slugified version of either:
return (schema.inputName || schema.label || schema.model)
// NB: This is a very simple, conservative, slugify function,
// avoiding extra dependencies.
.toString()
.trim()
.toLowerCase()
// Spaces & underscores to dashes
.replace(/ |_/g, "-")
// Multiple dashes to one
.replace(/-{2,}/g, "-")
// Remove leading & trailing dashes
.replace(/^-+|-+$/g, "")
// Remove anything that isn't a (English/ASCII) letter, number or dash.
.replace(/([^a-zA-Z0-9-]+)/g, "")
;
}
const idPrefix = this.formOptions && this.formOptions.fieldIdPrefix ? this.formOptions.fieldIdPrefix : "";
return slugifyFormID(schema, idPrefix);
}

}
Expand Down
47 changes: 39 additions & 8 deletions src/formGenerator.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template lang="pug">
div
fieldset.vue-form-generator(v-if='schema != null', :is='tag')
div.vue-form-generator(v-if='schema != null')
fieldset(v-if="schema.fields", :is='tag')
template(v-for='field in fields')
.form-group(v-if='fieldVisible(field)', :class='getFieldRowClasses(field)')
label(v-if="fieldTypeHasLabel(field)", :for="getFieldID(field)")
Expand All @@ -9,18 +9,36 @@ div
i.icon
.helpText(v-html='field.help')
.field-wrap
component(:is='getFieldType(field)', :disabled='fieldDisabled(field)', :model='model', :schema.sync='field', @model-updated='modelUpdated', @validated="onFieldValidated")
component(:is='getFieldType(field)', :disabled='fieldDisabled(field)', :model='model', :schema='field', :formOptions='options', @model-updated='modelUpdated', @validated="onFieldValidated")
.buttons(v-if='buttonVisibility(field)')
button(v-for='btn in field.buttons', @click='buttonClickHandler(btn, field)', :class='btn.classes') {{ btn.label }}
.hint(v-if='field.hint') {{ field.hint }}
.errors.help-block(v-if='fieldErrors(field).length > 0')
span(v-for='(error, index) in fieldErrors(field)', track-by='index') {{ error }}

template(v-for='group in groups')
fieldset
legend(v-if='group.legend') {{ group.legend }}
template(v-for='field in group.fields')
.form-group(v-if='fieldVisible(field)', :class='getFieldRowClasses(field)')
label(v-if="fieldTypeHasLabel(field)", :for="getFieldID(field)")
| {{ field.label }}
span.help(v-if='field.help')
i.icon
.helpText(v-html='field.help')
.field-wrap
component(:is='getFieldType(field)', :disabled='fieldDisabled(field)', :model='model', :schema='field', :formOptions='options',@model-updated='modelUpdated', @validated="onFieldValidated")
.buttons(v-if='buttonVisibility(field)')
button(v-for='btn in field.buttons', @click='buttonClickHandler(btn, field)', :class='btn.classes') {{ btn.label }}
.hint(v-if='field.hint') {{ field.hint }}
.errors.help-block(v-if='fieldErrors(field).length > 0')
span(v-for='(error, index) in fieldErrors(field)', track-by='index') {{ error }}
</template>

<script>
// import Vue from "vue";
import {each, isFunction, isNil, isArray, isString} from "lodash";
import getFieldID from "./fields/abstractField";
import { slugifyFormID } from "./utils/schema";

// Load all fields from '../fields' folder
let fieldComponents = {};
Expand All @@ -46,8 +64,6 @@ div
export default {
components: fieldComponents,

mixins: [ getFieldID ],

props: {
schema: Object,

Expand Down Expand Up @@ -93,13 +109,23 @@ div
computed: {
fields() {
let res = [];
if (this.schema) {
if (this.schema && this.schema.fields) {
each(this.schema.fields, (field) => {
if (!this.multiple || field.multi === true)
res.push(field);
});
}

return res;
},
groups() {
let res = [];
if (this.schema && this.schema.groups) {
each(this.schema.groups, (group) => {
res.push(group);
});
}

return res;
}
},
Expand Down Expand Up @@ -315,7 +341,12 @@ div
fieldErrors(field) {
let res = this.errors.filter(e => e.field == field);
return res.map(item => item.error);
}
},

getFieldID(schema) {
const idPrefix = this.options && this.options.fieldIdPrefix ? this.options.fieldIdPrefix : "";
return slugifyFormID(schema, idPrefix);
}
}
};

Expand Down
26 changes: 26 additions & 0 deletions src/utils/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,30 @@ module.exports.mergeMultiObjectFields = function(schema, objs) {
});

return model;
};

module.exports.slugifyFormID = function(schema, prefix = "") {
// Try to get a reasonable default id from the schema,
// then slugify it.
if (typeof schema.id !== "undefined") {
// If an ID's been explicitly set, use it unchanged
return prefix + schema.id;
} else {
// Return the slugified version of either:
return prefix + (schema.inputName || schema.label || schema.model)
// NB: This is a very simple, conservative, slugify function,
// avoiding extra dependencies.
.toString()
.trim()
.toLowerCase()
// Spaces & underscores to dashes
.replace(/ |_/g, "-")
// Multiple dashes to one
.replace(/-{2,}/g, "-")
// Remove leading & trailing dashes
.replace(/^-+|-+$/g, "")
// Remove anything that isn't a (English/ASCII) letter, number or dash.
.replace(/([^a-zA-Z0-9-]+)/g, "")
;
}
};
14 changes: 9 additions & 5 deletions test/unit/specs/VueFormGenerator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ function createFormGenerator(schema = {}, model = null, options, multiple) {
describe("VueFormGenerator.vue", () => {

describe("with empty schema", () => {
let schema = {};
let schema = {
fields: []
};

beforeEach( () => {
createFormGenerator(schema);
Expand All @@ -49,13 +51,15 @@ describe("VueFormGenerator.vue", () => {
});

describe("with empty schema and custom tag", () => {
let schema = {};
let schema = {
fields: []
};

beforeEach( () => {
let elm = document.createElement("div");
vm = new Vue({
// eslint-disable-next-line quotes
template: `<vue-form-generator :schema="schema" ref="form" tag="div"></vue-form-generator>`,
template: `<vue-form-generator :schema="schema" ref="form" tag="section"></vue-form-generator>`,
data: {
schema
}
Expand All @@ -66,9 +70,9 @@ describe("VueFormGenerator.vue", () => {
return [el, vm];
});

it("should be create fieldset", () => {
it("should be create custom tag", () => {
expect(vm.$el).to.be.exist;
expect(el.getElementsByTagName("div")).to.be.length(1);
expect(el.getElementsByTagName("section")).to.be.length(1);
});

});
Expand Down
33 changes: 17 additions & 16 deletions webpack.dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,24 @@ var loaders = [
test: /\.json$/,
loader: 'json'
},
{
test: /\.(woff2?|svg)$/,
loader: "url"
//loader: "url?limit=10000"
{
test: /\.(woff2?|svg)$/,
loader: "url"
//loader: "url?limit=10000"
},
{
test: /\.(ttf|eot)$/,
loader: "url"
{
test: /\.(ttf|eot)$/,
loader: "url"
}
];

module.exports = {
devtool: "source-map",

entry: {
full: path.resolve("dev", "full", "main.js"),
mselect: path.resolve("dev", "multiselect", "main.js"),
grouping: path.resolve("dev", "grouping", "main.js"),
checklist: path.resolve("dev", "checklist", "main.js")
},

Expand All @@ -43,14 +44,14 @@ module.exports = {
publicPath: "/"
},

plugins: [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development"),
FULL_BUNDLE: true
}
}),
],
plugins: [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development"),
FULL_BUNDLE: true
}
}),
],

module: {
loaders
Expand Down