th:value - if property exists

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

th:value - if property exists

Dachstein
I am posting here, because I have tried Stackoverflow and official Thymeleaf Docs but could not find an answer.

Problem:
I have a Thymeleaf template in Spring MVC which I want to use for two things:
1) For creating a new entity in the database
2) For updating an existing entity in the database

There is only one tiny difference between those two use cases: The entity in the database has a version (optimistic locking) attribute set, so I want to remember this version as a hidden field in the template, which is easy to do.


To understand better where i am coming from here is my code for creating a new entity:

@GetMapping("/new")
    String showMapFormForAdd( Model model ) {

        model.addAttribute( "map", null ); // PASS null into it

        return "map-form"; // same template
    }



And here is the code for updating an existing entity:

@GetMapping("/{mapId}/update")
    public String showMapFormForUpdate( @PathVariable Long mapId, Model model ) {

        GameMap map = mapService.findMap( mapId );

        model.addAttribute( "map", map ); // PASS the real map into it (with version!!!)

        return "map-form"; // same template
    }



And here is the code for the hidden version field in the Thymeleaf template:

<input type="hidden" th:value="${map?.version}" name="version" />


However, I get an Exception, that the property version does not exist.


Question:
How can I ask Thymeleaf, to only query the version and set it to value in the hidden field, if version is available on the "map" model which is injected into Thymeleaf?


Here is my Stackoverflow Link:
http://stackoverflow.com/questions/43952891/thymeleaf-thvalue-if-property-exists?noredirect=1#comment74951520_43952891
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Metroids
<input th:if="${map != null}" type="hidden" th:value="${map.version} name="version"/>
?
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Dachstein
I forgot to mention that I am facing 3 scenarios:

map exists but is NULL
map exists and version does not exist as a property on map !
map exists and version exists as a property on map !

so statements like this WONT work for ALL THREE:
<input th:if="${map?.version}" name="version"/>
<input th:if="${map != null}" th:value="${map.version}" name="version" />

How can I check in Thymeleaf IF A PROPERTY EXISTS ??

Is this somehow possible?

Cheers!
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Metroids
<input th:if="${map != null AND #maps.containsKey(map, 'version')}" type="hidden" th:value="${map.version} name="version"/>

?
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Dachstein
Hi Metroids,
thanks for your replies and for your help.

I forgot to mention one important thing: "map" is not a java.util.Map its a own class "GameMap".

So, #maps.containsKey(map, 'version') will not work.

Is there any chance that Thymeleaf has build in support that to ask like
gameMap.hasAttribute('version') or something like this?

Right now I come up with this solution:
<input type="hidden"
             th:if="${map instanceof T(path.to.GameMap) or map instanceof T(path.to.UpdateMapCommand)}"
             th:value="${map.version}" name="version" />

but it feels so "hacky" that the view has to know about the datatypes passed in.

Like I said, is there any way to check in Thymeleaf whether a property on an object (in my case "map") exists??

Cheers!



Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Metroids
Oh.  No, there is no general thymeleaf support for that -- and that's not really a way you should be doing this.

You should really be using the same command object for both inserts and updates.  If you don't want to do that, rather than trying to have thymeleaf try to figure out the different kind of objects for the form you should have the controllers adding extra attributes to the model that the form can use.  I.e.

Update Controller
model.put("update", true);

New Controller
model.put("update", false);

And on the form, just check that with th:if.
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Dachstein
I totally agree with your answer. Since I want to know if an Update or Insert happened I like the idea of two different commands (also because they UpdateCommand has some additional infos).

Would you think that if the only minor difference is this hidden input tag (needed in update) having two views (one insert, one update) assembled with th:fragement is also a way to go?

Cheers!
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Metroids
Typically I:

* Use a single command object for insert/update.  Since my objects generally have an integer key 'id', if this value is 0 I know it hasn't been saved to the database.  If it's id > 0, I know it's been saved and update instead.
* Use a single view for insert/update as well.  The view doesn't need to care in most cases whether or not it's an insert/update, however, if you do need additional data on an update, you could simply test if it's an insert or an update by th:if="${command.id > 0}".

I don't know how your database is set up, but perhaps you could use version for this as well?  Also, since I don't want users messing with the id, I use @SessionAttribute() to store the object so I don't have to have an input for id.
Reply | Threaded
Open this post in threaded view
|

Re: th:value - if property exists

Dachstein
Thanks for your answer. You helping me a lot!

Version is indeed the @Version annotation in javax.persistence thus for Optimistic Locking. Would you say to put this on the Session as well or as a hidden field? So the user cant mess with ids and even with versions?

Cheers!