Struts 2 - Accessing different properties on the ValueStack sharing the same name - struts2

Struts 2 will resolve all property names during view rendering against the top object in the ValueStack first. But how can one access a property with the same name on the object lower on the stack?
Example:
Let's say I have an Action class called MyAction and it has a a logDate property. In the view rendered after this action is invoked, there's this:
<s:iterator value="users" status="itStatus">
<s:property value="logDate"/>
</s:iterator>
Now imagine a User object also has a logDate property. During the iteration, Struts 2 will always push the current user object to the top of the ValueStack effectively resolving all property names against it. But, what if I wanted to access logDate from the action? What's the correct way to do this?

You can use an index to look at a substack. For example:
[0].logDate would start the search at the stop of the stack and find the logDate on the user object. [1].logDate would start the search one level deeper and find the logDate on the Action class. This OGNL page (see the section right above the Accessing static properties header) has some more detail and here is another explanation.

Related

Using navigation rules inside a jsf bean

I've created a bean to search an sql table. This bean produces an arraylist that is displayed in a rich:dateTable. For each row in this table, there is a column that is a link to another page that specifies which record in the table is to be displayed, e.g.:
<h:link id="profile_last_name" value="#{record.string}" outcome="#{search.action()}">
<f:param name="user_id" value="#{record.getInteger('user_id')}"/>
</h:link>
The search bean is passed a navigation outcome, e.g. "staffEditUser" that creates a URL like:
http://localhost:8080/staff/edit/user.xhtml?user_id=98
I'd like to change the search bean so that if there is only one row in the search result, it immediately goes to the edit page. I know how to do the redirect if I knew the destination page name but I don't; all that I know inside the search bean is the navigation outcome. Is there some way to access the navigation rules from inside the bean?
Alternatively, and this seems very kludgy to me, could I simply add parameters to a redirect in the xhtml file that would be processed by the jsf navigation? If so, how?
Thanks very much for any help.
You can redirect the JSF page from within your managed bean method with
FacesContext.getCurrentInstance().getExternalContext().redirect("url");
As I understand you. You should check inside your ManagedBean database read method if the returned results have the size of none and then redirect to the edit page of this record.

Difference in navigation by action="xyz" and action="#{bean.returnXyz}"

How is navigation from a Facelet page
<p:commandLink action="xyz.xhtml">
or a backing bean
<p:commandLink action="#{bean.redirect}">
public class Bean{
public String redirect(){
.....
return "xyz.xhtml";
}
}
different from each other?
How is navigation from a xhtml page or a backing bean different from each other.
There's no difference. The both examples invoke a POST request and instructs JSF to render the view associated with the given outcome. The backing bean method has the only advantage that it allows you to perform some business logic beforehand or even control the outcome value programmatically.
However, if you don't have any business logic at all and solely want to have an idempotent link to another page, then using a command link is actually a bad practice. Using POST for page-to-page navigation is not user nor SEO friendly. The target page is not bookmarkable (the URL remains the one of the page where the POST form was been submitted to) nor searchbot-crawlable (it is using JavaScript to submit a hidden form).
You should instead use a normal link.
<h:link outcome="xyz.xhtml">
This generates a SEO-friendly <a> element with the full URL in its href and ends up in an user-friendly bookmarkable URL.
See also:
When should I use h:outputLink instead of h:commandLink?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Check out the documentation of p:commandLink here, which says the following for action attribute:
A method expression or a string outcome to process when command is
executed.
Now, as action="xyz.xhtml" returns String xyz.xhtml you're redirected accordingly and for action="#{bean.redirect}" which again returns xyz.xhtml you are again redirected according to the returned String.

Why do my viewmodel properties end up null or zero?

I'm working on my first MVC application, still figuring it all out.
I have a viewmodel which, at this point, is identical to my domain object. My controller builds the viewmodel and passes it to a view. The view only displays a some of the properties because I don't want primary and/or foreign keys displayed for the user yet, in the case of a primary key, I need to have the data in order to update / delete the database.
It appears that unless I use a viewmodel property in the view, it is set to default values (0 for numeric value types and null for reference types) when I pass the viewmodel back. Is this correct behavior?
I confirmed the viewmodel passed to the Edit view does contain all the properties (as I would expect).
The question - Once a view is rendered, what happens to the viewmodel? If my viewmodel contains properties that are not used in the view, do their values just disappear? For example, when I click the Edit actionlink to fire the Edit action on the controller, the viewmodel that gets passed to the action does not contain any properties unless they are visible on the screen. Why?
BTW, this is ASP.NET MVC 4 RC.
It appears that unless I use a viewmodel property in the view, it is
set to default values (0 for numeric value types and null for
reference types) when I pass the viewmodel back. Is this correct
behavior?
Yes, when you invoke a controller action you need to pass all the properties that you want to be bound in the request. So for example if you are using a html <form> to call the action you need to use input fields. You could use hidden fields but they must be present, otherwise nothing is sent to the controller action
The question - Once a view is rendered, what happens to the viewmodel?
It falls out of scope and is eligible for garbage collected.
If my viewmodel contains properties that are not used in the view, do their values just disappear?
Absolutely. But even if you use those properties inside the view they disappear. For example if you only display the values inside the view but do not use input fields to send them back to the server when the form is submitted they will be gone as well.
For example, when I click the Edit actionlink to fire the Edit action
on the controller, the viewmodel that gets passed to the action does
not contain any properties unless they are visible on the screen. Why?
Because the view model no longer exists. It's gone and garbage collected. That's how the HTTP protocol works. It's stateless. Nothing is persisted between the requests. You will have to include whatever properties you want to be populated in the request either as POST form values or as query string parameters if you are using action links or whatever.
If the user is not supposed to modify those values inside the view you could then simply pass an id to the controller action which will allow for this controller action to retrieve the model from wherever it is stored (a database or something) using this id.
If your properties are in any helper methods which generates the input HTML element inside a form, It will be available in your HTTPost action method when you submit the form. If you are simply displaying it in a div/span , it is not going to get you the property values. That is how MVC model binding works.
Expect the values in your HttpPOST action if you use these HTML helpers
#Html.TextBoxFor
#Html.DropDownFor
#Html.EditorFor
#Html.HiddenFor
Dont expect the values if you use these
#Html.DisplayFor

struts2: accessing getters of action class in jsp without creating object

I am working on struts2. In my action class I have written some accessors (setter-getter). Now, suppose this action class is returning SUCCESS and in struts.xml I am open a jsp page (say abc.jsp) against the result "SUCCESS". I need the values of all getter methods written in action class without creating object of action class in my jsp (i.e abc.jsp).
If your controller has a getPostalCode property you can do:
<s:textfield name="postalCode"/>
Which will bind the value to the controller field. Outside s: tags you can also use jsp-el; the expression ${postalCode} will do the same. Read this documentation

Passing data from Controller to a User Control View with ASP.NET MVC

I have a View class (OrderView.aspx) which shows the details of an order (Account Name, Order Date) as well as a list of order lines via the Repeater control. Each order line is represented by a User Control View (OrderLineView.ascx) which shows the details of the order line (Item Name, Quantity, Price). I have a model object called Order which I use as the data source for all of this, which I pass as the model object for the view.
Each OrderLineView user control has a Save and a Delete button. I have the Save button posting the contents of a form within the OrderLine control to a Save method on the Controller and then RedirectToAction back to the same Order page (this refreshes the whole page, nothing AJAXy about it). I have the Delete button linking to a method on the Controller that tries to delete, and then RedirectToAction back to the same Order page. If the delete fails, however, I want a little error message to show up next to the delete button when the page renders again(remember, there is a delete button for every order line on the page, so I only want the message next to the one I clicked). My questions:
1 - How do I pass this data from my Controller method to the specific User Control? Should I somehow add it in to the model? Seems like a bad idea (since it really isn't part of the model).
2 - Should I have a OrderLineController for the OrderLine operations as well as a OrderController for Order operations? I just want to know if best practice is to have a separate Controller for every view.
3 - I have seen how some people might call RedirectToAction with an anonymous type value like this:
RedirectToAction("ViewOrder", new { Id = 1234, Message = "blabla"});
but this makes the Message value show up in the URL string. I am OK with that, but would prefer that it doesn't show if possible.
4 - Also, for accessing properties of the Model from within the view, I find myself doing this all of the time:
foo(((someModelType) this.ViewData.Model).SomeProperty);
I don't like this for a number of reasons, one of which is the fact that I don't want my view to be coupled with the type of my model (which is why I am using ViewPage instead of ViewPage). I would much prefer to be able to have a call like this:
foo(ModelEval("SomeProperty"));
Is there such a thing? I have written my own, but would like it if I didn't have to.
1
Check out ModelState.
ViewData.ModelState.AddModelError("something.Name", "Please enter a valid Name");
ModelState is actually a dictionary, so you could identify the errors on a per-control basis. I don't know if this is a best practice, but it would probably work.
Try something along the lines of
ViewData.ModelState.AddModelError("something#3.Name", "Please enter a valid Name");
and in your view, you could put
<%= Html.ValidationMessage(string.format({"something{0}.Name", YourUniqueId))%>
4
You can strongly type your view, so you don't need that cast, but if you're concerned about tightly coupling, this may put you off. But having the strong type there is no more tightly coupled than having a magic string point to that property of the model anyway. The former just gives you type safety and the glory that is intellisense.
Since your OrderLine has a unique ID you can use that to construct a key to be placed in the ModelState errors container.
public ActionResult Delete(int? Id)
{
ModelState.AddModelError("OrderLine" + Id.Value, "Error deleting OrderLine# " + Id.Value);
...
}
and then use the ValidatinoMessage helper. This will check the ModelState to see if an error exists and if it does it will display the message. Otherwise it's blank.
<%= Html.ValidationMessage ("OrderLine" + Id)%>
In the next release of MVC Model will become a top level property so the following
foo(((someModelType) this.ViewData.Model).SomeProperty);
can be written as
foo(Model.SomeProperty);
Model objects should already be typed unless you're using public object as a property?

Resources