This question already has answers here:
How to conditionally render plain HTML elements like <div>s?
(4 answers)
Closed 7 years ago.
I am using JSF 2.2 and PrimeFaces 5.2.
I have the following inside my body on my view:
<div class="headerDetails">
<h1> Nombre Empresa: #{loginController.login.empresa} </h1>
<h1> Bienvenido: #{loginController.login.nombre}</h1>
</div>
I want to dynamically hide and show the first <h1> depending on what user logged in. What is the best way of accomplishing this?
This is what I did for those who are interested:
<div class="headerDetails">
<h:panelGroup layout="block" rendered="#{loginTipoController.isEmpresarial()}">
<h1> Nombre Empresa: #{loginController.login.empresa} </h1>
</h:panelGroup>
<h1> Bienvenido: #{loginController.login.nombre}</h1>
</div>
My controller looks like this:
#ManagedBean
#ApplicationScoped
public class LoginTipoController {
private LoginTipo tipo;
public LoginTipo getTipo() {
return tipo;
}
public void setTipo(LoginTipo tipo) {
this.tipo = tipo;
}
#PostConstruct
public void init()
{
tipo = new LoginTipo();
//setting the value from get request
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
tipo.setTipo(params.get("tipo"));
}
public boolean isEmpresarial()
{
if(tipo.getTipo().equals("emp")) return true;
else return false;
}
}
If the user is "ind", I don't want to show the <h1> tag. If it is "emp", I want to show the tag.
Related
I am trying to post a string array to the post action in an Razor Pages project. For this, I thought about using a hidden <select> tag. The user would enter text into a text box, press a button and I would then add a new option to the <select> then post the whole thing with a submit button. However, after everything is posted, the array property of my model is empty.
Does anyone know if there is a better way of doing this or what I am doing wrong?
Razor:
<form method="post">
<input id="string-value" />
<input type="button" id="add-item" value="Add item" />
<select asp-items="#Model.Model.ArrayOfStrings" id="hidden-select"></select>
<table id="table-items">
</table>
<input type="submit" value="Submit" />
</form>
public class ArrayModel
{
public List<SelectListItem> ArrayOfStrings { get; set; } = new List<SelectListItem>();
}
public class IndexModel : PageModel
{
[BindProperty]
public ArrayModel Model { get; set; }
public void OnGet()
{
Model = new ArrayModel();
}
public void OnPost()
{
System.Diagnostics.Debugger.Break();
}
}
JS:
$('#add-item').on('click', function () {
debugger;
var value = $('#string-value').val();
$('#hidden-select').append(new Option(value, value));
$('#table-item tr:last').after('<tr><td>' + value + '</td></tr>')
});
Repository can be found here.
The options of the select will not be posted so this will not work.
The easiest way to do this is append the results to a hidden input with a separator char, then do a string split on the server side.
Another, maybee more elegant way, would be to add hidden inputs with the same name. Each input with it's own value. You should then be able to get this as a List or Array on the server.
Razor:
<input value="#String.Join(",", Model.Model.ArrayOfStrings)" id="tags"></select>
JS
$('#tags').val($('#tags').val() + ',' + value);
Controller
public void OnPost(string tags)
{
var tagsArray = tags.split(',');
}
This question already has answers here:
How to invoke a bean action method using a link? The onclick does not work
(3 answers)
Closed 6 years ago.
While page is reload, keep calling action method.
I only want to call this action method when link is clicked.
<li role="presentation">
<a role="menuitem" tabindex="-1" href="ViewAMC.xhtml" action="# {treeTableManagedBean.testingActionListener()}" >View AMC</a>
</li>
public void testingActionListener()
{
System.out.println("testing action listener!");
flag = false;
}
<h:commandLink action="#{treeTableManagedBean.testingAction()}" value="Click Here" actionListener="#{treeTableManagedBean.myActionListener}">
public void myActionListener(ActionEvent event) {
System.out.println("testing action listener!");
}
public String testingAction() {
System.out.println("testing action !");
return "ViewAMC.xhtml";
}
Try this out.
Panel is created and added to xhtml right but when I get it using findComponent("-formBotones-wizardEventContainer").getChildren() the result is null because its container got 1 children (id=tempTextIdLayer) when really html source show several children.
I've tried a solution with visitTree() but vars target and panel are the same, wizarEventContainer, and the got only 1 children (input hidden)
HtmlPanelGroup panel=(HtmlPanelGroup)FacesContextWrapper.getCurrentInstance().getViewRoot().findComponent("formBotones-wizardEventContainer");
panel.visitTree(VisitContext.createVisitContext(FacesContext.getCurrentInstance()),new VisitCallback() {
#Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target instanceof HtmlPanelGroup) {
HtmlPanelGroup layer = (HtmlPanelGroup) target;
System.out.println("id: " + layer.getId()); //wizardEventContainer // Collect them in an arraylist orso.
}
return VisitResult.ACCEPT;
}
});
Main xhtml code
<h:form id="formBotones" prependId="true">
<h:panelGroup layout="block" id="wizardEventContainer" styleClass="wizardEventContainer">
<h:inputHidden id="tempTextIdLayer" value="#{eventProvider.tempTextIdLayer}" />
</h:panelGroup>
</h:form>
HTML when panel is added
<form id="formBotones">
<input type="hidden" value="formBotones" name="formBotones">
<div class="wizardEventContainer" id="formBotones-wizardEventContainer">
<div data-widget="widget_formBotones_text_11_0" id="formBotones-text_11_0">
<div class="ui-panel-content ui-widget-content" id="formBotones-text_11_0_content">
<span id="formBotones-editor_text_11_0">Dynamic text</span>
</div>
<div class="ui-resizable-handle ui-resizable-e" style="z-index: 90;"></div>
<div class="ui-resizable-handle ui-resizable-s" style="z-index: 90;"></div>
<div class="ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se" style="z-index: 90;"></div>
</div>
<input type="hidden" value="text_11_0" name="formBotones-tempTextIdLayer" id="formBotones-tempTextIdLayer">
</div>
<input type="hidden" value="e5s4" id="javax.faces.ViewState" name="javax.faces.ViewState">
</form>
Create layers code
Here, it's a method which is setted to button's actionListener. It create a resizable and draggable panel with a span where I'll write dynamic text through javaScript.
public void createTextLayer() throws IOException{
logger.entry("EventProvider.createTextLayer()");
Application app=FacesContextWrapper.getCurrentInstance().getApplication();
UIComponent parent=FacesContextWrapper.getCurrentInstance().getViewRoot().findComponent("formBotones-wizardEventContainer");
CommandButton textBtn=(CommandButton)FacesContextWrapper.getCurrentInstance().getViewRoot().findComponent("formControl-textLayerBtn");
String finalId=null;
if(tempObjs!=null && tempObjs.size()>0 && tempObjs.containsValue("text")){
finalId="text_" + space.getIdSpace() + "_" + createFinalIndex("text");
}
else{
finalId="text_" + space.getIdSpace() + "_" + spaceBo.getDao().countSectionPages(space.getIdSpace(),4);
}
if(parent!=null){
HtmlPanelGroup panel=(HtmlPanelGroup)app.createComponent(HtmlPanelGroup.COMPONENT_TYPE);
panel.setId(finalId);
panel.setStyleClass(panel.getId());
panel.setStyle("display:inline-block;min-width:100px;min-height:100px;background:red;overflow:hidden;");
setTempTextIdLayer(finalId);
HtmlOutputText text=(HtmlOutputText) app.createComponent(HtmlOutputText.COMPONENT_TYPE);
text.setId("editor_" + panel.getId());
panel.getChildren().add(text);
Resizable resizable=(Resizable)app.createComponent(Resizable.COMPONENT_TYPE);
resizable.setFor(panel.getId());
resizable.setMaxWidth(new Integer(800));
resizable.setMaxHeight(new Integer(600));
resizable.setMinWidth(new Integer(50));
resizable.setMinHeight(new Integer(50));
resizable.setContainment(false);
resizable.setFor(panel.getId());
panel.getChildren().add(resizable);
Draggable drag=(Draggable)app.createComponent(Draggable.COMPONENT_TYPE);
drag.setFor(panel.getId());
drag.setOpacity(new Double(0.6));
drag.setContainment(new String("parent"));
drag.setSnap(true);
drag.setSnapMode(new String("outer"));
drag.setSnapTolerance(new Integer(5));
drag.setFor(panel.getId());
panel.getChildren().add(drag);
tempObjs.put(panel,"text");
}
updateViewRoot();
//Disabling text button
textBtn.setDisabled(true);
}
Add layer to container code
Here I get the container, wizardEventContainer, and I add every panel which are saved on tempObjs var.
public void updateViewRoot(){
logger.entry("EventProvider.updateViewRoot()");
UIComponent parent=FacesContextWrapper.getCurrentInstance().getViewRoot().findComponent("formBotones-wizardEventContainer");
if(parent!=null){
for (Entry<UIComponent, String> entry : tempObjs.entrySet()) {
parent.getChildren().add(entry.getKey());
}
}
}
As getViewRoot() only return elements which are written on xhtml file I've decided to save dynamic components in a map and when I place this dragabble component in the right site the I pass css style and other properties through managed bean properties, so every time a new panel is added on xhtml I create a new dynamic component with new properties setted and I replace for old dynamic component saved in the map.
It's a no elegant way but works fine at the moment for me.
public void saveTextLayer(){
logger.entry("EventProvider.saveTextLayer()");
List<UIComponent> list=null;
if(tempObjs.containsValue("text"))
list=getKeysByValue(tempObjs,"text");
for (UIComponent c:list){
if (c instanceof HtmlPanelGroup){
HtmlPanelGroup panel=(HtmlPanelGroup)c;
if(panel.getId().equals(getTempTextIdLayer())){
panel.setStyle(getTempCSS());
if(panel.getChildren().get(0) instanceof HtmlOutputText){
((HtmlOutputText)panel.getChildren().get(0)).setValue(getTempHTML());
}
//Adding delete layer
Application app=FacesContextWrapper.getCurrentInstance().getApplication();
HtmlPanelGroup deleteLayer=(HtmlPanelGroup)app.createComponent(HtmlPanelGroup.COMPONENT_TYPE);
deleteLayer.setId("delete_" + panel.getId());
deleteLayer.setStyle("display:inline-block;width:5px;height:5px;background:white;");
deleteLayer.setOnclick("deleteLayer($(this));");
panel.getChildren().add(0,deleteLayer);
//Replacing UIComponent
tempObjs.remove(c);
tempObjs.put(panel, "text");
updateViewRoot();
//Deleting temp vars
setTempCSS("");
setTempTextIdLayer("");
setTempHTML("");
}
}
}
I have a model with properties declared, Controller actions. and View with Viewmodel specified. I fill data in the form and submit, but model has only null values for all properties. If i try with view model i get same null values in HttpPost action.
My Model:
public class Supplier
{
public string SupplierSequenceNumber { get; set; }
public string SupplierName { get; set; }
public string SupplierActive { get; set; }
}
My Controller:
[HttpGet]
public ActionResult Add()
{
SupplierVM objSupplierVM = new SupplierVM();
return View(objSupplierVM);
}
[HttpPost]
public ActionResult Add(Supplier objSupplier)
{
return View();
}
My View:
#model AIEComm.ViewModel.SupplierVM
#using (Html.BeginForm("Add", "Supplier", FormMethod.Post, new { id = "formAddSupplier" }))
{
<div class="control-group">
#Html.LabelFor(m=>m.objSupplier.SupplierName, new{#class = "control-label"})
<div class="controls">
#Html.TextBoxFor(m => m.objSupplier.SupplierName, new { placeholder = "Swatch Style" })
#Html.ValidationMessageFor(m=>m.objSupplier.SupplierName)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m=>m.objSupplier.SupplierActive, new{#class = "control-label"})
<div class="controls">
#Html.DropDownListFor(m=>m.objSupplier.SupplierActive,new SelectList(AIEComm.Models.Utilities.YesNoSelectList,"Value","Text"),new{#class=""})
#Html.ValidationMessageFor(m=>m.objSupplier.SupplierName)
</div>
</div>
<div class="control-group">
<div class="controls">
<input type="submit" class="btn btn-primary" id="btnSubmit" value="Add"/>
</div>
</div>
}
The reason for this is the following code:
m => m.objSupplier.SupplierName
You're generating HTML elements with a model that is inside a ViewModel. This is a good approach, and your problem can be solved quite easily.
It's a good approach because you're keeping things organised, but it's not working because the above code is saying:
Ok, using the ViewModel object (m), take the objSupplier object and then use the SupplierName property.
This is fine, but then when you're submitting data, you're saying (to the action):
Hi, I have a SupplierName property. Please put this into the objSupplier object which you can find inside the ViewModel object.
To which the action says "Well, I am expecting an objSupplier object, but what's this ViewModel you speak of?"
A simple solution is to create a new partial view to generate your form. It's model type should be:
_SupplierForm.cshtml
#model Supplier
#* // The Form *#
In your View, continue to use the same ViewModel, but pass in the correct supplier model:
#model AIEComm.ViewModel.SupplierVM
#Html.Partial("_SupplierForm", Model.objSupplier)
I am starting an adventure with Apache Tapestry5. I am trying to make simple component (for tests), consisting of pair of Textfields. Component is named "TestComp". I have following elements:
testComp.tml
<t:container
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<p>
<input t:type="TextField" t:id="testOne" t:value="testOne.input"/><br/>
<input t:type="TextField" t:id="testTwo" t:value="testTwo.input"/><br/>
</p>
</t:container>
TestComp.java
public class TestComp {
private DataContainer testOne;
private DataContainer testTwo;
#SetupRender
public void setup(){
testOne = new DataContainer();
testTwo = new DataContainer();
}
public String getContentOfTestOne() {
return testOne.getInput();
}
public String getContentOfTestTwo() {
return testTwo.getInput();
}
public DataContainer getTestOne() {
return testOne;
}
public void setTestOne(DataContainer testOne) {
this.testOne = testOne;
}
public DataContainer getTestTwo() {
return testTwo;
}
public void setTestTwo(DataContainer testTwo) {
this.testTwo = testTwo;
}
}
And then I am trying to use it in other place, for example in index.tml:
<form t:type="form" t:id="out">
<t:testComp />
<br/><input type="submit" value="Component"/>
</form>
According to dozens of materials and examples I've found (to be honest non of it refereed to case similar to mine) such implementation should result of showing testComp element in the form, but unfotrunately there is nothing rendered above the button (though tapestry is not crashing). What am I missing? And will I be able to put in Index.java property of TestComp type and bind it with my
<t:testComp />
in Index.tml by id (or it requires something more to implement in my custom component?)
Did you provide the full index.tml file? If so, you are missing the tapestry namespace as well as a correctly setup html document. Try the following:
Index.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<head>
<title>My page</title>
</head>
<body>
<form t:type="form" t:id="out">
<div t:id="testComp" />
<br/><input type="submit" value="Component"/>
</form>
</body>
</html>
In your Index.java you can use this to access your component.
#component(id="testComp")
private TestComp testComp;
If this does not work there is probably something wrong in your configuration or setup and you might just be looking at a static tml file not handled by tapestry at all. In this case follow the step-by-step guide on the Getting Started page.