Last active
April 13, 2016 15:18
-
-
Save awdng/34732bb436e9e05f145bee8d7b8a8381 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ng formBuilder directive | |
* built by Arne Wieding (arne@wieding.com) | |
* v0.2a 2014 | |
*/ | |
(function(module) { | |
'use strict'; | |
module.factory('formBuilderApi', function() { | |
return { | |
forms: {}, | |
createForm: function(name) { | |
var newForm = { | |
submitted: false, | |
hasErrors: false, | |
isDirty: false, | |
data: {}, | |
fields: [], | |
fieldsByName: {}, | |
errors: {}, | |
submitFail: function(allErrors) { | |
var self = this; | |
this.errors = allErrors; | |
angular.forEach(allErrors, function(fieldErrors, fieldName) { | |
self.fieldsByName[fieldName].errors = []; | |
angular.forEach(fieldErrors, function(value) { | |
self.fieldsByName[fieldName].errors.push(value.message); | |
}); | |
}); | |
this.hasErrors = true; | |
}, | |
resetErrors: function() { | |
this.errors = {}; | |
this.hasErrors = false; | |
}, | |
submitSuccess: function() { | |
this.resetErrors(); | |
angular.forEach(this.fields, function(fieldData) { | |
if (fieldData.dirty) { | |
fieldData.lastChangeSuccess = true; | |
fieldData.dirty = false; | |
} | |
fieldData.errors = []; | |
}); | |
}, | |
bindFormData: function(data) { | |
this.data = data; | |
}, | |
addField: function(name, data) { | |
var self = this; | |
data.errors = []; | |
data.dirty = false; | |
data.lastChangeSuccess = false; | |
data.locked = false; | |
data.name = name; | |
if (!('value' in data)) { | |
data.value = this.data[name]; | |
} | |
if (('locked' in data) && data.locked === true) { | |
data.locked = true; | |
} | |
if (('handler' in data)) { // register handler if passed | |
data.onChange = function() { | |
var field = {}; | |
field[name] = self.fieldsByName[name].value; | |
data.handler(field); | |
//self.onChangeHandler(field);// fix missing request | |
data.dirty = true; | |
}; | |
} else { // register global onChange Handler | |
data.onChange = function() { | |
var field = {}; | |
field[name] = self.fieldsByName[name].value; | |
self.onChangeHandler(field); | |
data.dirty = true; | |
}; | |
} | |
data.checkError = function() { | |
if (data.errors.length > 0) { | |
return true; | |
} | |
return false; | |
}; | |
this.fieldsByName[name] = data; | |
this.fields.push(data); | |
}, | |
onChangeHandler: null | |
}; | |
this.forms[name] = newForm; | |
return this.forms[name]; | |
}, | |
getForm: function(name) { | |
return this.forms[name]; | |
} | |
}; | |
}); | |
module.directive('formBuilder', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/form.html', | |
scope: {}, | |
link: function(scope, element, attrs) { | |
scope.form = formBuilderApi.getForm(attrs.name); | |
scope.formName = attrs.name; | |
} | |
}; | |
}); | |
module.directive('formBuilder.rowWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/row.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.readonlyWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/readonly.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.textWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/text.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.textareaWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/textarea.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.richtextWidget', function($compile, formBuilderApi, $modal) { | |
var ModalCtrl = function($scope, $modalInstance, data) { | |
$scope.data = data; | |
$scope.ok = function() { | |
$modalInstance.close($scope.data); | |
}; | |
$scope.cancel = function() { | |
$modalInstance.dismiss('Abbrechen'); | |
}; | |
}; | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/richtext.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
scope.openModal = function() { | |
var modalInstance = $modal.open({ | |
templateUrl: 'formbuilder/template/widgets/richtext_modal.html', | |
controller: ModalCtrl, | |
resolve: { | |
data: function() { | |
return scope.data; | |
} | |
} | |
}); | |
modalInstance.result.then(function() { | |
scope.data.onChange(); | |
}, function() { | |
// | |
}); | |
}; | |
} | |
}; | |
}); | |
module.directive('formBuilder.dateWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/date.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.timeWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/time.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.numberWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/number.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.choiceWidget', function($compile, formBuilderApi, $filter) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/choice.html', | |
scope: { | |
data: '=fieldData', | |
expanded: '=', | |
multiple: '=' | |
}, | |
link: function(scope, element, attrs) { | |
scope.selectSingle = function() { | |
// console.log(scope.data); | |
if (typeof scope.data.value == 'undefined') {//fix initial value | |
scope.data.value = scope.data.options[0].value; | |
} | |
var selected = $filter('filter')(scope.data.options, {value: scope.data.value}); | |
return (scope.data.value && selected.length) ? selected[0].text : 'Keine Auswahl'; | |
}; | |
scope.radioList = function() { | |
var selected = $filter('filter')(scope.data.options, {value: scope.data.value}); | |
return (scope.data.value && selected.length) ? selected[0].text : 'Keine Auswahl'; | |
}; | |
scope.checkboxList = function() { | |
var selected = []; | |
angular.forEach(scope.data.options, function(s) { | |
if (scope.data.value.indexOf(s.value) >= 0) { | |
selected.push(s.text); | |
} | |
}); | |
return selected.length ? selected.join(', ') : 'Keine Auswahl'; | |
}; | |
} | |
}; | |
}); | |
module.directive('formBuilder.imageUploadWidget', function($compile, formBuilderApi, $http, $timeout, $upload) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/imageUpload.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
var app = angular.module('biologica'); | |
scope.onFileSelect = function($files) { | |
for (var i = 0; i < $files.length; i++) { | |
var file = $files[i]; | |
if (typeof global_company_id != 'undefined') { | |
//company | |
var uploadURL = app.getApiPath() + '/companies/' + global_company_id + '/media'; //upload.php script | |
} else { | |
//therapist | |
var uploadURL = app.getApiPath() + '/media'; | |
} | |
$upload.upload({ | |
url: uploadURL, //upload.php script, node.js route, or servlet url | |
file: file | |
}).progress(function(evt) { | |
var progr = parseInt(100.0 * evt.loaded / evt.total); | |
scope.dynamicProgress = progr; | |
}).success(function(result, status, headers, config) { | |
scope.dynamicProgress = 0; | |
//scope.data.value = result.entity.id; | |
scope.data.value = result.entity; | |
scope.data.onChange(); | |
}); | |
} | |
}; | |
} | |
}; | |
}); | |
module.directive('formBuilder.labelWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/label.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
module.directive('formBuilder.errorWidget', function($compile, formBuilderApi) { | |
return { | |
restrict: 'E', | |
templateUrl: 'formbuilder/template/widgets/error.html', | |
scope: { | |
data: '=fieldData' | |
}, | |
link: function(scope, element, attrs) { | |
// | |
} | |
}; | |
}); | |
})(angular.module('formBuilder', [ | |
'textAngular', | |
'angularFileUpload', | |
'xeditable', | |
'ui.bootstrap', | |
'localytics.directives', | |
'formbuilder.templates' | |
] | |
).run(function(editableOptions, datepickerConfig, datepickerPopupConfig, timepickerConfig) { | |
editableOptions.theme = 'bs2'; // options 'bs3','bs2', 'default' | |
datepickerPopupConfig.showButtonBar = false; | |
datepickerConfig.startingDay = '1'; | |
datepickerConfig.currentText = 'Heute'; | |
timepickerConfig.showMeridian = false; | |
} | |
)); | |
// initalize default templates | |
angular.module("formbuilder.templates", []).run(["$templateCache", function($templateCache) { | |
$templateCache.put("formbuilder/template/form.html", | |
"<li data-ng-repeat=\"data in form.fields\" ng-if=\"data.type !== 'hidden'\"> \ | |
<form-builder.row-widget field-data='data'></form-builder-row-widget> \ | |
</li>"); | |
$templateCache.put("formbuilder/template/widgets/row.html", | |
"<form-builder.error-widget field-data='data'></form-builder.error-widget> \ | |
<div class='input-label'> \ | |
<form-builder.label-widget field-data='data'></form-builder.label-widget> \ | |
</div> \ | |
<div class='input-value' ng-class=\"{'control-group success': !data.checkError(), 'control-group error': data.checkError()}\" tooltip='{{ data.attr.placeholder }}'> \ | |
<i ng-show='data.checkError()' class='icon status-icon icon-remove-sign'></i> \ | |
<i ng-show='!data.checkError() && data.lastChangeSuccess' class='icon status-icon icon-ok-sign'></i> \ | |
<form-builder.readonly-widget ng-if=\"data.type == 'readonly'\" field-data='data'></form-builder.readonly-widget> \ | |
<form-builder.text-widget ng-if=\"data.type == 'text'\" field-data='data'></form-builder.text-widget> \ | |
<form-builder.textarea-widget ng-if=\"data.type == 'textarea'\" field-data='data' class=\"text-area\"></form-builder.textarea-widget> \ | |
<form-builder.richtext-widget ng-if=\"data.type == 'richtext'\" field-data='data'></form-builder.richtext-widget> \ | |
<form-builder.date-widget ng-if=\"data.type == 'date'\" field-data='data' class=\"date-widget\"></form-builder.date-widget> \ | |
<form-builder.time-widget ng-if=\"data.type == 'time'\" field-data='data'></form-builder.time-widget> \ | |
<form-builder.number-widget ng-if=\"data.type == 'number'\" field-data='data'></form-builder.number-widget> \ | |
<form-builder.image-upload-widget ng-if=\"data.type == 'imageupload'\" field-data='data'></form-builder.image-upload-widget> \ | |
<form-builder.choice-widget ng-if=\"data.type == 'choice'\" field-data='data' expanded='data.expanded' multiple='data.multiple'></form-builder.choice-widget> \ | |
<div class='auto-form-edit' ng-if=\"data.type != 'readonly'\"><i class='icon icon-pencil'></i> Bearbeiten</div> \ | |
</div>"); | |
$templateCache.put("formbuilder/template/widgets/text.html", | |
"<a href=\"#\" editable-text=\"data.value\" onaftersave=\"data.onChange()\"> \ | |
{{ data.value || 'Leer' }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/textarea.html", | |
"<a href=\"#\" editable-textarea=\"data.value\" e-rows=\"data.rows\" e-cols=\"data.cols\" onaftersave=\"data.onChange()\"> \ | |
{{ data.value || 'Leer' }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/readonly.html", | |
"<a class=\"editable editable-click\">{{ data.value || 'Leer'}}</a>"); | |
$templateCache.put("formbuilder/template/widgets/richtext.html", | |
"<span href=\"#\" class=\"editable editable-click\" ng-click=\"openModal()\">{{ data.value || 'Leer'}}</span>"); | |
$templateCache.put("formbuilder/template/widgets/richtext_modal.html", | |
"<div> \ | |
<div class=\"modal-header message-reply-header\"> \ | |
<button class=\"btn btn-default pull-right close-respond\" type=\"button\" ng-click=\"cancel()\"><i class=\"icon icon-remove-sign\"></i></button> \ | |
<h3>Bearbeiten</h3> \ | |
</div> \ | |
<div class=\"modal-body\"> \ | |
<div class=\"modal-content-container\">\ | |
<text-angular text-angular-name=\"composeMessage\" placeholder=\"data.placeholder\" ng-model=\"data.value\" class=\"ta-editor\" ta-toolbar=\"[['h1','h2','h3', 'p'],['bold', 'italics', 'ul', 'ol', 'redo', 'undo', 'clear'],[ 'underline'],['justifyCenter', 'justifyLeft', 'justifyRight']]\"/> \ | |
</div> \ | |
</div> \ | |
<div class=\"modal-footer\"> \ | |
<button class=\"btn btn-success pull-left respond\" type=\"button\" ng-click=\"ok()\">OK</button> \ | |
<button class=\"btn btn-warning pull-right respond\" type=\"button\" ng-click=\"cancel()\">Abbrechen</button> \ | |
</div> \ | |
</div>"); | |
$templateCache.put("formbuilder/template/widgets/date.html", | |
"<a href=\"#\" editable-bsdate=\"data.value\" e-datepicker-popup=\"dd.MM.yyyy\" e-current-text=\"Heute\" onaftersave=\"data.onChange()\"> \ | |
{{ (data.value | date:'dd.MM.yyyy') || 'Leer' }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/time.html", | |
"<a href=\"#\" editable-bstime=\"data.value\" e-show-meridan=\"true\" e-minute-step=\"1\" onaftersave=\"data.onChange()\"> \ | |
{{ (data.value | date:\"HH:mm\") || 'Leer' }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/number.html", | |
"<a href=\"#\" editable-number=\"data.value\" onaftersave=\"data.onChange()\"> \ | |
{{ data.value || 'Leer' }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/choice.html", | |
"<a ng-if=\"!multiple && !expanded\" href=\"#\" editable-select=\"data.value\" e-ng-options=\"s.value as s.text for s in data.options\" onaftersave=\"data.onChange()\"> \ | |
{{ selectSingle() }} \ | |
</a> \ | |
\ | |
<select ng-if=\"multiple && !expanded\" multiple chosen \ | |
data-placeholder=\"Wählen Sie mehrere aus\" \ | |
ng-model=\"data.value\" \ | |
ng-options=\"s.value as s.text for s in data.options\" \ | |
ng-change=\"data.onChange()\"> \ | |
</select> \ | |
\ | |
<a ng-if=\"!multiple && expanded\" href=\"#\" editable-radiolist=\"data.value\" e-ng-options=\"s.value as s.text for s in data.options\" onaftersave=\"data.onChange()\"> \ | |
{{ radioList() }} \ | |
</a> \ | |
\ | |
<a ng-if=\"multiple && expanded\" href=\"#\" editable-checklist=\"data.value\" e-ng-options=\"s.value as s.text for s in data.options\" onaftersave=\"data.onChange()\"> \ | |
{{ checkboxList() }} \ | |
</a>"); | |
$templateCache.put("formbuilder/template/widgets/imageUpload.html", | |
"<input type=\"hidden\" ng-model=\"data.value.id\"> \ | |
<input style=\"margin-left:10px;margin-top:-3px;\" type=\"file\" ng-file-select=\"onFileSelect($files)\" class=\"btn btn-link btn-small\" /> \ | |
<span> \ | |
<img ng-src='{{ data.value.url }}'/> \ | |
</span> \ | |
\ | |
<div class=\"progress progress-striped active\" ng-show=\"dynamicProgress > 0\" style=\"margin: 20px;\"> \ | |
<div class=\"bar\" style=\"width: {{dynamicProgress}}%;\"></div> \ | |
</div>"); | |
$templateCache.put("formbuilder/template/widgets/label.html", | |
"{{ data.label }}"); | |
$templateCache.put("formbuilder/template/widgets/error.html", | |
"<div ng-show=\"data.checkError()\" class=\"alert alert-error\"> \ | |
<i class=\"icon icon-remove-sign\"></i> <a class=\"close\" data-dismiss=\"alert\">×</a> \ | |
<span ng-repeat=\"error in data.errors\">{{ error }}</span> \ | |
</div>"); | |
}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('company').controller('CompanyProfileCtrl', function($scope, $routeParams, Restangular, ngTableParams, $filter, $location, $q, $upload, formBuilderApi) { | |
var app = angular.module('app'); | |
var init = function() { | |
Restangular.one('companies/' + global_company_id).get().then(function (company) { | |
// bind the company model data to the form | |
$scope.companyForm.bindFormData(company); | |
// define form fields | |
$scope.companyForm.addField('name', { | |
label: 'Name', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('street', { | |
label: 'Strasse', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('short_description', { | |
label: 'Beschreibung', | |
type: 'textarea', | |
handler : function(field){ | |
$scope.companyForm.onChangeHandler({shortDescription:field.short_description}); | |
} | |
}); | |
$scope.companyForm.addField('zipcode', { | |
label: 'Postleitzahl', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('city', { | |
label: 'Stadt', | |
type: 'choice', | |
options: [ | |
{ | |
value: 'Leipzig', | |
text: 'Leipzig' | |
}, | |
{ | |
value: 'Berlin', | |
text: 'Berlin' | |
}, | |
{ | |
value: 'München', | |
text: 'München' | |
} | |
], | |
expanded: false, | |
multiple: false | |
}); | |
$scope.companyForm.addField('phone', { | |
label: 'Telefon', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('fax', { | |
label: 'Fax', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('web', { | |
label: 'Internet', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('email', { | |
label: 'Email', | |
type: 'text' | |
}); | |
$scope.companyForm.addField('logo', { | |
label: 'Logo', | |
type: 'imageupload' | |
}); | |
}); | |
}; | |
// create new form Object | |
$scope.companyForm = formBuilderApi.createForm('companyForm'); | |
// register form field save handler | |
$scope.companyForm.onChangeHandler = function(fieldData) { | |
Restangular.one('companies/' + global_company_id).patch(fieldData).then(function () { | |
$scope.companyForm.submitSuccess(); | |
}, function(response) { | |
$scope.companyForm.submitFail(response.data); | |
}); | |
}; | |
// init controller | |
init.apply(this, arguments); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div> | |
<form-builder name="companyForm"></form-builder> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment