Created
July 16, 2015 12:49
-
-
Save mliszcz/a2f46501d45b5ae8b6e0 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
app = angular.module 'tool' | |
app.controller 'dynamicFormsUpdateController', ($scope, $modalInstance, $q, _, | |
SchemaResolver, regularFormFilter, model, schema, resource, name, fields) -> | |
# NOTE | |
# angular-schema-form 0.8.3 contains bug realted to selects without trackBy | |
# https://github.com/Textalk/angular-schema-form/pull/418 | |
# trackBy support was reverted in 0.8.4 | |
# we will stick to the 0.8.3 til trackBy comes back | |
# TODO consider loading related entities one, in list controller | |
schemaCopy = angular.copy schema | |
props = schemaCopy.properties | |
# fields displayed on form (only primitive types) | |
simpleFields = fields.filter (k) -> | |
props[k].type != 'array' && props[k].type != 'object' | |
# do not allow to change PKs | |
if model.id then simpleFields = _.without(simpleFields, 'id') | |
if model.nsnid then simpleFields = _.without(simpleFields, 'nsnid') | |
# require all fields (required checkbox (boolean) must be checked!) | |
schema.required = simpleFields.filter (k) -> props[k].type != 'boolean' | |
schema.required = _.chain(schema.required).without('id').without('nsnid').value() | |
# transform date fields (timestamp integer) into date fields | |
dateFields = fields.filter (k) -> props[k].format == 'UTC_MILLISEC' | |
displayFields = simpleFields.map (field) -> | |
if props[field].format == 'UTC_MILLISEC' | |
props[field].type = 'string' | |
props[field].format = 'date' | |
key: field | |
type: 'datepicker' | |
format: 'yyyy-mm-dd' | |
else | |
field | |
# when POSTing, model shall contain only 'owned' entities | |
owningSideArrayFields = fields.filter (k) -> | |
props[k].type == 'array' && props[k].description == 'owningSide' | |
owningSideObjectFields = fields.filter (k) -> | |
props[k].type == 'object' && props[k].description == 'owningSide' | |
jsonStringify = (obj, fields) -> | |
JSON.stringify(obj, fields).replace(/\"([^(\")"]+)\":/g,"$1:") | |
# resolves to object field definition | |
loadObjectFieldDef = (field) -> | |
$q (resolve, reject) -> | |
SchemaResolver.resolve(props[field].$ref) | |
.then (schemaMeta) -> | |
schemaMeta.resource.query().$promise | |
.then (allObjects) -> | |
first = allObjects[0] | |
track = if first then switch | |
when _.has(first, 'nsnid') then 'nsnid' | |
when _.has(first, 'id') then 'id' | |
else null | |
# track is PK of related entities | |
resolve | |
key: field | |
type: 'select' | |
description: '' | |
titleMap: allObjects.map (obj) -> | |
entry = | |
value: obj | |
name: jsonStringify(obj, schemaMeta.stringFields) | |
entry[track] = obj[track] if track | |
entry | |
trackBy: track if track | |
.catch reject | |
.catch reject | |
# resolves to array field definition | |
loadArrayFieldDef = (field) -> | |
$q (resolve, reject) -> | |
SchemaResolver.resolve(props[field].items.$ref) | |
.then (schemaMeta) -> | |
schemaMeta.resource.query().$promise | |
.then (allObjects) -> | |
resolve | |
key: field | |
type: 'checkboxes' | |
htmlClass: 'dynamicforms-checkboxes' | |
items: null | |
description: '' | |
titleMap: allObjects.map (obj) -> | |
value: obj | |
name: jsonStringify(obj, schemaMeta.stringFields) | |
.catch reject | |
.catch reject | |
$q.all(owningSideObjectFields.map(loadObjectFieldDef)) | |
.then (objectFields) -> | |
$q.all(owningSideArrayFields.map(loadArrayFieldDef)) | |
.then (arrayFields) -> | |
# TODO redesign | |
safeModel = | |
if model.id or model.nsnid | |
resource.get | |
id: model.id | |
nsnid: model.nsnid | |
fields: owningSideArrayFields | |
else | |
m = {} | |
owningSideArrayFields.forEach (f) -> m[f] = [] | |
owningSideObjectFields.forEach (f) -> m[f] = {} | |
m.$promise = | |
then: (f) -> f(m) | |
m | |
safeModel.$promise.then (model) -> | |
# exclude non-owned object fields | |
for own k,v of model | |
if props[k] && props[k].type == 'object' | |
if props[k].description != 'owningSide' | |
delete model[k] | |
# non-owned array fields are not served from backend | |
owningSideArrayFields.forEach (f) -> | |
# When rendering array ob objects as checkboxes, none is initially | |
# selected, cause | |
# angular-schema-form/src/directives/array.js:updateTitleMapValues | |
# compares object by reference. | |
# Inject custom comparator here. | |
$scope.$watch (() -> model[f]), () -> | |
model[f].indexOf = (elem) -> | |
_.findIndex this, (other) -> | |
switch | |
when elem.nsnid && elem.nsnid == other.nsnid then true | |
when elem.id && elem.id == other.id then true | |
else false | |
dateFields.forEach (f) -> | |
# Datepicker stores dates as strings, backend expects timestamps. | |
$scope.$watch (() -> model[f]), (val) -> | |
if angular.isString(val) | |
model[f] = (new Date(val)).getTime() | |
$scope.name = name | |
$scope.dynamic = | |
model: model | |
form: displayFields.concat(objectFields).concat(arrayFields) | |
schema: schemaCopy | |
$scope.submitForm = () -> | |
$scope.$broadcast 'schemaFormValidate' | |
if not $scope.updateForm.$valid then return | |
$scope.submitInProgress = true | |
$scope.error = false | |
m = $scope.dynamic.model | |
result = if m.id then resource.update(m) else resource.save(m) | |
result.$promise | |
.then -> | |
$modalInstance.close() | |
.catch -> | |
$scope.error = true | |
.finally -> | |
$scope.submitInProgress = false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment