<html:select> with Yes/No options inside <logic:iterate> passing null to form in struts - struts

adminpage.jsp
I am iterating the users list from map and showing it in UI. Trying to send Yes/No values selected by user for agRestricted and processing it in the approve action.
<logic:iterate name="usersDetails" id="user" indexId="index">
<td><bean:write name="user" property="agName" /></td>
<td>
<html:select property="agRestricted" name="user">
<html:option value="Yes">Yes </html:option>
<html:option value="No">No</html:option>
</html:select>
</td>
<td>
<html:button property="Approve" value="" title="Approve" onclick="adminApprove()"></html:button>
</td>
</logic:iterate>
ApproveAction.java
In the approve action I am trying to read agRestricted value sent in form on submission. but Iam getting null here. Am I doing anything wrong.
public ActionForward approve(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
RegistrationForm registrationForm = (RegistrationForm) form;
if (loggingService.isInfoEnabled()) {
loggingService.logInfo(this, "is AG Restricted", agRestricted);
} // if{}//printing null
}
RegistrationForm.java
POJO Class for setting the form variables.
public class RegistrationForm extends org.apache.struts.action.ActionForm {
private String agRestricted;
private String agName;
public String getAgRestricted() {
return agRestricted;
}
public void setAgRestricted(String agRestricted) {
if (loggingService.isInfoEnabled()) {
loggingService.logInfo(this, "is AG Restricted", agRestricted);
} // if{}//printing null
this.agRestricted = agRestricted;
}
public String getAgName() {
return agName;
}
public void setAName(String agName) {
this.agName = agName;
}
}
adminpage.js
function adminApprove() {
var newUrl2 = './adminpage.do';
document.forms[0].action = newUrl2;
document.forms[0].submit();
}
struts-config.xml
<action input="/adminApprove" name="RegistrationForm"
path="/adminpage" scope="request"
type="com.cts.assetserv.core.web.action.ApproveAction" parameter="method">
<forward name="Success" path="/adminpage.do" />
<forward name="Error" path="/adminpage.do" />
</action>

Related

ui:repeat: Regardless of validation error inner component keeps in state "valid"

I would like to mark a single component within ui:repeat as not valid. My attempt:
Bean:
#Named
#RequestScoped
public class TestBean {
private List<String> strLst;
#PostConstruct
public void init() {
strLst = Arrays.asList("a", "b", "c");
}
public String send() {
return null;
}
public List<String> getStrLst() {
return strLst;
}
}
Validator:
#FacesValidator(value = "TestValidator", managed = true)
public class TestValidator implements Validator<String> {
#Override
public void validate(FacesContext arg0, UIComponent comp, String foo) throws ValidatorException {
throw new ValidatorException(new FacesMessage("Error"));
}
}
Facelet:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
</h:head>
<h:body>
<h:form>
<h:messages />
<!-- After validation error component keeps in state 'valid' - wrong! -->
<ui:repeat var="str" value="#{testBean.strLst}">
<h:inputText value="#{str}" validator="TestValidator"
styleClass="#{component.valid ? 'foo' : 'error'}" />
</ui:repeat>
<!-- After validation error the component switches in state 'not valid' - correct! -->
<h:dataTable var="str" value="#{testBean.strLst}">
<h:column>
<h:inputText value="#{str}" validator="TestValidator"
styleClass="#{component.valid ? 'foo' : 'error'}" />
</h:column>
</h:dataTable>
<h:commandButton action="#{testBean.send}" value="Send" />
</h:form>
</h:body>
</html>
My problem: The component in ui:repeat keeps in state valid, so the styleClass error is not set. With h:dataTable no such problems. But I need a horizontal list, so h:dataTable is not an option here.
Also not working with Omnifaces 1.14.1 as described in https://stackoverflow.com/a/9195360/802058:
<ui:repeat var="str" value="#{testBean.strLst}">
<h:inputText value="#{str}" styleClass="#{component.valid ? 'foo' : 'error'}">
<o:validator validatorId="TestValidator" />
</h:inputText>
</ui:repeat>
Is this a bug or a feature?
Mojarra 2.3.9.SP01

Fire event when the textbox changes in Blazor

I'm using EditForm and InputText to achieve data binding and forms validation. (Using <input #bind="SomeProperty" /> doesn't seem to fire component validation.)
I want to attach an event handler that gets fired whenever the value of the textbox changes:
<InputText #bind-Value="#model.ZipCode" #onkeypress="#model.InvokeThisMethod)"></InputText>
This sort of works, but when I'm in the event handler it's apparently firing before ZipCode has updated. The goal here is to do a thing when the zip code reaches 5 characters, not when the text input loses focus. I've also tried just forcing the change event to fire oninput but that just creates an error on the console about ChangedEventArgs to string not working.
How can I fire an event after the input field has updated the data binding?
After trying everything under the sun to get the grid to reload via the search string after inserting a new record, and failing, I found that I can just reload the grid by setting the search string to empty and displaying all the results (simply having a value in the search box prevents the grid from refreshing after an insert - there is no solution I could get to work for this), but at least it shows the record as being inserted. While this isn't the answer I was looking for, it will suffice for now.
Here's the index.razor page (final):
#page "/"
#inject IConfiguration config
#inject DialogService dialog
#inject NotificationService notification
<PageTitle>Memo Master</PageTitle>
<RadzenButton Click="() => GetMemos()" Text="Get Memos" ButtonStyle="ButtonStyle.Primary" ButtonType="ButtonType.Submit" />
<RadzenTextBox #ref="searchBox" Name="SearchPhrase" #bind-Value="#SearchString" MaxLength="400" #oninput="#(args => SearchString = args.Value?.ToString())" #onkeydown="#Enter" />
<RadzenButton Click="() => OpenMemo(0)" Text="New Memo" Icon="add_circle_outline" ButtonStyle="ButtonStyle.Secondary" />
<br />
<br />
#if (FoundMemos != null && !busy)
{
<RadzenDataGrid #ref=this.grid Data="#FoundMemos" TItem="MemoSearch" AllowFiltering="true" AllowSorting="true" AllowColumnResize="true" AllowPaging="true" PageSize=20
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" SelectionMode="DataGridSelectionMode.Single" #bind-Value="#SelectedMemos" RowClick="#OnRowClicked">
<Columns>
<RadzenDataGridColumn TItem="MemoSearch" Title="Index" Width="70px" Filterable="false" TextAlign="TextAlign.Left">
<Template Context="m">
<RadzenText TextStyle="TextStyle.Caption">#m.Idx.ToString()</RadzenText>
</Template>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="MemoSearch" Property="Title" Title="Title">
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="MemoSearch" Title="Modified" Width="140px" TextAlign="TextAlign.Right">
<Template Context="m">
<RadzenText TextStyle="TextStyle.Caption">#m.ModifiedOn.ToString("MM/dd/yyyy hh:mm tt")</RadzenText>
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
}
else
{
<DisplaySpinner />
}
<br />
<br />
<RadzenButton Click="Reset" Text="Reset" ButtonStyle="ButtonStyle.Secondary" />
#code {
[Parameter]
public string? SearchString { get; set; }
List<MemoSearch> FoundMemos = new();
private string DBConnStr { get; set; } = "";
public DB dB = new();
IList<MemoSearch>? SelectedMemos;
RadzenTextBox? searchBox;
private bool busy;
private RadzenDataGrid<MemoSearch>? grid; //reference to grid, so forced reloading can happen - though it doesn't actually work
async Task OpenMemo(int Idx)
{
string DialogTitle = (Idx == 0) ? "Create New Memo" : $"Edit Memo {Idx.xToStr()}";
object? RefreshResults = await dialog.OpenAsync<MemoDetails>(DialogTitle, new Dictionary<string, object>() { { "Idx", Idx } });
RefreshResults = (RefreshResults == null) ? false : RefreshResults;
if (RefreshResults.xToBoo())
{
if (Idx == 0) SearchString = ""; //force setting to empty reloads grid but only w/o search entry
await GetMemos();
}
await ReturnFocus();
}
protected override async Task OnInitializedAsync()
{
dB.DBConnStr = await Task<string>.Run(()=> config.GetConnectionString("DBConnStr"));
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender) await ReturnFocus(); //NOTE: this is for Radzen "elements"
}
public async Task GetMemos()
{
busy = true;
FoundMemos = await dB.MemoSearchByPageFilterSortAsync(SearchString, PageSize: 9999);
busy = false;
}
public async Task Reset()
{
FoundMemos = new();
SearchString = "";
await ReturnFocus();
}
public async void Enter(KeyboardEventArgs e)
{
if (e.Code == "Enter" || e.Code == "NumpadEnter" || e.Key == "Enter")
{
await GetMemos();
StateHasChanged(); //need to call this here after keypress, lest you get a continual spinner
}
}
async Task OnRowClicked(Radzen.DataGridRowMouseEventArgs<MemoSearch> args)
{
if (args != null)
{
await OpenMemo(args.Data.Idx);
}
}
async Task ReturnFocus()
{
if (searchBox != null) await searchBox.Element.FocusAsync();
}
}
and the MemoDetails.razor page:
#inject IConfiguration config
#inject DialogService dialog
#inject NotificationService notification
#if (memo != null)
{
<RadzenTemplateForm TItem="Memo" Data=#memo Submit=#OnSubmit>
<p>
<RadzenLabel Component="Title" Text="Title" />
<RadzenTextBox id="MemoTitle" Name="Title" #bind-Value=#memo.Title MaxLength="400" />
<RadzenRequiredValidator Component="Title" Text="Title is required!" />
</p>
<p>
<RadzenLabel Component="Body" Text="Memo" />
<RadzenTextArea id="MemoBody" Name="Body" #bind-Value=#memo.Body Rows="18" />
</p>
<p>
<RadzenLabel Component="Keywords" Text="Key Words" />
<RadzenTextBox id="MemoKeywords" Name="Keywords" #bind-Value=#memo.Keywords MaxLength="400" />
</p>
<RadzenButton ButtonType="ButtonType.Submit" ButtonStyle="ButtonStyle.Success" Icon="save" Text="Save" BusyText="Saving ..." IsBusy=#busy />
#if (Idx > 0)
{
<RadzenButton ButtonType="ButtonType.Button" ButtonStyle="ButtonStyle.Danger" Icon="delete" Text="Delete" Click="#((args) => DeleteMemo(memo.Idx))" #onclick:stopPropagation="true"></RadzenButton>
}
<RadzenButton Text="Close" Click="() => dialog.Close(false)" ButtonStyle="ButtonStyle.Light" />
</RadzenTemplateForm>
}
#code {
[Parameter]
public int Idx { get; set; } = 0;
public DB dB = new();
Memo? memo;
bool busy;
protected override async void OnInitialized()
{
dB.DBConnStr = config.GetConnectionString("DBConnStr");
memo = (Idx == 0) ? new Memo() : await GetMemoByIdx(Idx);
await InvokeAsync(() => StateHasChanged()).ConfigureAwait(false); //IMPORTANT!!
}
public async Task<Memo> GetMemoByIdx(int Idx) => await dB.MemoSelectByIdxAsync(Idx);
async Task OnSubmit(Memo memo)
{
int Result;
bool RefreshResults = false;
if (memo.ModifiedOn == DateTime.MinValue) memo.ModifiedOn = DateTime.Now;
string NotificationDetailMessage = memo.Idx == 0 ? "New Memo has been created." : $"Memo {memo.Idx} has been saved.";
busy = true;
Result = await dB.MemoUpsertAsync(memo);
if (Result < -1)
{
notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Saving", Detail = "An error saving this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
}
else
{
notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Save Success", Detail = NotificationDetailMessage, Duration = 2000 });
RefreshResults = true;
}
busy = false;
dialog.Close(RefreshResults);
}
async Task DeleteMemo(int Idx)
{
int Result;
bool RefreshResults = false;
var confirmResult = await dialog.Confirm("Are you sure?", "Confirm Memo Deletion");
if (confirmResult.HasValue && confirmResult.Value)
{
busy = true;
Result = await dB.MemoDeleteByIdxAsync(Idx);
if (Result < -1)
{
notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Error, Summary = "Error Deleting", Detail = "An error deleting this record has occured!\n" + dB.LastErrorMsg, Duration = 4000 });
}
else
{
notification.Notify(new NotificationMessage { Severity = NotificationSeverity.Success, Summary = "Deletion Success", Detail = $"Memo {Idx} has been deleted.", Duration = 2000 });
RefreshResults = true;
}
}
busy = false;
dialog.Close(RefreshResults);
}
}
Good enough, for now, but still baffled as to what Radzen is doing behind the scenes.
<InputText class="form-control" Value="#model.ZipCode" ValueExpression="#( ()=> model.ZipCode )" ValueChanged="#( (string s) => model.InvokeThisMethod(s) )"></InputText>
I didn't find this in the Microsoft documentation. I found it on the Telerik site for their Blazor controls (which apparently works for the non Telerik controls).
Dealing with form fields in Blazor really sucks right now.
<input #bind="model.Property" />
or
<InputText #bind-Value="model.Property" />
and then the ValueExpression attributes shown above. The intellisense in .razor files for VS2019 is poorly implemented. This sucks.

Wicket dynamicly add data from database to page

I'm trying to add some data into page from database, after applying "filter"
After submit form, candidate list is update and I want to push this changes into page.
How can I do this in wicket ?
.java file
public class SearchCandidate extends WebPage {
private SearchCandidateModel searchCandidateModel = new SearchCandidateModel();
private List<CandidateEntity> candidate = new ArrayList();
public SearchCandidate(PageParameters p) {
super(p);
final TextField<String> firstName = new TextField<>("first_name", new PropertyModel<String>(searchCandidateModel, "firstName")); //Filter
final DataView dataView = new DataView("simple", new ListDataProvider(candidate)) {
public void populateItem(final Item item) {
final CandidateEntity user = (CandidateEntity) item.getModelObject();
item.add(new Label("firstName", user.getFirstName()));
}
};
Form<?> form = new Form<Void>("step1") {
#Override
protected void onSubmit() {
candidate = databse.findCandidate(searchCandidateModel.getFirstName());
//UPDATE TABLE
}
};
form.add(firstName);
add(form);
add(dataView);
}
}
html file:
<form wicket:id="step1">
<input wicket:id="first_name" type="text" size="30"/>
</form>
<table cellspacing="0" class="dataview">
<tbody>
<tr wicket:id="simple">
<td><span wicket:id="name">Test ID</span></td>
</tr>
</tbody>
</table>
You can make you DataProvider - dynamic:
new ListDataProvider() {
#Override protected List getData() {
if (noFilter) return emptyList
else return database.getList(filter)
}
}
This way the provider will always load the data according to your data filter.
For more information about static vs. dynamic models/providers check:
https://cwiki.apache.org/confluence/display/WICKET/Working+with+Wicket+models#WorkingwithWicketmodels-DynamicModels

mvc passing parameter to controller

I am very new to MVC
I need some help to over come the issue of passing parameter to a controller on form submit
what i have got is the following controller and the view
public ActionResult Index(string method ="None")
{
if (Request.HttpMethod == "POST")
{
switch (method)
{
case "Add10":
_bag.GetBag = Get100Products().Take(10).ToList<Product>();
break;
case "Clear":
_bag = null;
_bag.GetBag = null;
_bag = new Models.Bag();
break;
case "Add":
if ((Request.Form["Id"] != null) && (Request.Form["Id"] != ""))
{
if (_bag.GetBag.Count < 100)
{
var p = GetProduct(Request.Form["Id"]);
int qnt = Convert.ToInt16(Request.Form["qnt"]);
if (p.ItemNumber != null)
{
p.Quantity = qnt;
p.Index++;
_bag.Item = p;
}
}
}
break;
}
}
return View(_bag.GetBag);
}
and the view part of the view
<div style="vertical-align:middle">
#using (Html.BeginForm("", "Home", new { method = "Add10" }, FormMethod.Post))
{
<!-- form goes here -->
<input type="submit" value="Add 10 Items to bag" />
}
#using (Html.BeginForm("GetDiscount", "Home", FormMethod.Post))
{
<div>
<!-- form goes here -->
<input type="submit" value="Get Discount" />
With MAX time in seconds <input type="text" name="time" maxlength="2" value="2" />
</div>
}
#using (Html.BeginForm("", "Home", new { method = "Clear" }, FormMethod.Post))
{
<input type="submit" value="Empty the bag" />
}
</div>
so i am expecting when the use clicked button Add 10 Items to bag to pass the method value "Add10" to the index controller and when clicked Empty the bag to pass "Clear" the method value in index controller
but it always shows as "None"
what have I done wrong?
</form>
First of all, you have to add [HttpPost] to your controller in order to accept POST requests:
[HttpPost]
public ActionResult Index(string method ="None")
{
You should differentiate GET and POST actions.
You can do like this:
// [HttpGet] by default
public ActionResult Index(Bag bag = null)
{
// "bag" is by default null, it only has a value when called from IndexPOST action.
return View(bag);
}
[HttpPost]
public ActionResult Index(string method)
{
// Your logic as specified in your question
return Index(_bag.GetBag);
}
EDIT:
Your code is wrong, for example you will get a NullReferenceException because your try to call a property on a null object (_bag):
_bag = null;
_bag.GetBag = null; // NullReferenceException: _bag is null!
Also your code would be cleaner and more easier to maintain if we split this Action into several actions and follow the technology philosophy.
Do you consider refactoring this piece of code into smaller and more understandable chunks?

After logout main window the popup window links still working

I am using struts 2 login interceptor. Code is working fine. In my application many popup windows have used.when I open my popup window and logout from my main window popup window showing login page as I coded but only for this scenario, i want that it will showing any message ( either session expired or u have already logged out) instead of login page.
Please go thru my code if any modification is required
LoginInterceptor.java
public class LoginInterceptor extends AbstractInterceptor implements
StrutsStatics{
private AdminUserSessionInfo objAdminUserSessionInfo = new AdminUserSessionInfo();
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(LoginInterceptor.class);
private static final String LOGIN_ATTEMPT = "loginAttempt";
private static final String LOGIN_OUT = "loginOut";
private static final String USER_HANDLE = "loggedInUser";
Map sessionMap = null;
public void init() {
log.info("Intializing LoginInterceptor");
}
public void destroy() {
}
public String intercept(ActionInvocation invocation) throws Exception {
final ActionContext context = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context
.get(HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) context
.get(HTTP_RESPONSE);
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
HttpSession session = request.getSession(true);
Object user = session.getAttribute(USER_HANDLE);
String loginOut = request.getParameter(LOGIN_OUT);
if (user == null) {
String loginAttempt = request.getParameter(LOGIN_ATTEMPT);
System.out.println("loginAttemp---->"+loginAttempt);
/* The user is attempting to log in. */
if (!StringUtils.isBlank(loginAttempt)) {
return invocation.invoke();
}
return "login";
} else {
return invocation.invoke();
}
}
web.xml
<interceptors>
<interceptor class="org.iaf.aos.common.LoginInterceptor"
name="loginInterceptor"></interceptor>
<interceptor-stack name="loginStack">
<interceptor-ref name="loginInterceptor" />
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="loginStack"></default-interceptor-ref>
<global-results><result name="login">aos.jsp</result></global-results>
<action name="checkUserLogin" class="org.iaf.aos.web.login.action.AdminUserAction" method="checkUserLogin">
<!-- <result name="success">index.jsp</result> -->
<interceptor-ref name="loginStack"></interceptor-ref>
<result name="success" type="chain">HomePage</result>
<result name="error">WEB-INF/jsp/admin/Error.jsp</result>
<result name="selectRole">aos1.jsp</result>
<!--<result name="selectRole">WEB-INF/jsp/admin/SelectRole.jsp</result>-->
</action>
<action name="home">
<!-- <result>index.jsp</result>-->
<interceptor-ref name="loginStack"></interceptor-ref>
<result name="success" type="chain">HomePage</result>
</action>
<action name="logOutUser" class="org.iaf.aos.web.login.action.LogOutUserAction">
<interceptor-ref name="loginStack"></interceptor-ref>
<result name="logout">WEB-INF/jsp/admin/LoggedOut.jsp
</result>
</action>
LogOutUserAction.java
public class LogOutUserAction extends ActionSupport {
private static final long serialVersionUID = 1L;
public String execute() throws Exception {
System.out.println("inside :: LogOutUserAction------");
Map session = ActionContext.getContext().getSession();
session.remove("loggedInUser");
return "logout";
}
}
logout.jsp
<td width="*" align="right" valign="top">
<s:url var="urlLogOut" action="logOutUser.action">
<s:param name="loginOut" value="%{'2'}"/>
</s:url>
<sx:a href="%{#urlLogOut}" targets="divAddEditUser">
<font color="white">Log Out</font>
</sx:a>
<!--<font color="white">Log Out</font>
--></td>
</tr>
AdminUserAction.java
ServletActionContext.getRequest().getSession().setAttribute("loggedInUser", loginId);
return "selectRole";
You will have to do that explicitly write that logic, It wont do by default.
In your logout action after removing the user from session, invalidate it too.
session.remove("loggedInUser");
session.invalidate();
session = null;
Then in your interceptor you check if session is valid or not, if not then you add an attribute, stating your session has either expired or you have logged out.
So your interceptor code become something like this:
HttpSession session = request.getSession(true);
if(session == null){
request.setAttribute("SessionExpired","Your session has expired or you have logged out");
}
Object user = session.getAttribute(USER_HANDLE);
Then if your jsp page when you show the login screen you check if request has "SessionExpired" attribute, if yes show that to the user.