With JSF2, Facelets.
I need to code a CSS style based on a variable that can contain multiple (undetermined) values:
<p rendered="#{not empty element.state}" class="globalStyle CODED_CLASS_ACCORDING_TO_element.state">#{element.state}</p>
How to get CODED_CLASS_ACCORDING_TO_element.state in JSF is uncertain to me. Most of the answers I see always apply a ternary option (odd/even, on/off, applied/not_applied...) which is not valid in my case, because state can be "Done", "Under development", "initiated", etc. Neither it is to code the conversion in the bean, since it should not know about view. Is still option 3 in this answer the preferred one?
style="color: #{yourVar == 'yes' ? 'green' : 'red'};"
make two <h:outputText> components with different styles, each with a different rendered attribute (one #{yourVar == 'yes'} and
the other #{yourVar == 'no'})
define a (jstl/facelets/jsf 2.0) function that takes the var as argument and returns a style/class -
styleClass="#{my:getStyleClass(yourVar)}"
If so, I am not sure how to do this (I am entirely new to JSF). I can think of a <cc:interface> and <cc:implementation> and render the right output according to some <c:if> condition, but I am sure it is not the right way and it would bevery inneficient.
Just make state an enum.
public enum State {
DONE, UNDER_DEVELOPMENT, INITIATED, ETC;
}
And use it directly as class name.
<p ... class="globalStyle state #{element.state}">
.state.DONE {
color: green;
}
.state.UNDER_DEVELOPMENT {
color: orange;
}
.state.INITIATED {
color: red;
}
.state.ETC {
color: pink;
}
Using enums has other advantages too. E.g. How to use enum values in f:selectItem(s) and Localizing enum values in resource bundle.
Related
For one of the columns in my Grid i use a TemplateRenderer (an icon is shown to give a hint about a possible issue with this row):
grid.addColumn(TemplateRenderer.<T>of("<iron-icon icon='[[item.icon.name]]' title='[[item.icon.tooltip]]' style='width: 1em;'></iron-icon>")
.withProperty("icon", item -> StatusHint.of(item))
...
;
For some items, this template is not relevant (there are no issues), so property "icon" is null. The result is this HTML: <iron-icon style="width: 1em;" title="undefined"></iron-icon>.
Also note that the 'icon' attribute is not shown and the title attribute is undefined?!
Although the browser does not show anything, the clueless HTML code is ugly imho (do not know if there are also performance penalties).
An empty cell or <div></div> looks much better.
How do i accomplish this? The API does not give me any hints.
It's a bit elaborate, but you can use Polymer's dom-if templates to create conditional subtemplates for cases where you can't just bind a property. Here's an example that prints "even" or "odd" depending on whether a Person's age is even or odd:
grid.addColumn(
TemplateRenderer.<Person>of(
"<template is='dom-if' if='[[item.even]]'><b>even</b></template><template is='dom-if' if='[[!item.even]]'><i>odd</i></template>"
).withProperty("even", p -> {
int age = p.getAge();
return age % 2 == 0;
}))
.setHeader("Is age even or odd?");
I am trying to develop an UI and the first step is to create CssLayout. Each CssLayout component is added hierarchically with and many CssLayout component.
The problem is when i run the application and inspect the div tags, the class attribute has extra strings that needs to be removed.
<div class="v-csslayout v-layout v-widget .content-container v-
csslayout-.content-container v-has-width v-has-height" style="width: 100%;
height: 100%;"><div class="v-csslayout v-layout v-widget .inner-content-
container v-csslayout-.inner-content-container"></div></div>
and what I need is
<div class=".content-container">
<div class=".inner-content-container">
</div>
</div>
Java Code:
#StyleSheet("{css/spreadjsdefault.css}")
public class SpreadJSWidget extends CssLayout {
/**
*
*/
public SpreadJSWidget() {
super();
addStyleName(".content-container");
CssLayout mainBox = new CssLayout();
mainBox.addStyleName(".inner-content-container");
addComponent(mainBox);
}
spreadjsdefault.css (They are empty for now)
.content-container
{
}
.inner-content-container
{
}
Please advice !
Two things:
In order to be able to properly match the css rules, you have to omit the leading . when adding the style name, i.e. addStyleName("contentContainer"). This way, the css elements will match your style definition.
Css classes like v-csslayout are default classes defined by vaadin used by the default themes to provide a basic layout. They are there by default and can't (and actually shouldnt) be removed entirely. What you can do, however, is to define and overwrite these rules yourself. What's important: Either way, your custom classes will still match when you define them in your style sheet and can overwrite the default theming.
I have the following navigation using Thymeleaf and I want to append a CSS class when the link is selected:
<div class="nav-links">
<a th:href="#{/somepage(someId=${someId},filter='filterA')}" href="/somepage"
class="subnav-item"
th:classappend="${selected}">Filter A</a>
<a th:href="#{/somepage(someId=${someId},filter='filterB')}" href="/somepage"
class="subnav-item"
th:classappend="${selected}">Filter B</a>
<a th:href="#{/somepage(someId=${someId},filter='filterC')}" href="/somepage"
class="subnav-item"
th:classappend="${selected}">Filter C</a>
</div>
Assuming some style like:
.subnav-item.selected, .subnav-item.selected:hover, .subnav-item.selected:focus {
background-color: #FFF;
border-color: #000;
}
Looking at this question, it can be easily done based on the URI of the page (in this case, somepage but I need to have it work selectively based on the request parameter (in this case, filter). Is there an easy way to do this?
I tried adding the selected value to the model on the server side and separately tried using the request itself, but it does not differentiate based on the filter param (just on the somepage page).
Is the only way to do some hacky stuff with request.getQueryString()?
Found the answer. There's a utility for the HttpServletRequest that can easily be accessed as such:
th:classappend="${#request.getParameter('filter') == 'filterA' ? 'selected' : ''}"
I have a number of tabs, representing different services. I wish to have a final 'tab' tagged on the end of the list used to add a new service. Denoted by a simple '+'. This will open a simple dialogue.
I was hoping I could put my own ng-click behaviour on this single tab and prevent default but this doesn't work.
Is there any way I can 'catch' the tab click event BEFORE the tab body switch takes place and prevent it from happening?
It seems that it is not possible at the moment (see e.g. https://groups.google.com/forum/#!topic/ngmaterial/rNWMk3S9uDI) - at least using official api.
If you are ok with a solution which hacks into the directive internals then you can do following:
angular.module('MyApp').directive('tabWatcher', function() {
return {
require: ['mdTabs'],
restrict: 'A',
link: function(scope, el, attrs, controllers) {
var mdTabsCtrl = controllers[0];
var origSelectFn = mdTabsCtrl.select;
// overwrite original function with our own
mdTabsCtrl.select = function(index, canSkipClick) {
if (...) {
origSelectFn(index, canSkipClick);
}
}
}
};
I've placed a demo here http://codepen.io/jarek-jpa/pen/wGxqOq . Try to click some tabs. The select() call will be intercepted and depending on a condition let pass or not.
Disclaimer: Again, it hacks into the md-tabs directive internals, so may stop working any time (tested with angular-material 1.0.7)
You can set pointer-events to none to prevent the md-tab from responding to clicks.
Example:
<style>
md-tabs.readonly {
pointer-events: none;
user-select: none;
}
</style>
<md-tabs class="readonly">
<md-tab label="can't touch this"></md-tab>
</md-tabs>
This is tested to work with Angular Material 1.0.1
I have a column of radio buttons in h:datatable in JSF2 but I can not find a way to group them. Meaning all of them can be selected at the same time where as whole point of radio button is so that only one can be selected at any given time. I am sure there will be standard way of doing it.
I am using myfaces. Can use richfaces if really needed to.
Can any one help with this.
When using standard JSF <h:selectOneRadio> component inside a <h:dataTable> you'll need to bring a shot of JavaScript into the game which unchecks all other radio buttons in the same column when one is checked.
<h:column>
<h:selectOneRadio onclick="uncheckOthers(this);">
</h:column>
with
function uncheckOthers(radio) {
var name = radio.name.substring(radio.name.lastIndexOf(':'));
var elements = radio.form.elements;
for (var i = 0; i < elements.length; i++) {
if (elements[i].name.substring(elements[i].name.lastIndexOf(':')) == name) {
elements[i].checked = false;
}
}
radio.checked = true;
}
First, it's ludicrous that something this simple in HTML or JSP is so hard to do in JSF. These added layers should be making life easier, not harder. But it seems to me they just make life harder. I used to like them. Now I am a Java Luddite, advocating now in favor of simpler approaches that include less in the way of "new cool-sounding 'technologies'" and more in the way of "stuff that just plain works without having to struggle all week to do something that used to take just 5 minutes". Anyway, I have tried the past 3 working days to get the simple functionality in JSF to work that causes other radio buttons to deselect and leave the user-selected one unchanged. I tried several approaches including a custom tag library ("overkill", defined) and a number of mixing and matching of stuff that only produced a lot of stacktraces. I finally fell back on Javascript and accepted that creating a reliably generalized solution was not likely. I have read similar complaints elsewhere. OK, my gripe session is over. Here's what I did to slay my particular JSF-radio-button dragon:
On the .xhtml page:
<ui:composition template="../template.xhtml"
...
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="https://ajax4jsf.dev.java.net/ajax"
...
>
<a4j:loadScript src="/resources/scripts/custom.js" />
...
<ui:param name="pageBean" value="#{recordsBean}" />
...
<h:dataTable id="tblMine"
value="#{pageBean.records}"
var="item"
border="1" celpadding="0" cellspacing="0"
style="font-size=10px;text-align: center;"
>
<h:column>
<f:facet name="header">
<h:panelGroup><h:panelGrid cellspacing="0" cellpadding="0" border="0"
id="rowSelect" columns="1" width="100%"><h:outputText
value="Select" /></h:panelGrid></h:panelGroup>
</f:facet>
<h:selectOneRadio id="userselectedrecord"
onclick="javascript:clearOtherRadioButtons(event);" >
<f:selectItem itemValue="#{item.recordid}"
itemLabel="" /> <!-- I set itemLabel to "" because in my case,
I don't want any text next to the radio btns -->
</h:selectOneRadio>
</h:column>
...
... and the rest of the page ...
In the custom.js file, I have:
function clearOtherRadioButtons(evnt)
{
// Have to try 'currentTarget', then 'srcElement'. Issue is Firefox
// supports 'currentTarget' but IE does not. IE supports 'srcElement'.
var btn = (evnt.currentTarget) ? evnt.currentTarget : evnt.srcElement;
var matchindexlocn = btn.id.indexOf('userselectedrecord');
var btnidstarttxt = btn.id.substring(0,
matchindexlocn + 18 ); // 'userselectedrecord' length = 18
var elementid = '';
var i = 0;
var ele = null;
var allElements = document.getElementsByTagName('*');
for(i = 0; i < allElements.length; i++)
{
elementid = allElements[i].id;
if ( (elementid.indexOf(btnidstarttxt) == -1) &&
(elementid.indexOf('_') > -1) )
{
try
{
ele = document.getElementById(elementid);
ele.checked = false;
} catch (e) {}
}
}
} // function clearOtherRadioButtons(evnt)
That's it. By way of some explanation re that if() in the Javascript:
elementid.indexOf(btnidstarttxt) == -1
--> This narrows the elements down to those that do not start with the JSF-added object ID text that is associated with the button group associated with the passed-in event. We do not want to unselect the button in the button group whose event was passed into the function.
elementid.indexOf('_') > -1
--> This narrows the elements down further to only actual buttons since JSF adds underscores to the button element IDs.
The reason the code that sets checked = false is in a try..catch block is just in case something goes wrong with any presumptions around the logic and the circumstance is not handled. If you know the environment and can control the element ids, you should be fine. However on the off chance that something changes due to, let's say for example, the app's host server getting some new version JSF library installed that overrides your app's classloading policy (in a work environment, these things as we know can happen beyond our control) that now assigns these element ids differently, the app won't break with a sudden nasty Javascript error or worse yet, the radio button selection just stops working. Worst I guess that can happen is that multiple radio btns can be selected at the same time and the user can submit them. I suppose a good precaution to take is to add yet more Javascript code to validate that only one option is being submitted by the user, or validate the user's submission server-side.
See, way too much work just to manage radio button state.