2015-06-10

Collection extraction from forms

For the Ninja framework

Ninja quickly became one of my favorite web frameworks. For REST, MVC, dependency injection, database and other basic stuff, it mostly is very convenient. But what about the more complicated things web development often demands? Because documentation is rather sparse for it, here's how you can use built in functionality to extract a collection of objects from a form.

My example has a simple edit form for a trip model.A trip can have multiple stops, for simplicity represented by a String. With a POST route in the TripsController, Ninja can automatically parse the request, extract your form data and inject the Trip instance into the method call - one has to add a Trip reference the controller's signature and it just works, how great is that:


public Result saveTrip(Context context, Trip trip) {

However, the documentation states, that the extraction only works with primitives and arrays of them. This means no other collections, like Lists, can be extracted automatically. But no one uses plain arrays as fields... So, an easy way to circumvent this limitation, is to add the given items within the collection to the form and provide the same name attribute for all of them:
<#list trip.stops as stop>
  <tr>
    <td><input type="text" class="form-control" id="stops[${stop_index}]" name="stops" value="${stop}" ></td>
  </tr>
</#list>

Then, add the String[] stops parameter to your signature and you're done.


public Result saveTrip(Context context, @Params("stops") String[] stops, Trip trip) {

In my case, I updated all of the trip instance's stops with the stops automatically injected and saved the objet. Can't get any easier, I think.

I'm not yet sure if this would work for more complex (means no-primitive type) objects. For this purpose, argument extractors were introduced. The documentation is again a bit sparse about them - a first try seemed that argument extractors that try to parse the request data for object extraction tend to be a bit hacky. Will be continued.