I've been working on a complex Angular CRUD-ish project recently and one of the requirements was to create a form based on an MVC model. This model was not definite and could vary depending on many parameters in the application. As a result, I've created a directive that could generate a form for every complex model. Final code is available on Github repository and it's called angular-repeater. Demo is available here.
Sometimes the amount of new frontend technologies feels really overwhelming to me. Everybody is writing about these shinny new frameworks, but there are plenty of applications that are still using "old" technologies (that are not that old). Nobody is writing about them anymore. This is a solution for Angular 1.
Let's go back to the code. Even better, let's consider model examples for this task:
These models contain typical types of data:
- arrays and
Since we need to iterate through these models to display labels and inputs, we should create at least 3 templates for them because they are formatted differently. That seems like a lot of work. Therefore that doesn't sound like the correct solution. Finally, if we try to iterate a model using ng-repeat directive and display every property as an input, we would repeat the code for every property. As a result we'll end up with a bloated and very ugly code.
The solution lies in recursion. It is a programming principle when a function calls itself. In our case, we'll use a recursive-repeater directive that will call itself.
For now, ignore IsObject() and IsNumber() functions.
If we run this code, we'll get an error. This is because Angular 1 doesn't support recursively included directives out of the box. But there is a solution.
The solution is Mark Lagendijk's RecursionHelper service that makes it possible to have recursive Angular directives.
I've already included this awesome service in recursive-repeater directive, like this:
As you could see, we're not using link property when defining directive, we are using compile instead.
This directive works only when jsonData is provided via json-data attribute. label attribute is optional and is used to display label for every input. You could see an example in a previous section.
In addition, there are 2 helper functions in a directive:
- IsObject() - used to check model property type and
- IsNumber() - used to check if model property key is a number.
The last one is used to decide whether an object property is a regular array. If so, then the name of the input will end with '' characters resulting with correctly submitted form. If not, object is provided and the name of the input will be formatted like this:
label[objectKey]. This is very important when submitting data to server, as many programming languages cannot read form data that is not formatted in fore-mentioned fashion.
There you have it, recursively includible Angular directive.
This particular directive is used to display label and input for every model property. I'm considering to extend this functionality and allow user to define any other output.
I'm also considering to compare this technique with other popular frameworks, like Vue.js, Angular 2 and React.
Please let me know what do you think, leave a comment bellow or tweet me.