Velocity solution like Thymeleaf - thymeleaf

I would like to know if I can use Velocity Template like Thymeleaf when I have an object in Spring with attributes, let say, (product.courseName) and I want to send it to an HTML page this way
h1 th:text="${product.courseName}" HTML Example Course Name /h1
so i can show it directly...
Thymeleaf let me isolate the HTML development from the Spring Coding, but I cannot find such a simple approach in Velocity. Can I show the HTML with "HTML Example Course Name" in a browser and the real Course Name from each object when Velocity executes (just like in Thymeleaf)?
PD: I would appreciate any documentation reference.
SPRING CONTROLLER
#RequestMapping("/product/{id}")
public String getProductById(#PathVariable Integer id, Model model){
model.addAttribute("product", productService.getProduct(id));
return "product";
}
PRODUCT.HTML
<div class="row">
<div class="col-md-12">
<h1 th:text="${product.courseName}">Course Name</h1>
</div>
</div>
Thanks

Yes but not exactly you are doing it. If you take a look the section properties of the reference documentation it's explained how to do it:
Properties
The second flavor of VTL references are properties, and properties
have a distinctive format. The shorthand notation consists of a
leading $ character followed a VTL Identifier, followed by a dot
character (".") and another VTL Identifier. These are examples of
valid property references in the VTL:
$customer.Address
$purchase.Total
And aswell is explained, if you use it, it calls the getter of the property like thymeleaf surely does.
$customer.Address. It can have two meanings. It can mean, Look in the
hashtable identified as customer and return the value associated with
the key Address. But $customer.Address can also be referring to a
method (references that refer to methods will be discussed in the next
section);
$customer.Address could be an abbreviated way of writing
$customer.getAddress()
........
edited
So in resume, don't use thymeleaf tags like th:text.
<h1>$product.courseName</h1>

Related

Thymeleaf th:field model evaluation

I'm including dynamic content to a view using a custom Thymeleaf attribute processor that simply adds additional nodes while processing the attribute itself.
The code I use is very similar to the one below:
final Template template = arguments.getTemplateRepository().getTemplate(
new TemplateProcessingParameters(arguments.getConfiguration(), "name-of-a-view", arguments.getContext()));
final List<Node> children = template.getDocument().getChildren();
// Add to the tree.
for (final Node node : children) {
element.addChild(node);
}
This works fine, but breaks when the included nodes contains forms that use th:object and th:field.
I put the model I need inside the node variable map and in fact th:object does find and retrieves the object, but th:field does not seems to care and breaks with a
Neither BindingResult nor plain target object for bean name 'model' available as request attribute
From my understanding (step-by-step debugging), it seems to me that th:field only search for the model in the request context.
Am I missing something here?
Thank you in advance.
No, you're spot on. I'm still not sure why the binding is different for th:field than other th: attributes, but it definitely works differently. Essentially, you can't use th:field unless your th:object is on the model. The workaround is to stop using th:field and just specify your input attributes manually, like:
<form action="#" th:action="#{/process}" th:object="${objectFromList}" method="post">
<input type="text" id="fieldName" name="fieldName" th:value="*{fieldName}" />
</form>
I realize this post is old. Hopefully, this will help someone who is running into this quirk.

Direct Model.Property versus Html Helper DisplayFor in Razor

Is there a reason to use preferably one of these:
#Model.Property
#Html.DisplayFor(m => m.Property)
I never arrived in a crossroad where one works differently from the other.
There is any difference?
Model.Property - as you know - will just write out the value of the property in question. Html.DisplayFor(m => m.Property), on the other hand, will call a display template, which can render out other markup around the property value.
For example, you might define a display template like so:
#model String
<div class="property-wrapper">
<p>#Model.Property</p>
</div>
The surrounding divs will be rendered around the value of the property when using DisplayFor (if the display template is selected, which typically means it has a filename matching the property's type, is specified in the UIHint attribute for the property, or is explicitly specified in the call to DisplayFor.
You also have access to model metadata in your display templates, meaning you can do something like this:
<div class="property-label">
#Html.DisplayNameForModel()
</div>
<div class="property-value">
#Model.Property
</div>
Display templates give you a huge amount of flexibility and reusability. The best way to explore this is to start building custom templates and see where it takes you.

Play Framework - Variables in URL instead of as ? parameters

I'm a just starting to learn Play, so this is a basic question, but I've searched every term I can think of and can't find the answer.
All I want to do is have a page that on submit takes an ID from a text field and puts it in the URL directly (e.g. /myservice/person/123). Instead, the URL being generated contains the ID as a parameter (e.g. /myservice/person?id=123).
I know my controller is being invoked correctly if I type the URL in by hand, so I'm inclined to think my routes file is correct. This is what my entry looks like:
GET /person/:id controllers.PersonActions.getPerson(id: String)
So I'm assuming something is going wrong in my template, which looks like this:
#form(routes.PersonActions.getPerson(personID)) {
#* #inputText(personForm("id")) *#
<input type="text" name="id" value="#personID">
<input type="submit" value="Get">
}
You can see that I've commented out another way using #inputText also, but it behaves identically for me. I'm not tied to either method.
I've also tried this using POST, which removes the ID from the URL entirely, which I don't understand either, but since I'm just doing a simple query, I'd rather use GET.
Can anyone help me understand what's going on here? I feel like there's something fundamental about how routing/URLgeneration works that I'm not understanding, but I've gone through the tutorial and the docs so many times today I'm at a loss.
Thanks in advance.
Oh, and I'm using Java 7, Play 2.1, and Eclipse Kepler
I think you are trying to skip a step and map form request data from a view directly to a controller method. You will need to submit the form, have a controller parse the data and then render the next appropriate view based on the data you parsed from the form.
Remember that the personId in your view is a parameter that is bound server-side when the view is rendered. In this case, the submit url of the form is hard coded to whatever personId is passed in to the view at render time -- it doesn't change dynamically when the input box changes.
To fix, add a controller method to accept requests from /person (I'm guessing this based on the part in your question that says the form is being submitted to /person?id=123, in any case it should be the URL of the form you've shown above)
e.g. if you want to use a GET method for the form add:
GET /person controllers.PersonActions.findPerson(id: String)
and in your PersonActions controller (I'm assuming you're using Java, if scala I'm sure you can adapt it from the docs)
public static Result findPerson(String id){
/*
* I'm assuming this method exists and works because you say
* when you type in /person/123 manually the routing works
* and your router says getPerson is the method name for that URL.
*/
return getPerson(id);
}

Is it possible to I create LabelTemplates for Html.Label and Html.LabelFor() in ASP.NET MVC?

For reasons that are questionable but practical, I'd like to create LabelTemplate defaults, just like EditorTemplates or DisplayTemplates.
So instead of this:
#Html.LabelFor(x => x.PropertyName, "Property Name")
or instead of this(the better way to do it in a View Model):
[DisplayName("Property Name")]
public string PropertyName{ get; set; }
I want this:
#Html.LabelFor(x => x.PropertyName)
With this (in a folder like this: /Views/Shared/LabelTemplates)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.String>" %>
//Display logic here
Can you help a coder out?
Create your own custom html helper.
http://develoq.net/2011/how-to-create-custom-html-helpers-for-asp-net-mvc-3-and-razor-view-engine/
This is the code you can use to convert your property names:
Regex.Replace("PropertyName", "[a-z][A-Z]", m => m.Value[0] + " " + m.Value[1]);
I know this isn't strictly an answer to your question, but since I still want to suggest a plan of action, I'll post it like this rather than in a comment.
Are you sure you want this?
If you manage to do this, you will set the label of a field to some value based on its type. This might seem tempting at first glance - you could possibly save yourself some key strokes every here and there.
But what happens if you e.g. have a type Address containing some properties for street name, number, zip code etc, and then want the user to fill in the home address and the work address in the same form - how would you label them differently and still use the same type? And even worse - do you really want the same label on all your strings? In order to avoid these two scenarios, you'll need to resort to Html.DisplayFor(m => m.PropertyName, "TemplateName") anyway, which means you'll be in just as sorry a situation as you already are. Furthermore, you'll have at least two places you have to look to find the correct display logic for your label, rather than just one.
Remember that there is no absolute requirement to use the LabelFor() helper - you can just as well just roll your own extension method on HtmlHelper, or even ignore them and output plane HTML:
<label for="Person_HomeAddress">Home address</label> <!-- the ID might be wrong -->
<%: Html.EditorFor(m => m.HomeAddress) %>
Since the EditorFor() outputs an ID matched to the name of the model and property names, you'll be fine.

Grails: Supplying Data to a Global UI Element

Please pardon this newbie question...
In Grails, if I want a partial to be embedded in a layout so that it appears globally, which requires live data, let's say a list of categories, where is the best place to pull the category data to feed it into the view?
I realize this is a very basic question, but I haven't seen this covered in any tutorials yet.
I started this as a comment to Bill James's answer but I figured it might be longer. Bill suggeseted using groovy code inside ${} to make the template (called partial in Rails) work globally:
<g:each in="${ Category.findAll() }" var="cat" />
But, you should not just add code if you dont feel like it might mess up your tidy xml/html. You can always put it in a closure inside a TagLib and thus make it a Tag. The closure must have no parameters, or an 'attr' parameter, or an 'attr' and 'body' parameters but other signatures are invalid.
class CustomTagLib {
static namespace = 'cus'
def categories = { attr, body ->
g.each( in: Category.findAll(), var: attr?.var ?: 'categories' )
}
}
Then you can use that tag into the template with the namespace you chose:
<cus:categories />
Personally I prefer using tags since most of the time it is a reusable code, so it's better for not violating the DRY principle.
You want to put it in grails-app\views\layouts\main.gsp. That's the default layout that most generated code (and likely most examples that you'll see) will use.
Check out the sitemesh section of the grails documentation.
I think you're trying to ask... "How do I feed the category data to the view when I don't know which action caused the page to render, so the action can't add the data to the model?" If that's so, you can use Groovy code directly in the ${} block, such as:
<g:each in="${ Category.findAll() }" var="cat" />
Note that findAll is added to every Model class, and can be called statically (via the classname, not an instance).
Hope this helps

Resources