Massive EDIT
Let's say I have two differents controllers. One that renders the View and one that renders the <jsp:include> tags.
The ViewController :
#Controller
public class ViewController {
#Resource
private VehicleCatalogAPIService vehicleCatalogAPIService;
#RequestMapping("/en/new/{organizationUnitId}")
public String view(ModelMap modelMap, Locale locale,
#PathVariable Integer organizationUnitId,) {
Vehicles vehicles = vehicleCatalogAPIService.getVehicule(organizationUnitId);
modelMap.put("vehicles", vehicles);
return "/catalog/" + view;
}
}
The IncludeController:
#Controller
public class IncludeController{
#Resource
VehicleCatalogAPIService vehicleCatalogAPIService;
#RequestMapping(value = "/fragment/test", produces = "text/html")
public String test(ModelMap modelMap,
#RequestParam("view") String view,
#RequestParam("test") String test,
#RequestParam("vehicleId") String vehicleId,
Locale locale) {
Vehicle particularVehicle = vehicleCatalogAPIService.get(vehicleId);
modelMap.put("vehicle", vehicle);
return "/catalog/vehicle/fragments/" + view;
}
#RequestMapping(value = "/fragment/test2", produces = "text/html")
public String test(ModelMap modelMap,
#RequestParam("test") String test,
#RequestParam("view") String view,
Locale locale) {
return "/catalog/vehicle/fragments/" + view;
}
}
I hit the page in the browser : http://example.com/en/new
The ViewController is called and returns the the jsp page that has to be rendered, in this case /catalog/listing.jsp. The JSP looks like this :
<jsp:useBean id="vehicles" type="java.util.List<com.sm360.auto.webauto.webapplib.bean.display.VehicleDisplayBean>" scope="request"/>
<h1> LISTING JSP </h1>
<div>
<c:forEach items="${vehicles}" var="vehicle" begin="${k.index}" end="${k.index + k.step-1}">
<div class="c-item-out">
<content:sheet-new-vehicule vehicle="${vehicle}" isCompact="true" hasCompared="true" />
</div>
</c:forEach>
</div>
<jsp:include page="/fragment/test">
<jsp:param name="view" value="view1"/>
<jsp:param name="vehicle1" value="vehicle1"/>
<jsp:param name="test" value="test1"/>
</jsp:include>
That include now calls the IncludeController with 3 parameters : view, vehicleId and test. The proper method is invoked and the correct view is returned (view1).
The view1 contains another include :
<jsp:useBean id="vehicle" type="com.sm360.auto.webauto.webapplib.bean.display.VehicleDisplayBean" scope="request"/>
<h1> view 1 </h1>
<div>
<h2>${vehicle.name}
</div>
<jsp:include page="/fragment/test2">
<jsp:param name="view" value="view2"/>
<jsp:param name="test" value="test2"/>
</jsp:include>
In that second call, the view parameter will be "view2,view1" and the test parameter will be "test2, test1".
I would like that second include to have its own values of the parameters it passes to the controller, not a merge from the other call.
EDIT :
Following this diagram, when a <jsp:include> is met during the rendering of the view, does the process return to the Front Controller and re-Delegate the request to the Controller specified in the include tag with the same request with updated parameters?
Is it possible to have a new set of fresh parameters?
A long shot: could you just remove the view entry from the model before setting the next? I'm having a common Spring controller method in mind, please post your code for clarification.
#RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.remove("view");
model.addAttribute("view", "foobar");
return "helloWorld";
}
Related
I have a wrapper class like so:
#NoArgsConstructor
#Data
public class ListWrapper {
public ListWrapper(List<Object> objects) {
this.objects = objects;
}
private List<Object> objects;
}
I am looking to populate the wrapper with custom beans. Let's call it an ItemBean.
So then I have:
#GetMapping("/rentSetup")
public String setupRent(#RequestParam("companyId") Integer companyId,
Model model) {
List<Object> beans = new ArrayList<>();
ItemBean bean = new Builder()
.someProperty(something)
.build();
beans.add(bean);
ListWrapper wrapper = new ListWrapper(beans);
model.addAttribute("itemBeansWrapper", wrapper);
return "setup";
}
I'd like to have the user edit the property someProperty on in the view. I'm thinking that I would do:
<form th:object="${itemBeansWrapper}"
th:action="#{/setup(companyId=${companyId})}"
th:method="post">
<div th:each="bean, iterStat : ${itemBeansWrapper.objects}">
<input type="number"
th:name="${bean[__${iterStat.index}__].someProperty}">
</div>
<button type="submit"
th:name="action"
th:value="review" value="review"> Review
</button>
</form>
But this results in:
org.springframework.expression.spel.SpelEvaluationException: EL1027E:(pos 4): Indexing into type 'com.ItemBean' is not supported
at org.springframework.expression.spel.ast.Indexer.getValueRef(Indexer.java:176)
What am I doing wrong?
Note that I also have my controller annotated with #SessionAttributes({"companyId", "itemBeansWrapper"}) since I would like to persist the wrapper across pages in the session.
If I leave off the [__${iterStat.index}__], the page compiles fine, but I am thinking that I would need something like that to differentiate the nested beans.
Caught my error. It should be:
<input type="number" th:field="*{objects[__${iterStat.index}__].someProperty}"/>
I am just learning spring MVC.
I have passed a object named emp of class Employee using model.addAttribute("emp",emp); to a jsp page. I have used the same modelAttribute in form attribute of jsp as:
<form:form method="POST" modelAttribute="emp" id="emp" action="${pageContext.request.contextPath}/AcceptIncrementDecrementPayroll">
So the fields with matching are displayed and allowed to update. Suppose Employee has firstName and salary. The salary is displayed in a text box and is editable. So I need the new salary value in the text field along with the other properties like firstName as an object of the employee class.
These are the controllers:
This is the first controller where i am setting the model attribute to Employee object emp.
#Transactional
#RequestMapping(value = "/viewIncDecPay")
public String ViewIncrDecrPayroll(HttpServletRequest req,Model model)
{
List<Employee> empList=this.employeeDaoImpl.getCurrentCTC(staffId);
System.out.println("empList has: "+empList.toString());
List<IncrementDecrementPayroll> empRequestList=this.employeeDaoImpl.getExpectedCTC(staffId);
System.out.println("empRequestList has: "+empRequestList.toString());
int count=0;
for(Employee emp:empList){//empList has only one object as it is fetched based on a criteria
System.out.println(count+"in List");
model.addAttribute("emp", emp);
}
model.addAttribute("incrementDecrement", empRequestList);
return "ViewIncrementDecrementPayroll";
}
This is the jsp page Form declaration
<form:form method="POST" modelAttribute="emp" id="emp" action="${pageContext.request.contextPath}/AcceptIncrementDecrementPayroll">
<form:input path="salary" type="text" class="form-control" name="" id="basicMonthly" value=""/>
</form>
This is the controller function that is being hit by the jsp page
#Transactional
#RequestMapping(value="/AcceptIncrementDecrementPayroll")
public void acceptIncrement(HttpServletRequest req,Model model,#ModelAttribute("Employee")Employee emp){
System.out.println("in accept payroll");
String employeeName=emp.getFirstName();//this gives me null as all the properties are lost
System.out.println("returned after jsp: name is: "+employeeName);
}
Above in #ModelAttribute I have declared again the object and there it looses it properties, but I don't know how to call the same object again. Thanks for any suggestion!
I have some code in JSP as below:
<c:iterate name="list" id="payment" index="idx">
<tr class="gRowEven"
_paid="<c:write name="payment" property="paid"/>">
Now my problem is that I want to call a method in a controller based on the variable _paid. I can do a request.setAttribute("_paid", _paid)
I am assuming it would work. But I am not supposed to do it that way. So I was wondering if there is any other way to do it?
You can pass that value to a hidden input field (on form submit)
<form action='your controller' method='POST'>
...
<input type='hidden' id='newfield' name='newfield' value=''/>
</form>
then you controller can retrieve its value (using request.getParameter('newfield'), or a MVC framework provided method)
Or simply append to the URL if your controller takes GET request
By the way,
request.setAttribute("_paid",_paid);
probably won't work for you. Because this call is only executed when page is loaded, not when you submit the page. Also, when you submit a page, it will have a new fresh request
Edit: (this is what I meant by saying 'pass that value to a hidden input field (on form submit)')
<script type='text/javascript'>
function updateHiddenField() {
var trPaid = document.getElementById('trPaid'); //assume tr field's id is trPaid
//if tr doesn't have an id, you can use other dom selector function to get tr
//element, but adding an id make things easier
var value = trPaid.getAttribute('_paid');
document.getElementById('newfield').value = value;
document.getElementById('form1').submit();
return false;
}
</script>
<form action='your controller' id='form1' method='POST'
onsubmit='javascript:updateHiddenField();'>
...
</form>
Then _paid's value will be passed with request in newfield parameter
And here's how you get the parameter when you are using Spring MVC
#Controller
#RequestMapping("/blah")
public class MyController {
#RequestMapping(value="/morepath" method = RequestMethod.POST)
public ModelAndView test(#RequestParam("newfield") int paid) {
logger.debug("here's the value of paid: " + paid);
}
...
I have a strongly typed view inheriting from a POCO class. I want to initialize the property of a model with a Querystring value at the time when view loads.
On the View Load I am using ViewData to the save the code :
public ActionResult Data() {
ViewData["QueryStringValue"] = this.Request.QueryString["Param1"]
return View();
}
In the HTML markup, I am using this code to initialize the model property in a hidden variable
<%:Html.HiddenFor(m=>m.Param,
Convert.ToInt32(Html.Encode(ViewData["QueryStringValue"]))) %>
m.param is a byte type.
URL of the request is somewhat like this : http://TestApp/Data/AddData?Param1=One
On View Save event, I am using model binding but issue is that I don't get to see the value of param initialized in the controller. It is always NULL.
My Save Event maps to a controller :
[HttpPost]
public ActionResult SaveData(MyData d)
{
string paramValue = d.Param; //this always returns null
BO.Save(d);
}
I inspected the HTML source and saw that the value of the hidden field itself is blank. Not sure why this is happening since the below code works and shows the param value in a heading element
<h2> <%=Html.Encode(ViewData["QueryStringValue"]) %> </h2>
I have no idea where I am going wrong on this.
I think, Instead of Passing the Querystring value in ViewData, You should set it as the Property value of your ViewModel/ Model and pass that to your View.
public ActionResult Data()
{
YourViewModel objVm=new YourViewModel();
objVm.Param=Request.QueryString["Param1"];
return View(objVm);
}
Now in your Strongly typed View, use it like this
#model YourViewModel
#using(Html.BeginForm())
{
#html.HiddenFor(#m=>m.Param);
<input type="submit" value="Save" />
}
Now Param value will be available in yout HttpPost action method
[HttpPost]
public ActionResult Data(YourViewModel objVm)
{
string param=objVm.Param;
//Do whatever you want with param
}
Just made this work, Issue is with this line:
<%:Html.HiddenFor(m=>m.Param,
Convert.ToInt32(Html.Encode(ViewData["QueryStringValue"]))) %>. I stated in the question that m.Param is of type byte. I figured out that issue was with casting.
I tried this code and it worked
<%:Html.HiddenFor(m => m.Param, (byte)Convert.ToInt16(this.Request.QueryString["Param1"].ToString()))%>
I have the following problem:
I have a form in site/banen (currently local running webserver) which is using a SQL database. The link is made using ADO.net and is instantiated in the controller in the following way:
DBModelEntities _entities;
_entities = new DBModelEntities(); // this part is in the constructor of the controller.
Next, I use this database to fill a Html.DropDownList() in my view. This is done in two steps. At the controller side we have in the constructor:
ViewData["EducationLevels"] = this.GetAllEducationLevels();
and a helper method:
public SelectList GetAllEducationLevels()
{
List<EducationLevels> lstEducationLevels = _entities.EducationLevels.ToList();
SelectList slist = new SelectList(lstEducationLevels, "ID", "Name");
return slist;
}
In the view I have the following:
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<!-- various textfields here -->
<p>
<label for="EducationLevels">EducationLevels:</label>
<!-- <%= Html.DropDownList("EducationLevels", ViewData["EducationLevels"] as SelectList)%> -->
<%= Html.DropDownList("EducationLevels", "..select option..")%>
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
Now, the form is rendered correctly when I browse to the create page. I can select etc. But when selected I have to use that value to save in my new model to upload to the database. This is where it goes wrong. I have the following code to do this in my controller:
//
// POST: /Banen/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection form)
{
// set rest of information which has to be set automatically
var vacatureToAdd = new Vacatures();
//vacatureToAdd.EducationLevels = form["EducationLevels"];
// Deserialize (Include white list!)
TryUpdateModel(vacatureToAdd);
// Validate
if (String.IsNullOrEmpty(vacatureToAdd.Title))
ModelState.AddModelError("Title", "Title is required!");
if (String.IsNullOrEmpty(vacatureToAdd.Content))
ModelState.AddModelError("Content", "Content is required!");
// Update the variables not set in the form
vacatureToAdd.CreatedAt = DateTime.Now; // Just created.
vacatureToAdd.UpdatedAt = DateTime.Now; // Just created, so also modified now.
vacatureToAdd.ViewCount = 0; // We have just created it, so no views
vacatureToAdd.ID = GetGuid(); // Generate uniqueidentifier
try
{
// TODO: Add insert logic here
_entities.AddToVacatures(vacatureToAdd);
_entities.SaveChanges();
// Return to listing page if succesful
return RedirectToAction("Index");
}
catch (Exception e)
{
return View();
}
}
#endregion
It gives the error:
alt text http://www.bastijn.nl/zooi/error_dropdown.png
I have found various topics on this but all say you can retrieve by just using:
vacatureToAdd.EducationLevels = form["EducationLevels"];
Though this returns a string for me. Since I'm new to ASP.net I think I am forgetting to tell to select the object to return and not a string. Maybe this is the selectedValue in the part where I make my SelectList but I can't figure out how to set this correctly. Of course I can also be complete on a sidetrack.
Sidenote: currently I'm thinking about having a seperate model like here.
Any help is appreciated.
You can't return an object from usual <SELECT> tag wich is rendered by Html.DropDownList() method, but only string variable could be returned. In your case ID of EducationLevels object will be send to the server. You should define and use one more custom helper method to reconstruct this object by ID.