Play Framework Partial Form Processing

I use the Play Framework, and I have a common use case to update a model using a form in a controller action. But I have some problems that understand the concept, because it just works if you have a form that includes ALL the properties of the model. If you only have a partial form, for example. editing only the password of the user model, this method destroys the model because it sets the other properties of the model to null. Is there an β€œofficial” solution to this problem? In any case, only listen to updates to existing properties?

public static Result update(Long id) { Model model = Model.findById(id); Form<Model> filledForm = modelForm.bindFromRequest(); if (filledForm.hasErrors()) { return badRequest(edit.render(filledForm)); } else { model.update(); flash("message", "Created new Model!"); return ok(index.render()); } } 

Perhaps the solution is somehow related to the fact that the bindFormRequest () method can be called with additional parameters, such as Strings or Map of Strings? But I can not understand the purpose of this. Some understanding of this would be wonderful. Thank you very much!

+4
source share
3 answers

In a recent project, I needed such a function, and I had to redefine the Form class (based on the original playback form) to allow an additional parameter to the bindFromRequest() method.

Taking your code as an example, it will become something like this:

 Model model = Model.findById(id); Form<Model> filledForm = CustomForm.form(Model.class).bindFromRequest(model); 

The idea is to modify only the fields defined in your form and not change the rest of the fields in your model.

To enable this specific binding, you should override the bind(Map<String,String> data, String... allowedFields) method bind(Map<String,String> data, String... allowedFields) (along with bindFromRequest ) in something like this:

 public Form<T> bind(T instance, Map<String,String> data, String... allowedFields) { DataBinder dataBinder = null; Map<String, String> objectData = data; if(rootName == null) { dataBinder = new DataBinder(instance); } else { dataBinder = new DataBinder(instance, rootName); objectData = new HashMap<String,String>(); for(String key: data.keySet()) { if(key.startsWith(rootName + ".")) { objectData.put(key.substring(rootName.length() + 1), data.get(key)); } } } 

Instead of creating a DataBinder with blankInstance() , as the standard playback form class does, you create it with an instance of the model as an argument to the constructor.

+7
source

There is a solution. I would make this a more service oriented app. Where you create forms and models for specific actions: updateUserPassword , updateUserEmail , etc., And these simple methods are implemented in your model.

+1
source

I suggest you take a look at the direction of scala, since you can combine both scala and java in one project, and scala your form can be tuple , for example:

val someForm = Form(tuple("user_id" -> number, "password"->text)) , and then from your request you can use it to update your model:

 someForm.bindFromRequest.fold( formWithErrors => { BadRequest }, data => { // update method takes two parameters user_id and password to update User.updatePassword(data._1,data._2) Ok("...") } ) 
0
source

Source: https://habr.com/ru/post/1487411/


All Articles