I have an integer field and when i enter a non integer value (let's say a symbolic one) the Feedback panel should be triggered automatically with default message, but it does not work, I have to call it in onError method of the form by method error().
This is the textField, that i use:
RequiredTextField<Integer> intField =
new RequiredTextField<>("intValue", integerValue,Integer.class);
this is my simple FeedBackPanel:
fragment.add(new FeedbackPanel("feedback"));
it works only when i call method error() in method onError() of the form.
Could you show us how you create your Form and the Model you use? As far as I understand it you will want to bind a Model to your Fields. My best guess is that your Model does not have a property "intValue".
You might want to (re)visit the Wicket Wiki "More on Models".
I'm not sure how you are setting your model. And once you add RequiredTextField it will not allow you empty and since you set the Integer type it will not allow characters to be entered.
I have tried some code snippet which is working perfectly and validating.
HomePage.html
<html xmlns:wicket="http://wicket.apache.org">
<body>
<form wicket:id="someForm">
<div wicket:id="feedback"></div>
<input type="text" wicket:id="requiredText">
<input type="submit" value="submit">
</form>
</body>
</html>
HomePage.Java
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;
public HomePage(final PageParameters parameters) {
super(parameters);
Form form = new Form("someForm");
form.add(new FeedbackPanel("feedback"));
IModel integerValue= Model.of("");
form.add(new RequiredTextField("requiredText",integerValue,Integer.class));
add(form);
}
}
Please let me get back to me on this incase if you need anything .
Related
I use jquery datepicker and it not display after I click ajax button.
Is there any way to show datepicker again after click? I use wicket 8.
BasePage.java
public class BasePage extends WebPage {
...
}
BasePage.html
<body>
...
<script src="/js/jquery.min.js"></script>
<script src="/js/jqueryui.min.js"></script>
<script src="/js/main.js"></script>
</body>
HomePage.java
public class HomePage extends BasePage {
public HomePage() {
SearchForm searchForm = new SearchForm();
Form<SearchForm> form = new Form<>(new CompoundPropertyModel<SearchForm>(searchForm))
AjaxButton btn = new AjaxButton() {
protected void onSubmit(AjaxRequest target) {
// Handle search data
...
target.add(form);
}
};
TextField<String> date = new TextField<>("searchDate");
form.add(date);
form.add(btn);
}
}
HomePage.html
<wicket:extend>
<form wicket:id="form">
<input wicket:id="searchDate" class="datepicker" />
<button wicket:id="btn">Search</button>
</form>
</wicket:extend>
main.js
$(function() {
$(".datepicker").datepicker();
...
});
After click ajax button all script in file main.js not working
Please help me.
when you update form via AJAX you replace each element inside it, which includes the input field you use with datepicker. But doing so you loose the javascript setting done by main.js when page was first loaded.
You can solve this in two ways. First, you could update only those elements that need to be refreshed, for example the component that you use to show search result (I suppose there must be such an element in your code).
The second solution, more heavier and complicated, is to make a custom TextField component that execute the datepicker javascript code each time is rendered.
An example of such solution can be found is in the user guide: https://wicket-guide.herokuapp.com/wicket/bookmarkable/org.wicketTutorial.ajaxdatepicker.HomePage
I would recommend to follow the first solution as it's more natural and simpler and requires less code.
UPDATE:
If you want to refresh the textfield another simple solution is to use target.appendJavaScript​ to reapply the datepicker plugin:
target.add("$('#" + date.getMarkupId() + "').datepicker();");
this should add the datepicker to the fresh new field.
I have a simple partial with a form inside which is used as a search bar.
#using (Html.BeginForm("Details", "Projects", FormMethod.Get))
{
<div class="row" style="margin-bottom: 20px;">
<div class="col-lg-3 pull-right">
<input type="search" class="form-control" placeholder="Search Code" id="projectSearch" name="code" />
</div>
</div>
}
This should post to my Projects Controller Details Action, however this isn't happening, and I believe this because of the [Route] attribute that is applied to the action, as when I comment this out, the form posts correctly. However I want to use the [Route] attribute.
The action looks like this:
[HttpGet]
[Route("{code}/Details")]
public ActionResult Details(string code)
{
if (code == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
...
return View(viewModel);
}
When the attribute is in use the form will post to this url:
/Projects/Details?code=PP61
which doesn't map to the correct action. Instead I get a resource cannot be found error.
The expected/desired url should look like
/Projects/PP61/Details
This works fine if I create a Url.Action or browse to the URL, so I know this action works, however it doesn't work with a form post. Any ideas why?
Thanks.
Change [HttpGet] to [HttpPost] on the controller and FormMethod.Get to FormMethod.Post in the view.
I have one solution to the problem, it doesn't however answer why this wasn't working in the first place. I have created a separate action which is for the search bar to POST to, this action then redirects to the GET action which I was trying to reach in the first place.
[HttpPost]
public ActionResult ProjectSearch(string code)
{
if (code != "")
{
return RedirectToAction("Details", new { code });
}
else
{
return RedirectToAction("Index");
}
}
This now works correctly, but I would still love to know why this didn't work to begin with if any body has any ideas. Cheers.
First of all if this is a double post, my bad. I feel I tried my best to look for this, and I cannot find it.
What I'm trying to do is create a quick CMS editor. I have an editor page (PageViewModel class) and then, in this case, using that editor as way to create a new page (Page class).
I've been trying to go "by the book" on how to submit data via forms created in MVC 4, which is basically, through the WYSIWYG editor when adding a view and selecting Create. For it to bind the fieldset data, it needs the view model. My problem is that I don't want the form model to be based on the view model. In my scenario, I have a PageViewModel class, and I also have a Page class. Just know that the PageViewModel is composition pattern, which combines a Page with other items.
In the case here, I see everywhere using the #model to generate that content like:
<fieldset>
<legend>Page</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
How do I have fieldset generate or reference another class type other than the #model, so I can use a different model?
Thanks everyone,
Kelly
Kelly,
in your PageViewModel you can have a property that points to another ViewModel, for example:
public class PageViewModel
{
public Page Content { get; set; }
}
public class Page
{
public int Id { get; set; }
public string Foo { get; set; }
}
And then you can create a strongly typed view for "PageViewModel", that will renders a partial view named "Page":
#model MvcApplication2.Models.PageViewModel
#{
ViewBag.Title = "PageViewModel";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Html.Partial("Page",#Model.Content)
That is the partial view's code, it is strongly typed as well:
#model MvcApplication2.Models.Page
<fieldset>
<legend>Page</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Foo)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Foo)
#Html.ValidationMessageFor(model => model.Foo)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
You can alternatively also use the ViewData property. In your controller, your code would look like this:
public ActionResult Index()
{
Page page = new Page();
ViewData.Add("Page", page);
return View();
}
And in your view, it is almost the same:
#Html.Partial("Page", ViewData["Page"])
Create a different view that uses your new model, or make the current view take a base version of a model, e.g., an Interface or abstract (virtual) class that the other two models inherit from.
It seems like it may be a lot of work to update two forms, but if you think the two models will vary greatly, it's easier to separate them now then to try to maintain a lot of if-then code in the view later on. If they are relatively similar, why not use the method mentioned above, OR just use the same model?
Look idea is that in your view you can pass model which can be any class containing other classes or so called ViewBag.
For example, in your action method you can populate a model and pass it to the view
var model = new MyModel();
model.Text = "";
return View(model);
But if you need to pass something else and more important you don't want to include this in your model then use ViewBag.
For example, we pass Title.
ViewBag.Title = "My Page";
Idea is that viewBag is a dynamic generated object so you can add any properties to it and use them in the view later.
#ViewBag.Title
So after submitting a form you will have only model containing a user's text, but not title.
I am using DockLayoutPanel as my main panel.
Dependent of the menu I click I change the center-part of the DLP.
For example I change either to form1.ui.xml or to form2.ui.xml.
Both of these forms have a "marker" implemented to display an error message:
<g:HTMLPanel ui:field="messageblock"/>
I am following the MVP Pattern (I use EventBus for communication) and so far everything works great. The only thing I can't figure out is how to replace the content of messageblock. Or to be more concret how to get access to messageblock from my MainPresenter. The main idea behind this stuff is to bundle the error-handling in one presenter...
I am looking for something like
final Panel panel = DockLayoutPanel.get("messageblock");
panel.add(subwidget);
I appreciate every hint...
You could either make the Display responsible for rendering the error (make some interface with a renderError(Error) method) or make the Display return an HTMLPanel that something else can render the error into (some interface with a HTMLPanel getErrorPanel() method). The latter is closest to what you're talking about. Have Form1 and Form2 both implement HasErrorPanel and then call getErrorPanel().add(subWidget).
Here is the conclusion I came to. Maybe it helps someone else.
It's based on what Riley Lark recommended - Thanks to Riley btw.
RegistrationPresenter here is responsible for the registration process and shows a registration form to the user. The error-message should be displayed as close as possible to the place where the error occurred.
Without error http://www.mikemitterer.at/fileadmin/stacktrace_imagehosting/screenshot-778.jpg
An error occurred:
Error popped up http://www.mikemitterer.at/fileadmin/stacktrace_imagehosting/screenshot-780.jpg
Here now a rough description how I implemented this behavior:
public class RegistrationPresenter implements Presenter {
public interface Display extends StatusDisplay, HasMessageBlock {
Widget asWidget();
void setData(RegistrationTO registration);
}
private final Display display;
private final EventBus eventBus;
...
as you can see it's Display implements HasMessageBlock:
public interface HasMessageBlock {
void showMessage(Message message);
void hideMessage();
}
There exists a UIBinder-Widget MessageBlock (MessageBlock.ui.xml + MessageBlock.java)
(messageblock will be turned to invisible in it's constructor)
<g:HTMLPanel styleName="errorblock" ui:field="messageblock">
<div id="errorMsg" class="flurid">
<div class="row">
<div class="column width_15/16">
<h3><ui:msg key="errorblock.headline">An error occurred...</ui:msg></h3>
</div>
<div class="column orientation-right islink width_1/16">
<g:Image resource='{res.xgray}' ui:field="image" />
</div>
...
The Registration-Widget now includes MessageBlock
<g:HTMLPanel styleName="registration" ui:field="panel">
<div class="uniForm maxgrid700">
<h1>
<ui:msg key="registration.headline">Registration</ui:msg>
</h1>
<c:MessageBlock ui:field="messageblock"/>
<div class="ctrlHolder">
<p class="label">
<em></em>
<ui:msg key="registration.name">Name:</ui:msg>
</p>
...
Now, if someone fires a Message
eventbus.fireEvent(new MessageEvent(new MessageImpl(Message.MESSAGETYPE.ERROR, "Server Error Message")));
every Presenter which has "HasMessageBlock" for it's Display can process/display the message:
eventBus.addHandler(MessageEvent.TYPE, new MessageEventHandler() {
#Override
public void execute(final MessageEvent event) {
display.showMessage(event.getMessage());
}
});
I'm stuck -
I need to have a Wicket Panel be able to add a class attribute to the <body> tag of whatever page it's on.
Example usage:
Java:
add(new SpecialSidebarComponent("sidebar"));
Generated HTML:
<body class="sidebar">
...
<div id="sidebar">My Wicket Panel</div>
...
</body>
I cannot add a wicket:id and make the body a Wicket component, because this makes it very difficult to add components to a page in the big page hierarchy I have, and it still also doesn't easily allow for a Panel to modify the body attribute.
I thought BodyTagAttributeModifier may be for this, but apparently it is for something else and cannot get it to function ( Wicket: how to use the BodyTagAttributeModifier class? )
Any helpful ideas?
Update:
In looking at it, it appears the BodyTagAttributeModifier class is only for a Panel's parent tag, not the Page's <body> tag:
Example (Scala syntax):
class Home extends WebPage {
add(new Sidebar("sidebar"))
}
class Sidebar(id: String) extends Panel(id) {
add(new BodyTagAttributeModifier("class", true, new Model("layout-class"), getParent))
}
Template:
<html>
<body>
<div wicket:id="sidebar">Sidebar</div>
</body>
</html>
Rendered:
<html>
<body>
<div class="layout-class">
<h1>Hello World!</h1>
</div>
</body>
</html>
Very confusing name IMHO. Doesn't solve the issue but at least makes more sense.
I personally think the Javascript option is the cleanest for this specific case. However, your comment about add(Component...) being final leads me to believe that you might be interested in the setTransparentResolver(true) method. Here's how it works...
BasePage.html
<body wicket:id="body">
<div wicket:id="panel" />
</body>
BasePage.java
public class BasePage extends Page {
public String bodyClass = "";
public BasePage() {
super();
WebMarkupContainer bodyContainer = new WebMarkupContainer("body");
bodyContainer.setTransparentResolver(true);
bodyContainer.add(new SimpleAttributeModifier("class", new PropertyModel<String>(this, "bodyClass")));
}
}
MyPage.java (extends BasePage)
public class MyPage extends BasePage {
public MyPage() {
super();
add(new SidebarPanel("panel"));
super.bodyClass = "sidebar";
}
}
Even though you are not adding the SidebarPanel directly to the bodyContainer in the BasePage, it will still work out because of setTransparentResolver(true).
For your simple case, go with the Javascript. For the general issue of feeling constrained by subclasses not being able to fit inside containers, be aware of transparent resolving.
If you really can't give the <body> tag a wicket:id (I'll assume you don't have a BasePage that every, or almost every, other page extends in which to abstract this), it'll be not possible to know at page render time (when that <body> tag is rendered) what class to append to it, it will be simply copied as is from your HTML to the output.
You could achieve the same via javascript, however. Make your Panel implement IHeaderContributor and use IHeaderResponse.renderOnDomReadyJavscript().
public abstract class SpecialSidebarComponent(String id) extends Panel
implements IHeaderContributor {
.....
public void renderHead(IHeaderResponse response){
String javascript = "document.body.setAttribute('class', 'sidebar');";
response.renderOnDomReadyJavascript(javascript);
}
....
}
I think you were on the right track with BodyTagAttributeModifier, at least according to JavaDoc. The compilation problems in the linked article stem from the use of a non-existing Constructor...
in SpecialSidebarComponent you should be able to do this:
add(new BodyTagAttributeModifier("class", Model.of("sidebar"), this));
Can't try this right now because I'm not at my development computer...