Define validation properties outside Panel in Wicket - validation

I need to define Wicket validation messages in .properties file of a page for a reusable panel. I will give an example (code snippets below):
MyPage class contains MyPanel with a fragment MyFragment in which there is a component called MyComponent (TextField of a type BigDecimal).
I need to define 3 instances of reusable MyPanel on the MyPage and I need to define a validation key for the MyComponent in MyPage (because they are used in a different context).
class MyPage extends WebPage {
public void onInitialize() {
super.onInitialize();
add(new MyPanel("fuelConsumption");
add(new MyPanel("populationGrowth");
add(new MyPanel("averageGrade");
}
}
class MyPanel extends Panel {
public void onInitialize() {
super.onInitialize();
Fragment fragment = new MyFragment("fragment");
add(fragment);
}
class MyFragment extends Fragment {
public void onInitialize() {
super.onInitialize();
add(new MyComponent("component");
}
}
class MyComponent extends TextField<BigDecimal> {
}
}
So, I need to add a validation messages for all 3 usages of the MyComponent field of type BigDecimal into the MyPage.properties, something like:
fuelConsumption.fragment.component.IConverter.BigDecimal=Fuel consumption must be a decimal
populationGrowth.fragment.component.IConverter.BigDecimal=Please check the population growth format
averageGrade.fragment.component.IConverter.BigDecimal=This is not an average grade!
I deliberately use different kinds of validation messages, I don't want to use a single one with configurable parameter
When I add MyPanel.properties and put a line like this:
component.IConverter.BigDecimal=Component is not a valid BigDecimal.
it works fine, but I really want to specify it outside the reusable panel (so that the panel may be used in other ways and meanings).
How would I do that?
When I try to add the lines above, it does not work, nor in any way I tried, like omitting the "fragment" or "component" from the properties string. Nothing helps.
Thanks for any suggestions!

Your solution looks good to me.
Enable debug logging for org.apache.wicket.resource.loader.ComponentStringResourceLoader to see which keys are searched.

Related

Create a Base TagHelper with no TargetElement

I'm creating a library of MVC6 TagHelpers for a large project.
I find myself writing certain functionality in these TagHelpers again and again.
I'd like to make a base TagHelper that all the others inherit from to remove all the duplicated code.
The issue is this - suppose I create a base TagHelper as below:
public class BaseTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//Some implementation...
}
}
Now, when I go to write a view, I will have intellisense suggesting the taghelper <base>.
Is there any way I can tell intellisense that this isn't a TagHelper I actually want to use, just a base class containing implementation common to other TagHelpers I've created?
Create it as an abstract class, see some examples in the official MVC Core repo like CacheTagHelperBase
public abstract class BaseTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//Some base implementation...
}
}

WebApi Controller action parameter base class for common features

Where WebApi Controller actions share identical features, E.g. pagination and partial response, is it possible to create a base class to model these parameters?
For example, this URI:
http://letsdoitclean.com/api/v1/athletes?clean=true&fields=name,age&offset=0&limit=25
might map to:
class AthletesController
{
IHttp Get(bool clean, string[] fields, int offset, int limit)
{
...
}
}
However, fields, offset and limit are concepts that will be frequently used. So I want something like:
abstract class ActionParameter
{
public string[] fields;
public int offset;
public int limit;
}
class AthletesGetParameter : ActionParameter
{
public bool clean;
}
class AthletesController
{
IHttp Get(AthletesGetParameter param)
{
...
}
}
Can I do it?
This could also be achieved by adding it globally to your WebApiConfig so that you don't have to mark it up in every single controller action:
config.ParameterBindingRules.Insert(0, descriptor =>
typeof(ActionParameter).IsAssignableFrom(descriptor.ParameterType)
? new FromUriAttribute().GetBinding(descriptor)
: null);
Yes, absolutely you can do this. ASP.NET will handle the parameter binding if you, in this example, specify the FromUriAttribute for the complex object:
public class AthletesController : ApiController
{
public string Get([FromUri] AthletesGetParameter athletesGetParam)
{
// ...
}
}
The only thing I would argue against from your question, is the name of the abstract class. It doesn't really describe the base class all that well and what it's intended for. Maybe something like abstract class PaginationParameter or something similar. To call it ActionParameter could confuse you in the future (or other programmers) that all action parameters should derive this class, and I don't think that's right.
Maybe minutia on the naming of the base class, but to answer your direct question... yes you can do this.

Spring change the binding target

I have 2 class like this :
public class A {
B b;
}
public class B {
String id;
}
I have a form that modify my object A et its subs object :
it send
b.id=XXXXX
What I want to do is
a.setB(BDao.findbyId(b.id));
I want to look up in DB for the B object and set it on my object A instead of seting the id property of the A.b object
I can do it by hand in the controller after the automatic binding:
a.setB(bDao.findbyId(a.getB().getId));
But isn't it possible to do this with a Custome editor ?
thanks !
I think it would be possible. You would have to write a custom init binder, which is basically a 'PropertyEditor', in which you can extend 'PropertyEditorSupport' class. It would look something like:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(MyClass.class, new MyCustomePropertyEditor());
}
In which your MyCustomePropertyEditor would look something like:
public class MyCustomePropertyEditorextends PropertyEditorSupport {
public void setAsText(String text) {
MyClass mc = service.doSomethingToLookUpMyClass(text);
setValue(mc);
}
}
In the JSP/View, you will need to change your tags so they set you object reference, not the reference's id. This has obviously been written off-the-cuff and by memory, so mileage might vary. You may also want to consider looking into a custom validator as well, which you can also setup through the init binder, I believe. Documentation is here.

Good way to define module in Spring mvc

Im using Spring mvc 3.1 version and Apache Tiles 2.2.2 version i'd like to define some common modules in my applications pages.
For example i want to define a menu in the top, a left side and right side,.. all my page will display these block.
Im using Tiles to define the differents blocks, some part of tiles implements ViewPreparer because i need to get information from database, know if the user is logged,... each tile is responsable of its own module(get data, set attribute for the jsp...).
Is it a good way to create some modules ? Or should i define a controller who will define the data, the business...to all page modules ? (left side, right side, menu...)
If your common module only consists of HTML then it doesn't matter how you do it. Tiles template is sufficient.
The problem is if the common module need models to be populated on the controller. You don't want to duplicate the code on every single of your controller which view includes the common module.
One approach you can take is subclass your controller with a class that populates common module model, eg:
public class CommonHandler {
#ModelAttribute("loggedInUser")
public UserInfo getLoggedInUser() {
// check and return logged in user if any here..
}
}
#Controller
public class MyController extends CommonHandler (
#RequestMapping(..)
public String myHandler() {
// ...
}
}
In above example if myHandler is requested, getLoggedInUser from CommonHandler class will automatically be called to populate loggedInUser model. In your view you just obtain it using ${loggedInUser}
When using ViewPreparerSupport which implements ViewPreparer, it works very well :
#Component
public class MyPreparer extends ViewPreparerSupport {
#Autowired
private UtilisateurService utilisateurService;
#Override
public void execute(TilesRequestContext tilesContext,
AttributeContext attributeContext) {
//information to set for the jsp tile
}
}

Mvc3 - Best practice to deal with data which are required for (almost) all requests?

I am creating an application in mvc3 and wondering how to deal with database data which is required for all application requests, some of them depends on a session, some of them depends on url pattern basically all data is in database.
Like to know best practice
What I do in my applications and consider to be the best practice is to load your common data to the ViewBag on the Controller constructor.
For every project, I have a DefaultController abstract class that extends Controller. So, every controller in the project must inherit from DefaultController, instead of Controller. In that class' constructor, I load all data common to the whole project, like so:
// DefaultController.cs
public abstract class DefaultController : Controller
{
protected IRepository Repo { get; private set; }
protected DefaultController(IRepository repo)
{
Repo = repo;
ViewBag.CurrentUser = GetLoggedInUser();
}
protected User GetLoggedInUser()
{
// your logic for retrieving the data here
}
}
// HomeController.cs
public class HomeController : DefaultController
{
public HomeController(IRepository repo) : base(repo)
{
}
// ... your action methods
}
That way you will always have the logged in user available in your views.
I do the same as #rdumont but with one exception: I create a CommonViewModel which I use to define all common properties that I use.
public class CommonViewModel
{
public string UserName {get;set;}
public string Extension {get;set; }
}
Declare a property in the base controller:
public abstract class BaseController : Controller
{
protected CommonViewModel Commons { get; private set; }
protected virtual void OnResultExecuting(ResultExecutingContext filterContext)
{
ViewBag.Commons = Commons;
}
}
By doing so I get everything almost typed. The only cast that I need to do is to cast ViewBag.Commons to the CommonViewModel.
Best is to avoid ViewBag at all.
See this answer, which details how to use Html.RenderAction() for that purpose:
Best way to show account information in layout file in MVC3
I'd suggest using a base ViewModel class.
So a base class with properties/functions which should be available at any point.

Resources