Extract part of Wicket form in a reusable panel - wicket

1 year ago, i ported an existing application from older wicket to version 8, without too much thinking how it works.
Now, i want to understand a bit better to simplify the code i found...
For this, in a big form page, i have code like the sample below.
The "situationdiv?"'s have the same structure, i want to make it a reusable panel.
I wanted to pass the model "CLBX.?" to the panel constructor, but i can't find the good way to do it.
Is there another better solution ?
Please help me find how to do this...
<form wicket:id="form">
<input name="check1" id="check1" type="checkbox" wicket:id="IGEN1ST"
value="1" oninput="visibiliteTxtArea('1')"/>
<div id="body1div"><textarea id="body1" wicket:id="T01K1ST01" name="body1"
maxlength="1000" control_length="1"
style="display: none" rows="10"></textarea></div>
....
<div id="situationdiv1">
<h2><wicket:message key="F8.Mot2">Durée de la situation</wicket:message></h2>
<wicket:message key="F8.Per">Période du</wicket:message>
<input type="text" class="text date" name="startDate0" id="DPERBEG0"
wicket:id="CLBX.0.DPERBEG" value=""/>
<wicket:message key="F8.Tot2">au</wicket:message>
<input type="text" class="text date" name="endDate0"
wicket:id="CLBX.0.DPEREND" id="DPEREND0"
value=""/>
......
</div>
<div id="situationdiv2">
<h2><wicket:message key="F8.Mot2">Durée de la situation</wicket:message></h2>
<wicket:message key="F8.Per">Période du</wicket:message>
<input type="text" class="text date" name="startDate1" id="DPERBEG1"
wicket:id="CLBX.1.DPERBEG" value=""/>
<wicket:message key="F8.Tot2">au</wicket:message>
<input type="text" class="text date" name="endDate1"
wicket:id="CLBX.1.DPEREND" id="DPEREND1"
value=""/>
......
</div>
....
</form>
public class MyWebPage extends WebPage {
//Data is filled/organized from DB.
//Structure: Map<String, Object>
//mostly <String, String> or <String, Integer>
//sometimes anything else like <"CLBX", ArrayList<Map<String, Object)>> (for situations)
// and in these, only <String, String> or <String, Integer>
public MyWebPage(Map<String, Object> data) {
this.init(data, readonly);
}
private void init(Map<String, Object> data, boolean readonly) {
Form<String> form = new Form<String>("form") {
#Override
protected void onSubmit() {
super.onSubmit();
log.debug("form submit");
}
}
add(form);
form.setDefaultModel(new CompoundPropertyModel(data));
}
}

You could use FormComponentPanel to reuse the common form components.
FormComponentPanel is a FormComponent that could have its own markup, like a Panel. As such, it could have FormComponent children, like TextField, DropdownChoice, etc.

Related

Redirect to page a certain amount of times - Spring Boot

I am trying to make a Quiz Creation application.
In the beginning, I ask the user to enter the quiz title, description, and the number of questions included in the quiz.
Based on the number of questions I want to redirect the user to the 'question and answers' page. I thought of adding another variable named 'count' which would keep the number of times the page is accessed so I can show the next or submit button.
I am not sure how to calculate the number of times the page is redirected and how to redirect the code to a certain page based on the number of questions.
This is the saveQuiz method in the QuizController class:
#PostMapping("/saveQuiz/{cid}")
public String saveQuiz(#PathVariable("cid") Long cid, #Valid #ModelAttribute Quiz quiz,
Model model, #RequestParam("questionNumber") int noOfQuestions) throws ParseException {
Chapter chapter = chapterService.findChapterById(cid);
quiz.setQuizName(quiz.getQuizName());
quiz.setGuidelines(quiz.getGuidelines());
quiz.setChapter(chapter);
quizService.saveQuiz(quiz);
model.addAttribute("quiz", quiz);
model.addAttribute("noOfQuestions", noOfQuestions);
return "redirect:/add_quiz_questions/"+quiz.getId();
}
Then in my QuestionController class I have the below methods
#Controller
public class QuestionController {
#Autowired
QuizService quizService;
#Autowired
QuestionService questionService;
#Autowired
AnswerService answerService;
private static int count = 0;
#GetMapping("/add_quiz_questions/{qid}")
public String addQuestions(#PathVariable("qid") Long qid, Model model) {
count++;
Quiz quiz = quizService.findQuizById(qid);
model.addAttribute("quiz", quiz);
model.addAttribute("count", count);
return "add_quiz_questions";
}
#PostMapping("/saveQuizQuestion/{qid}")
public String saveQuestions(#PathVariable("qid") Long qid, #Valid #ModelAttribute QuizForm quizForm,
Model model, #RequestParam("noOfQuestions") int noOfQuestions) throws ParseException {
Quiz quiz = quizService.findQuizById(qid);
Question question = new Question();
question.setQuestion(quizForm.getQuestion());
//Add answers
Set<Answer> answers = new HashSet<>();
Answer a = new Answer();
a.setAnswer(quizForm.getOption1());
a.setCorrect(1);
answers.add(a);
a.setAnswer(quizForm.getOption2());
a.setCorrect(0);
answers.add(a);
a.setAnswer(quizForm.getOption3());
a.setCorrect(0);
answers.add(a);
answerService.saveAnswers(answers);
question.setAnswers(answers);
questionService.saveQuestion(question);
Chapter chapter = quiz.getChapter();
Course course = chapter.getCourse();
Set<File> files = chapter.getFiles();
int nrFiles = files.size();
model.addAttribute("chapter", chapter);
model.addAttribute("course", course);
model.addAttribute("files", files);
model.addAttribute("numberOfFiles", nrFiles);
model.addAttribute("quiz", quiz);
if(count == noOfQuestions) //check if the page has been redirected as many times as there were questions then redirect to chapter page
return "redirect:/chapter_details/"+chapter.getId();
else
return "redirect:/add_quiz_questions/"+quiz.getId();
}
}
This is the Thymeleaf page:
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<div class="card">
<h5 class="card-header info-color white-text text-center py-4">
<strong>Quiz questions</strong>
</h5>
<div class="card-body px-lg-5">
<!-- Form -->
<form class="text-center" style="color: #757575;" th:action="#{/saveQuizQuestion/{qid}(qid=${quiz.id})}" method="post" th:object="${quizForm}">
<p>Create your quiz</p>
<!-- Question -->
<div class="md-form mt-3">
<input type="text" id="question" class="form-control" name="question">
<label for="question">Question</label>
</div>
<!-- Right answer -->
<div class="md-form">
<input type="text" id="ans1" class="form-control" name="option1">
<label for="ans1">Answer 1</label>
</div>
<!-- Answer 2 -->
<div class="md-form">
<input type="text" id="ans2" class="form-control" name="option2">
<label for="ans2">Answer 2</label>
</div>
<!-- Answer 3 -->
<div class="md-form">
<input type="text" id="ans3" class="form-control" name="option3">
<label for="ans3">Answer 3</label>
</div>
<input type="hidden" th:value="${count}" name="count"/>
<input type="hidden" th:value="${noOfQuestions}" name="noOfQuestions"/>
<button th:if="${noOfQuestions < count}" class="btn btn-outline-info btn-rounded btn-block z-depth-0 my-4 waves-effect" type="submit">Next</button>
<button th:if="${noOfQuestions == count}" class="btn btn-outline-info btn-rounded btn-block z-depth-0 my-4 waves-effect" type="submit">Submit</button>
</form>
<!-- Form -->
</div>
</div>
</html>
I believe the way that I am using the count variable is wrong but it's there just to give an idea. If anyone could help me clarify the question that I have, I'd be grateful.
Thank you in advance.
you can make a count variable in session with #SessionAttribute annotation.
and whenever they submit you will again set count variable to default value.

One servlet One JSP 2 forms [duplicate]

This question already has answers here:
How to transfer data from JSP to servlet when submitting HTML form
(4 answers)
Closed 4 years ago.
One JSP, which contains two forms
<div class="modal" id="modalDialog">
<input method="post" action="newsPage">
<input type="hidden" name="modalForm" value="modalFormPush"/>
<input type= "text" name="title">
<textarea cols="45" maxlength="100" onkeyup="countf()" id="text" name="content"></textarea>
<input type="submit" value="Save" name="modalForm">
</form>
</div>
<div class="modal" id="newsModalDialog">
<form method="post" action="newsPage">
<input type="hidden" name="modalForm" value="modalFormNews"/>
<input type= "text" name="title">
<textarea cols="45" maxlength="100" onkeyup="countf2()" id="news_text" name="content"></textarea>
<input type="submit" value="Save" name="modalForm">
</form>
The goal is to send data from this forms to one servlet, which inserts its to database.
From one form data values must be inserted to one table-database, from second form - to second table-database, accordingly.
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
String modalForm = request.getParameter("modalForm");
if ("modalFormPush".equals(modalForm)) {
Pushdata pushdata = new Pushdata();
pushdata.setTitle(request.getParameter("title"));
pushdata.setContent(request.getParameter("content"));
pushModifier.savePushdata(pushdata);
}
else
if ("modalFormNews".equals(modalForm)) {
Newsdata newsdata = new Newsdata();
newsdata.setTitle_news(request.getParameter("title_news"));
newsdata.setContent_news(request.getParameter("content_news"));
newsModifier.saveNewsdata(newsdata);
}
}
But when I try to send data from one of this forms (for example "newsModalDialog"), joint table is created. This table contains fields from two tables. And this new table is empty.
Thus, values are not inserted to database, through servlet.
Thanks in advance!
I have found a mistake.
Not
<input method="post" action="newsPage">
But
<form method="post" action="newsPage">

How to pass data from a form in a view to another controller with C# MVC?

If I have a form that needs to use a textbox input like as below:
#{
if(IsPost){
username = Request.Form["username"]
}
}
<form action="Home/Index" method="post">
<input type="text" name="username" />
<input type="submit" value="submit" />
</form>
The controller is something like below,
public class HomeController : Controller
{
public ActionResult Index (string username) {
if (string username != string.Empty)
{
Console.WriteLine("Your username is " + username);
}
return View();
}
}
Seems like the data is not being passed from the post method. When I hit submit the URL that it requests is Home/Home/Index, which is not were the controller(HomeController) action is located, it should be Home/Index, and use the HomeController right?
What if I need to pass this data to a different controller that has an Index for the action, like UserController?
In this instance, you're missing a slash!
<form action="/Home/Index" method="post">
<input type="text" name="username" />
<input type="submit" value="submit" />
</form>
But when using asp.net mvc, you should use Url.Content with the home directory character to ensure that if your site is deployed in a sub-directory of the site, the correct root will be found. So use:
<form action="#Url.Content("~/Home/Index")" method="post">
<input type="text" name="username" />
<input type="submit" value="submit" />
</form>

gwtp Accessing uibinder input, div, span using DOM

I wanted to access the elements in uibinders using DOM or document interface in presenters, is it possible.
wanted to get the element and attach handler to it.
I have input, select, div, span element in uibinders. Is it possible to achieve.
I tried to get using DOM and Document it returns null.
<g:HTMLPanel styleName="{style.content1}" ui:field="containerPanel1">
<div class="{style.rightAlign}" id="container">
<g:FormPanel styleName="{style.formLayout}" ui:field="formPanel1">
<g:HTMLPanel width="100%" height="100%">
<div id="inner" class="{style.horiCon}">
<div class="{style.label}">
<ui:msg key="name" description="Name of the user">Name</ui:msg>
</div>
<input type="text" id="firstName" name="name"
placeholder="FirstName" class="{style.textboxFirstName}" />
<input type="text" id="lastName" placeholder="LastName"
name="name" class="{style.textboxLastName}" />
<span id="nameError" class="{style.errorMsgHide}">Error</span>
</div>
</g:HTMLPanel>
</g:FormPanel>
</div>
</g:HTMLPanel>
Presenter
#Override
protected void onBind() {
super.onBind();
Window.alert("" + DOM.getElementById("firstName"));
// returns null;
}
#Override
protected void onReveal() {
super.onReveal();
Window.alert("" + DOM.getElementById("firstName"));
// returns <input class="GG1RCY0BHB" id="firstName" name="name" placeholder="FirstName" type="text">
}
Onbind() returns null and onreveal() returns
after that when I do
TextBox.wrap(DOM.getElementById("firstName"));
I am getting
java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:136)
at com.google.gwt.user.client.ui.TextBox.wrap(TextBox.java:69)
What is the issue? Can I use Rootpanel in presenter to get the reference?
Please help me.
Thanks In Advance,
Jose.
To access DOM elements the elements need to get attached to the DOM first, otherwise it will return null. You can use the DOM.getElementByID("id") in overridden onLoad() method in your ui-binder java class .
#Override
void onLoad()
{
DOM.getElementByID("id");
}
You Mentioned the input, select, div, span element in uibinders. Why not use a ui:field and access the field directly to add handlers etc? Just a thought.
select is GWT ListBox there is FlowPanel is a div likewise.

HTML required readonly input in form

I'm making a form. And on one input tag is an OnClick event handler, which is opening a popup, where you can choose some stuff, and then it autofills the input tag.
That input tag is also readonly, so only right data will be entered.
This is the code of the input tag:
<input type="text" name="formAfterRederict" id="formAfterRederict" size="50" required readonly="readonly" OnClick="choose_le_page();" />
But the required attribute isn't working in Chrome. But the field is required.
Does anybody know how I can make it work?
I had same requirement as yours and I figured out an easy way to do this.
If you want a "readonly" field to be "required" also (which is not supported by basic HTML), and you feel too lazy to add custom validation, then just make the field read only using jQuery this way:
IMPROVED
form the suggestions in comments
<input type="text" class="readonly" autocomplete="off" required />
<script>
$(".readonly").on('keydown paste focus mousedown', function(e){
if(e.keyCode != 9) // ignore tab
e.preventDefault();
});
</script>
Credits: #Ed Bayiates, #Anton Shchyrov, #appel, #Edhrendal, #Peter Lenjo
ORIGINAL
<input type="text" class="readonly" required />
<script>
$(".readonly").keydown(function(e){
e.preventDefault();
});
</script>
readonly fields cannot have the required attribute, as it's generally assumed that they will already hold some value.
Remove readonly and use function
<input type="text" name="name" id="id" required onkeypress="return false;" />
It works as you want.
Required and readonly don't work together.
But readonly can be replaced with following construction:
<input type="text"
onkeydown="return false;"
style="caret-color: transparent !important;"
required>
1) onkeydown will stop manipulation with data
2) style="caret-color: transparent !important;" will hide cursor.
3) you can add style="pointer-events: none;" if you don't have any events on your input, but it was not my case, because I used a Month Picker. My Month picker is showing a dialog on click.
This is by design. According to the official HTML5 standard drafts, "if the readonly attribute is specified on an input element, the element is barred from constraint validation." (E.g. its values won't be checked.)
Yes, there is a workaround for this issue. I found it from https://codepen.io/fxm90/pen/zGogwV site.
Solution is as follows.
HTML File
<form>
<input type="text" value="" required data-readonly />
<input type="submit" value="Submit" />
</form>
CSS File
input[data-readonly] {
pointer-events: none;
}
If anyone wants to do it only from html, This works for me.
<input type="text" onkeydown="event.preventDefault()" required />
I think this should help.
<form onSubmit="return checkIfInputHasVal()">
<input type="text" name="formAfterRederict" id="formAfterRederict" size="50" required readonly="readonly" OnClick="choose_le_page();" />
</form>
<script>
function checkIfInputHasVal(){
if($("#formAfterRederict").val==""){
alert("formAfterRederict should have a value");
return false;
}
}
</script>
You can do this for your template:
<input required onfocus="unselect($event)" class="disabled">
And this for your js:
unselect(event){
event.preventDefault();
event.currentTarget.blur();
}
For a user the input will be disabled and required at the same time, providing you have a css-class for disabled input.
Based on answer #KanakSinghal but without blocked all keys and with blocked cut event
$('.readonly').keydown(function(e) {
if (e.keyCode === 8 || e.keyCode === 46) // Backspace & del
e.preventDefault();
}).on('keypress paste cut', function(e) {
e.preventDefault();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="readonly" value="test" />
P.S. Somebody knows as cut event translate to copy event?
Required and readonly don't work together.
Although you can make two inputs like this:
<input id="One" readonly />
<input id="Two" required style="display: none" /> //invisible
And change the value Two to the value that´s inside the input One.
I have the same problem, and finally I use this solution (with jQuery):
form.find(':input[required][readonly]').filter(function(){ return this.value === '';})
In addition to the form.checkValidity(), I test the length of the above search somehow this way:
let fcnt = $(form)
.find(':input[required][readonly]')
.filter(function() { return this.value === '';})
.length;
if (form.checkValidity() && !fcnt) {
form.submit();
}
function validateForm() {
var x = document.forms["myForm"]["test2"].value;
if (x == "") {
alert("Name missing!!");
return false;
}
}
<form class="form-horizontal" onsubmit="return validateForm()" name="myForm" action="" method="POST">
<input type="text" name="test1">
<input type="text" disabled name="test2">
<button type="submit">Submit</button>
</form>