I am trying to build dynamically forms from JSON which I receive via websocket.
Therefore I tried to nest two directives, one for the form itself (newForm) and another one for the form items (formItems) which should be generated recursively (using RecursionHelper) from JSON.
In the end I would like to send the form object on blur or on submit. I tried to pass the name for the form dynamically,
<form name='panelitems.html_form'> or
<form name='{{panelitems.html_form}}'>
but I can't manage to access the form object with linked form items from either directive. I want to submit the form data back to the websocket e.g. for validation.
Has anybody an idea, what I am messing up here or knows a better way to do this? Thanks heaps in advance.
I build an example on fiddle: http://jsfiddle.net/3or3p2ba/
HTML:
<div ng-controller="FormCtrl">
<new-form panelitems='json[0]'></new-form>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.directive('newForm', function(RecursionHelper) {
return {
restrict: "E",
replace: true,
scope: {
panelitems: '='
},
template:
"<form name='{{panelitems.html_form}}'> " +
"<form-items parentform='panelitems.html_form' items='panelitems'></form-items>" +
"<br><br>" +
"<pre>{{panelitems.html_form}} = {{ panelitems.html_form | json}}</pre><br>" +
"</form>",
compile: function(element) {
return RecursionHelper.compile(element, function(scope, iElement, iAttrs, controller, transcludeFn) {});
},
controller: function($scope) {
$scope.submit = function(form) {
alert("newForm - submit - " + JSON.stringify(form));
};
$scope.redirect = function(destination) {
alert("newForm - redirect - " + destination);
};
$scope.check = function(input) {
alert("newForm - check - " + input);
};
}
};
});
myApp.directive('formItems', function(RecursionHelper) {
return {
restrict: "E",
replace: true,
scope: {
items: '=',
parentform: '='
},
template: '<div ng-repeat="item in items.children">' +
'<form-items parentform="parentform" items="item"></form-items>' +
'<div ng-if="item.item_type == ' + "'input'" + '">' +
'<input name={{item.item_key}} ng-blur="check(parentform)" type={{item.input_type}} placeholder={{item.item_name}} title={{item.item_tooltip}}>' +
'</div>' +
'<div ng-if="item.item_type == ' + "'button'" + '">' +
'<button ng-click=submit(parentform) class="btn btn-default btn-block">{{item.item_infotext}}</button>' +
'</div>' +
'</div>'
};
});
myApp.controller('FormCtrl', function($scope) {
$scope.json = [{
"html_form": "signup_panel",
"item_type": "itemgroup",
"children": [{
"item_type": "itemgroup",
"children": [{
"item_type": "itemgroup",
"children": [{
"item_name": "First name",
"item_required": "true",
"item_key": "input1",
"item_type": "input",
"input_type": "text",
"item_of": "signup_panel"
}, {
"item_name": "Last name",
"item_required": "true",
"item_key": "input2",
"item_type": "input",
"input_type": "text",
"item_of": "signup_panel"
}]
}, {
"item_tooltip": "Please provide your email address.",
"item_name": "Email",
"item_required": "true",
"item_key": "input5",
"item_of": "signup_panel",
"item_type": "input",
"input_type": "email"
}, {
"item_tooltip": "Please re-enter your email address for validation purposes.",
"item_name": "Re-enter email",
"item_required": "true",
"item_key": "input6",
"item_of": "signup_panel",
"item_type": "input",
"input_type": "email"
}, {
"item_tooltip": "Please enter a password you want to use.",
"item_name": "New password",
"item_required": "true",
"item_key": "input7",
"item_of": "signup_panel",
"item_type": "input",
"input_type": "passwort"
}, {
"item_infotext": "Sign Up",
"item_of": "signup_panel",
"item_type": "button",
"input_type": "click"
}]
}]
}];
});
myApp.factory('RecursionHelper', function($compile) {
return {
/**
* Manually compiles the element, fixing the recursion loop.
* @param element
* @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
* @returns An object containing the linking functions.
*/
compile: function(element, link) {
// Normalize the link parameter
if (angular.isFunction(link)) {
link = {
post: link
};
}
// Break the recursion loop by removing the contents
var contents = element.contents().remove();
var compiledContents;
return {
pre: (link && link.pre) ? link.pre : null,
/**
* Compiles and re-adds the contents
*/
post: function(scope, element) {
// Compile the contents
if (!compiledContents) {
compiledContents = $compile(contents);
}
// Re-add the compiled contents to the element
compiledContents(scope, function(clone) {
element.append(clone);
});
// Call the post-linking function, if any
if (link && link.post) {
link.post.apply(null, arguments);
}
}
};
}
};
});