Display message from Servlet to JSF page - servlets

I'm trying to display success message in xhtml page from servlet but no luck, here's my code
In servlet i have
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
FacesContext facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
facesContext.addMessage( "user:displaymessagesave", new FacesMessage("user saved successfully" ));
In xhtml page inside form i have written tag for display message form id=user
<h:message class="success" for="displaymessagesave" id="displaymessagesave" />
Saving to database is happening but its not displaying any message, please suggest where i'm going wrong.

It is not possible to access FacesContext from a servlet other than FacesServlet.
Recently I faced that same problem, and what I did was, on my servlet, put the messages in the Session:
List<String> msgs=(List<String>)request.getSession().getAttribute(KEY);
if (msgs==null)
{
msgs=new ArrayList<String>();
}
msgs.add("My new message");
request.getSession().setAttribute(KEY, msgs);
Then, on the xhtml view, I added a call to put these messages on FacesContext, and a growl element:
<h:outputText value="#{managed.prepareMessages()}"/>
<p:growl id="growl" showDetail="false" life="4000" />
Finally, the prepareMessages method takes them from session and add the messages to FacesContext:
public String prepareMessages()
{
List<String> msgs = (List<String>)FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get(KEY);
if (msgs!=null)
{
for(String msg:msgs)
{
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(msg));
}
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().remove(KEY);
}
return "";
}
It may not be an elegant solution, but is the only one I found...

Don't give the same id for message as the "for" component. If you just want a messageholder without attaching it to a valueholder than you should use the tag.
<h:messages class="success" id="displaymessagesave" />

Related

How to create shared form in ASP.NET CORE Razor Pages?

I have to create a reusable form in my page header. It should be displayed on each page. Simple input and submit button that will send a POST request.
Options that I'm aware of are partial views or view components.
I checked a documentation about view components but there is no mention that it works with forms. Only InvokeAsync method is available to initialize a view.
With partial view, it may be hard to define its page model and I don't understand where to put its POST handler.
One other option I see, somehow to place a form directly on _Layout.cshtml, but, again, it doesn't have its page model (afaik),
So what is a way to create a shared form, and where POST request should be handled?
You should use a view component, as this allows you to have a somewhat self-contained model and view interaction.
public class SharedFormViewComponent : ViewComponent
{
public Task<IViewComponentResult> InvokeAsync() =>
Task.FromResult(View(new SharedFormViewModel()));
}
Then, put your form HTML code in Views\Shared\Components\SharedForm\Default.cshtml. For your form's action, you'll need to specify a route. More on that in a sec. Then, to display your form:
#await Component.InvokeAsync("SharedForm")
Now, as you've somewhat discerned, view components can't be posted to. It's not an issue of "not supporting forms"; they're literally not part of the request pipeline, and therefore can't respond to requests such as a POST. You'll need a distinct action that will handle the POST on some controller. On your component's form tag, then:
<form asp-action="SharedFormHandlerAction" asp-controller="Foo" asp-area="" method="post">
The asp-area attribute should be provided just in case this is used in the context of different areas.
You'll also need a "return URL". This will be the URL of the current page, so that after the user successfully posts the form, they'll go back to the page they submitted it from. You can achieve that by adding a hidden input to your form:
<input type="hidden" name="returnUrl" value="#(Context.Request.Query["returnUrl"].FirstOrDefault() ?? (Context.Request.Path + Context.Request.QueryString))" />
Your handler action should then take a param like string returnUrl = null, and on success you should do:
return !string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)
? Redirect(returnUrl)
: RedirectToAction("SomeDefaultAction");
Where things get a little tricky is in handling validation errors. Since you're posting to a different action, you can't return the previous view the user was on to show the validation errors within the from in the layout or whatever. Instead, you'll want a view specific to this handler action which will simply be your shared form. You can use the view for your view component here as a partial:
<partial name="~\Views\Shared\Components\SharedForm\Default.cshtml" />
If you want to use a PageModel, you could do so in a BasePageModel class that inherits from PageModel and that all your pages inherit from. You can use a named handler (https://www.learnrazorpages.com/razor-pages/handler-methods#named-handler-methods) in the BasePageModel class to process the form submission. Add the form directly to the Layout, which will need an #model directive for your BasePageModel type.
public class BasePageModel : PageModel
{
[BindProperty]
public string SearchString { get; set; }
public void OnPostBaseSearch()
{
// process the search
}
}

How to POST from one Page Handler to another?

I am working on a ASP.NET Core 2.0 project using Razor Pages (not MVC).
I have the following flow:
User fills out form and POSTs
This page's POST handler validates the info and returns Page() if there are issues. If not, handler saves data to database.
From here, I want the handler to POST to a different page's POST handler with the validated and saved data from Step 2.
How do I POST to another page from within a page handler? Is this the appropriate way to do this kind of thing? The reason I don't want to RedirectToPage() is because I don't want the final page in the sequence to be navigable via GET. The final page should not be accessible via a direct link but should only return on a POST.
I thought about validating/saving the data and setting a boolean "IsValid" and returning the page, checking for that IsValid, and immediately POSTing to the final page via JS. However this feels dirty.
Set the "asp-page" property of the form to your other page. Then set values in the standard way.
<form method="post" asp-page="/pathto/otherpage">
Select Example:<select name="DataForOtherPage">
Then in your controller, bind the value...
[BindProperty]
public string DataForOtherPage { get; set; }
You don't need to cross post!
If possible, you should avoid the cross-post. Do it all under the original action. The action can return a different view by specifying the view name in the View call.
If the target of the cross-post contains complicated logic that you don't want to duplicate, extract it to a common library, and call it from both actions.
For example, instead of
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
return //Something that posts to action2
}
}
ActionResult Action2()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
return View("View2");
}
Do something like this:
class CommonLibrary
{
static public void DoSomethingComplicated()
{
DoSomethingComplicated1();
DoSomethingComplicated2();
DoSomethingComplicated3();
DoSomethingComplicated4();
}
}
ActionResult Action1()
{
if (canHandleItMyself)
{
return View("View1");
}
else
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
}
ActionResult Action2()
{
CommonLibrary.DoSomethingComplicated();
return View("View2");
}
If you really want to cross-post
If you insist on using a cross-post, you will have to render a page that does the post, e.g.
<HTML>
<BODY>
<IMG Src="/Images/Spinner.gif"> <!-- so the user doesn't just see a blank page -->
<FORM name="MyForm" Action="Action2" Method="Post">
<INPUT type="hidden" Name="Argument1" Value="Foo">
<INPUT type="hidden" Name="Argument2" Value="Bar">
</FORM>
<SCRIPT type="text/javascript>
document.getElementById("MyForm").submit(); //Automatically submit
</SCRIPT>
</BODY>
</HTML>

Unable to display an image in my view

I try to display an image (stored in my database) and I have some trouble with it.
I have the following code in my view:
<img src="#Html.Action("DownloadLogo", new { logoID = item.Logo.Key })" alt="" width="60" height="60">
And I have the following code in my controller:
public FileContentResult DownloadLogo(int logoID)
{
LogoDTO logoDTO = _serviceClient.GetLogo(logoID);
return File(logoDTO.LogoContent, logoDTO.LogoContentType);
}
I got the error below when reaching the code in my view:
HttpException
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
Before leaving the controller I check values:
logoDTO.LogoContent = {byte[50802]}
logoDTO.LogoContentType = "image/png"
Any idea?
Thanks.
Html.Action should be Url.Action instead. Html.Action will render an tag inside your href attribute. Url.Action will only render the URL.

Validating that a form input is not empty

I have this code for Form Submit..
<input type="submit" runat="server" id="buttonSubmit" value="Add" style="width:100px;" />
My BeginForm is like this..
<% using (Html.BeginForm("Insert", "StudentController", FormMethod.Post, new { #id = "exc-" }))
{%>
I have one textbox in my view I need to check my textbox is empty or not if it is Empty display alert box saying please Enter some value in textbox
other wise go to controler..
Please any body help me out?
thanks
You can do this many ways, but possibly the cleanest is to use Data Annotations on your ViewModel. For example -
public class MyViewModel
{
[Required]
public string MyProperty { get; set; }
}
Now in your View use
<% Html.EnableClientValidation(); %>
just before you start the form. This will cause a JavaScript object to be emitted in the markup sent to the client. The script looks like this example
<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"FirstName","ReplaceValidationMessageContents":true,"ValidationMessageId":"FirstName_validationMessage","ValidationRules":[{"ErrorMessage":"The First Name field is required.","ValidationParameters":{},"ValidationType":"required"}]},{"FieldName":"LastName","ReplaceValidationMessageContents":false,"ValidationMessageId":"LastName_validationMessage","ValidationRules":[{"ErrorMessage":"The Last Name field is required.","ValidationParameters":{},"ValidationType":"required"}]},{"FieldName":"EmailAddress","ReplaceValidationMessageContents":false,"ValidationMessageId":"EmailAddress_validationMessage","ValidationRules":[{"ErrorMessage":"The Email Address field is required.","ValidationParameters":{},"ValidationType":"required"}]},{"FieldName":"ZipCode","ReplaceValidationMessageContents":false,"ValidationMessageId":"ZipCode_validationMessage","ValidationRules":[{"ErrorMessage":"Zip Code must be 5 character long.","ValidationParameters":{"minimumLength":0,"maximumLength":5},"ValidationType":"stringLength"},{"ErrorMessage":"Zip Code must be five digits.","ValidationParameters":{"pattern":"\\d{5}"},"ValidationType":"regularExpression"},{"ErrorMessage":"The Zip Code field is required.","ValidationParameters":{},"ValidationType":"required"}]}],"FormId":"form0","ReplaceValidationSummary":false,"ValidationSummaryId":"valSumId"});
//]]>
</script>
This object contains validation metadata that can be used by a client side validation plugin to hook up validation on the client side. The plugin that comes with ASP.NET MVC 2 is the Microsoft AJAX validator and you will need to include these scripts in the page to use the validation (MicrosoftAjax.js, MicrosoftMVCAjax.js and MicrosoftMvcValidation.js in that order).
Alternatively, if you're more comfortable with jQuery, you can get a script in the MvcFutures source that hooks the validation into the jQuery validate plugin (this isn't a fully fledged script and is missing a few pieces, such as getting client side validation summaries). The script is MicrosoftMvcJQueryValidation.js and you can get it here
The advantage of using Data Annotations is that you get the server side validation too and your client and server side validation will validate for the expected values. Also, the Data Annotations allow you to set Error Messages and names for the field labels from the attributes (error messages and display names* can also come from resource files)
*Because MVC2 was compiled against .NET 3.5 version of Data Annotations, display name cannot be set from resource files. There is a workaround to this - DisplayName attribute from Resources?.
NOW THE EASY WAY
Just set up a submit event handler on the form
var form = document.getElementById('exc-');
var oldSubmit = form.onsubmit || function() {};
form.onsubmit = function() {
var input = document.getElementById('myinput');
if (input.value === '') {
alert('please Enter some value in textbox');
return false;
}
oldSubmit();
}
or with jQuery
$('#exc-').submit(function() {
if ($('#myinput').val() === '') {
alert('please Enter some value in textbox');
return false;
}
});

Retrieving data from Html.DropDownList() in controller (ASP MVC) | string returned?

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.

Resources