Recursively includible Angular directive

Recursively includible Angular directive

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.

Digression

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.

Angular Model

Let’s go back to the code. Even better, let’s consider model examples for this task:

First model for angular repeater
First model for angular repeater (click here to see full code)
Second model for angular repeater
Second model for angular repeater (click here to see full code)
Third model for angular repeater
Third model for angular repeater (click here to see full code)

These models contain typical types of data:

  • strings,
  • integers,
  • floats,
  • arrays and
  • objects.

Recursion problem

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.

Template for angular repeater
recursive-repeater directive (click here to see full code)

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.

Recursion helper

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:

Angular repeater directive
Angular repeater directive (click here to see full code)

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.

 

Important notice

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.

Final thought

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.

  • Ali Reza

    Nice articel…

    • Star Bist

      Thank you, @disqus_ohVMIIdxhU:disqus!

  • Mathew Cormier

    Yep nice article! The recursive-repeater is pretty cool! I totally feel the same way about new frameworks nowadays. It sometimes feels like one step forward and two step back. I tested Angular2 late last year and as much as I liked Angular1, ng2 seemed overly complicated in my opinion. Lots of great features, probably a good choice for large projects, but not really fit for small/medium ones. I currently hesitate between going further into the React territoy or try angular2 one more time to see if it has fixed some of its flaws.
    +1 for linking to the hackernoon article! hehe

    • Star Bist

      Thank you, @mathewcormier:disqus!
      I think React is the way to go. I’m currently in the middle of the learning process.
      But there is another topic that bothers me lately – should frontend developer role be separated to HTML/CSS3/jQuery/JS developer and Angular/Angular2/Vue/React developer? I’m thinking out loud here, but maybe there is something in this.

      • Mathew Cormier

        Indeed, the more parts of a project are decoupled from one another, the more flexibility you get to separate tasks to different individuals with specific expertise. I know a lot a graphic designers that can write good HTML/CSS and simple Angular1 code (they can use ng-if, ng-repeat). This is a real time saver for programmers, that can then focus on more complex code. But with Angular2 and React, the trend seems to be to bundle the view and logic into modular components. It has lots of advantages, but what I heard from graphic designers and web integrators is that it’s a lot more complex for them. F8 2017 is just around the corner though, maybe they’ll come up with a solution to this. Web technologies are moving at such a fast pace.. and that’s what makes them interesting!