Formex - a form library for Phoenix inspired by Symfony

I thought about something that would return form inputs etc. in JSON to use it in Vue/React/Elm
But in my every React app I have max several inputs so why I would use Formex here. My admin panels however are always in simple HTML rendered on backend. Like in the old days :smiley: So I don’t need such JSON functionality yet

1 Like

Would you be interested in working on a super opinionated FlaskAdmin-type admin backend on top of Formex? It’s not too hard, just write some macros that create a controler, a view and a form type based on the schema and possibly some configuration options that overwrite the defaults.

The tricky bit is always how to add some configurability, but I think there’s a place for super simple backend that can eb generated with a couple lines of code.

2 Likes

Sure.

Did you saw ex_admin? Not as good as our project would be because of lack of Formex :smiley: but what if we want to reinvent the wheel? Anyway, I have never tried it

1 Like

Yes, I contributed some ideas to v2.0 (talon) by the same author. @smpallen99 seems to have stopped working on that a while ago and he was going the opposite direction: less magic, more generators. I think it should be the other way around: more magic, fewer generators xD If you find yourself requiring lots of customizations you’ve probably outgrown these kinds of solutions and need to design from scratch.

1 Like

I think such a project should have an API like this:

defmodule MyApp.MyAdmin do
  use SomeMagicHere
  defresource MySchema1, options: [...]
  defresource MySchema2, options: [...]
  defresource MySchema3, options: [...]
  defresource MySchema4, options: [...]
  # ...
end

It would define controllers for the resources (using macros, no code generation). Then you’d just add the stuff to the router.

defmodule MyAppWeb.Router do
  # ...
  require MyApp.MyAdmin
  # ...

  MyApp.MyAdmin.routes "admin/"
  # ...
end

The :options would allow the user to customize some things, and even add extra controller actions. For example:

defresource User, options: [
  extra_actions: [
    change_password: &PasswordController.change_password/2
  ]
]

My idea was to have zero work for the default case (just define the schemas and you’re good to go) and incrementally more work for more advanced use cases. I think that FlaskAdmin or FlaskAppBuilder are good sources of inspiration.

They take tons of options, with varying levels of granularity depening on how much customization you need. You can change the field labels, the order of the fields, etc. They do all of this with class inheritance, of course, but it an be done by merging option dictionaries r keyword lists.

1 Like

Years ago I built a CakePHP based admin backend generator. It worked really well and had CRUD level access control lists down to the form field. We didn’t use generators because we needed that admin interface to change as our application grew as long as we followed the proper database naming rules. You could override those at any point though.

The trickiest bit with configuration really just boiled down to being able to pass a nested map down the function chain to make deep level changes from the highest level when necessary.

With Elixir though, I’d be more concerned about properly leveraging IOLists and I’d probably go with the generator approach as well. Something like the Taggart library I just saw might be a good fit for it.

Ideally, you’d want to be able to specify configuration details for specific templates, then run a mix task to regenerate the proper template code for each one so that it follows the proper compilation process, etc.

1 Like

That doesn’t sound that tricky. It’s just a job for Map.merge/2

Where do IOLists enter the picture? You use Taggart if you want, of course, but you can just generate EEx templates end compile them with Phoenix’s EEx engine, which I think uses IOLists anyway. Those templates could be compiled at macro-expansion time. Is there anything I’m not seeing here?

1 Like

I might have misunderstood what you were going for when you mentioned going away from generators earlier.

1 Like

Going away from generators means that you supply a minimal amount of configuration and the framework generates the rendering functions at compile time without any extraneous artifacts being written to disk. Such render functions might use EEx template, of course, but those templates are not available for customization by the user.

2 Likes

See…that explanation looks like a different type of generator to me. We’re on the same page though.

1 Like

Great work on formex, only just found it. A major time saver.

2 Likes

Is there any way to make forms use the HTTP PUT method instead of POST? I can’t find an option for that in formex_form_for to change the (default) POST method.

Use:
formex_form_for(form, action, method: :put)

Almost all of options are passed to a Phoenix.HTML.Form.form_for/4 options. You can check the implementation here:

If you are using formex_ecto, then this option is set by default depending on create/update action

1 Like

Thanks! Everything works now.

I have just improved the documentation for this function

https://hexdocs.pm/formex/Formex.View.html#formex_form_for/4

2 Likes

@jakub-zawislak, Phonix’s respurce generators + Formex give you a pretty cool CRUD interface almost for free. The only thing missing is filters for the Index view. We can probably just copy what torch does, but we can improve on it because we can use Formex itself to write the form for the filters.

Instead of using generators we can use macros (as I mentioned above) that generate templates and controllers for us, but then it becomes hard to add customizations. The amount of code one needs to generate is actually quite manageable because Formex does some of the heavy lifting for us.

PS: Using macros is much cooler than using generators, of course, but generating “normal”
controllers makes it much easier to add things like authorization with the proper level of granularity, for example, because you can add new plugs and even add code inside the controller functions.

Thanks, much better now :slight_smile:

Also, I’ve discovered that if you’re building an Admin panel and you the build_form callback inside the module that defines the Ecto schema everything becomes much less verbose. I’m still not sure that this level of coupling is a good thing.

I think it is, because you should define a new context for your Admin interface, and there is no problem is the schemas in that conext come with some helper functions that make using forms easier.

Great work!

2 Likes

hi,
I am trying to use formex ecto to create a nested form but I get some odd errors even though I went through the a few times… I keep getting an error saying that create_form is undefined… nay ideas why that might be the case?
Anyway congrats for the library and I really hope to manage to get in working :slight_smile: