I have a primeface datepicker inside a modal dialog. Setting the initial date with the pattern "MMMM yyyy" (german) works fine. When i am trying to update the componenent via an ajax call im getting the javascript exception "uncaught name at positon [...]".
I am using Primefaces 7.0 and wrote a Year Month Converter by myself.
PrimeFaces locale:
PrimeFaces.locales['de'] = {
closeText: 'Schließen',
prevText: 'Zurück',
nextText: 'Weiter',
monthNames: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
monthNamesShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
dayNamesShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'],
dayNamesMin: ['S', 'M', 'D', 'M ', 'D', 'F ', 'S'],
weekHeader: 'Woche',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: '',
timeOnlyTitle: 'Nur Zeit',
timeText: 'Zeit',
hourText: 'Stunde',
minuteText: 'Minute',
secondText: 'Sekunde',
currentText: 'Aktuelles Datum',
ampm: false,
month: 'Monat',
week: 'Woche',
day: 'Tag',
allDayText: 'Ganzer Tag',
};
Converter:
/**
* The Class YearMonthConverter.
*/
#Slf4j
#SuppressWarnings("common-java:DuplicatedBlocks")
#FacesConverter(value = "yearMonthConverter")
public class YearMonthConverter implements Converter {
private static final String PATTERN = "MMMM yyyy";
#Override
public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String s) {
String componentPattern = extractPattern(uiComponent);
String pattern = componentPattern.equals("") ? PATTERN : componentPattern;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, Locale.GERMANY);
try {
return YearMonth.parse(s, formatter);
} catch (DateTimeParseException e) {
log.warn("conversion of date '{}' expected pattern '{}' failed with {}", s, pattern, e);
return YearMonth.now();
}
}
#Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object o) {
if (o instanceof YearMonth) {
String componentPattern = extractPattern(uiComponent);
String pattern = componentPattern.equals("") ? PATTERN : componentPattern;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, Locale.GERMANY);
return formatter.format((YearMonth) o);
} else {
return null;
}
}
private String extractPattern(UIComponent component) {
// try to get the pattern from component
if (component instanceof Calendar) {
Calendar calendarComponent = (Calendar) component;
return calendarComponent.getPattern();
} else if (component instanceof DatePicker) {
DatePicker datepickerComponent = (DatePicker) component;
return datepickerComponent.getPattern();
}
return "";
}
}
Example xhtml-file:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<composite:interface>
</composite:interface>
<composite:implementation>
<style type="text/css">
.ui-panel .ui-panel-content {
padding: 0;
}
</style>
<!-- modaler someDialog -->
<p:dialog id="someDialog"
header="some header"
widgetVar="someDlg"
modal="true"
width="500"
height="280"
resizable="false"
closeOnEscape="true">
<p:panel id="pnlContent" styleClass="ui-noborder">
<p:panelGrid id="inputArea" columns="2">
<p:outputLabel value="Label:" style="width: 12em; display: block;"/>
<p:outputLabel value="example"
style="display: block;"/>
<p:outputLabel value="Monat:" style="width: 12em; display: block;"/>
<h:panelGroup>
<!-- Monat zurück -->
<p:commandButton
id="btnPrevMonth"
action="#{someDialogVC.previousMonth}"
style="padding: 2px"
icon="fa fa-angle-double-left"/>
<!-- Monatsanzeige -->
<p:datePicker id="dpMonat" view="month"
value="#{someDialogVC.state.selektierterMonat}"
converter="yearMonthConverter" pattern="MMMM yyyy" yearNavigator="true"
yearRange="2000:2050" inputStyle="width: 17em;" readonlyInput="true">
<p:ajax event="dateSelect" listener="#{someDialogVC.monthChanged}"/>
</p:datePicker>
<!-- Monat vor -->
<p:commandButton
id="btnNextMonth"
action="#{someDialogVC.nextMonth}"
style="padding: 2px"
icon="fa fa-angle-double-right"/>
</h:panelGroup>
</p:panelGrid>
<p:separator style="border-color: #aaaaaa; margin-bottom: 10px;"/>
<div style="display: flex; justify-content: flex-end">
<p:commandButton id="btnCreate"
value="Anlegen"
action="#{someDialogVC.createAndExit()}"
disabled="#{someDialogVC.doGetAnlegenDisabled()}"/>
</div>
</p:panel>
<p:blockUI block="pnlContent" trigger="btnCreate">
<p:graphicImage name="images/loader.gif"/>
</p:blockUI>
</p:dialog>
</composite:implementation>
</html>
setting initial date in bean:
#PostConstruct
public void init() {
data = new someDialogVO();
state = new someDialogVS();
state.setSelektierterMonat(YearMonth.now());
}
code snippets bean:
public void previousMonth() {
state.setSelektierterMonat(state.getSelektierterMonat().minusMonths(1L));
updateMonat();
}
public void nextMonth() {
state.setSelektierterMonat(state.getSelektierterMonat().plusMonths(1L));
updateMonat();
}
private void updateMonat() {
PrimeFaces.current().ajax().update("contentForm:someDialog:dpMonat");
}
After the ajax update call i am able to see, that the new Month is selected visually but after some milliseconds i am getting the described javascript exception. When using the pattern "MM.yyyy" everything works fine.
This appears to be a problem with the datePicker component. I have tried reproducing this with a minimalistic test:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<script>
PrimeFaces.locales ['de'] = {
closeText: 'Schließen',
prevText: 'Zurück',
nextText: 'Weiter',
monthNames: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ],
monthNamesShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ],
dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
dayNamesShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'],
dayNamesMin: ['S', 'M', 'D', 'M ', 'D', 'F ', 'S'],
weekHeader: 'Woche',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix:'',
timeOnlyTitle: 'Nur Zeit',
timeText: 'Zeit',
hourText: 'Stunde',
minuteText: 'Minute',
secondText: 'Sekunde',
currentText: 'Aktuelles Datum',
ampm: false,
month: 'Monat',
week: 'Woche',
day: 'Tag',
allDayText: 'Ganzer Tag'
};
</script>
</h:head>
<h:body>
<p:datePicker view="month" locale="de"
pattern="MMMM yyyy" value="#{monthOverviewController.currentDate}">
</p:datePicker>
</h:body>
</html>
And sure enough, the same uncaught exception: Unknown name at position 0 occurs, which most likely originates from here. I have tested this with a couple of the translations provided on PrimeFaces' Wiki, all with the same result.
The problem lies within the _setInitValues function in the datePicker component:
_setInitValues: function () {
var parsedDefaultDate = this.parseValue(this.options.defaultDate);
this.value = parsedDefaultDate;
this.viewDate = this.options.viewDate ?
this.parseValue(this.options.viewDate)
:
((((this.isMultipleSelection() || this.isRangeSelection()) && parsedDefaultDate instanceof Array) ? parsedDefaultDate[0] : parsedDefaultDate) || this.parseValue(new Date()));
this.options.minDate = this.parseOptionValue(this.options.minDate);
this.options.maxDate = this.parseOptionValue(this.options.maxDate);
this.ticksTo1970 = (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000);
if (this.options.yearRange === null && this.options.yearNavigator) {
var viewYear = this.viewDate.getFullYear();
this.options.yearRange = (viewYear - 10) + ':' + (viewYear + 10);
}
if (this.options.userLocale && typeof this.options.userLocale === 'object') {
$.extend(this.options.locale, this.options.userLocale);
}
if (this.options.disabledDates) {
for (var i = 0; i < this.options.disabledDates.length; i++) {
this.options.disabledDates[i] = this.parseOptionValue(this.options.disabledDates[i]);
}
}
},
The defaultDate is the value of the bean property (currentDate) formatted using the components pattern and locale, resulting in our case in the German string. Now the very first instruction in _setInitialValues attempts to parse this date. However, the custom translation has not yet been loaded (see $.extend(this.options.locale, this.options.userLocale); and thus the month name (in most cases) cannot be resolved. This is in my opinion an error in the component and the best/most stable solution should be waiting for an appropriate fix. An intermediate solution (keep in mind this is just a hack at best) would be to copy the JavaScript file and move the loading of the translation up above the first parse:
_setInitValues: function () {
if (this.options.userLocale && typeof this.options.userLocale === 'object') {
$.extend(this.options.locale, this.options.userLocale);
}
var parsedDefaultDate = this.parseValue(this.options.defaultDate);
No legends appears in my bar and pie charts.
I tried several arguments for setLegendPlacement and setLegendPosition methods but it was without results.
Where I went wrong ?
This is my config for the bar chart :
BarChartModel model = new BarChartModel();
model.setZoom(true);
model.setLegendPlacement(LegendPlacement.INSIDE);
model.setLegendPosition("ne");
model.setAnimate(true);
model.setMouseoverHighlight(true);
model.setShowPointLabels(true);
ChartSeries myChartSeries = new ChartSeries();
bank.setLabel("myChatSeries");
for (String key : datas.keys()) {
bank.set(key, datas.get(key));
}
model.addSeries(myChartSeries);
Axis yAxis = model.getAxis(AxisType.Y);
yAxis.setLabel(status.name());
yAxis.setMin(0);
yAxis.setMax(maxCount+1);
yAxis.setTickInterval("2");
Axis xAxis = model.getAxis(AxisType.X);
xAxis.setTickAngle(-20);
This is my config for the pie chart :
PieChartModel model = new PieChartModel();
model.setLegendPosition("ne");
model.setLegendPlacement(LegendPlacement.INSIDE);
model.setTitle("Informations général");
model.setMouseoverHighlight(true);
model.setShowDataLabels(true);
model.set("type1", 3);
model.set("type2", 6);
model.set("type3", 8);
My stack : java 8, jsf 2.1.28, primefaces 5.1, primefaces-themes 1.0.10
Resolved by setting the property legend.show to true on a hook before drawing :
$.jqplot.preDrawHooks.push(function () {
this.legend.show = true;
});
A little trashy hack somehow, Primefaces 5.1 doesn't seem to set this property by default.
I have problem to set the zoom on a chart with "date time" axis. I made a simulation comparing the chart of Primefaces with native jqplot. With jqplot native works fine, but with primefaces not.
It seems to me an bug in the calculation of the viewport.
My JSF page:
<p:chart type="line" model="#{chartController.model}" id="chart" style="height: 400px" />
My managed bean:
#Named(value = "chartController")
#ViewScoped
public class ChartController implements Serializable {
private LineChartModel model;
public ChartController() {
}
#PostConstruct
public void init() {
long[][] lines = {{1334856823000l, 2}, {1334856853000l, 1}, {1334856883000l, 0}, {1334856913000l, 4}, {1334856914000l, 13},
{1334856943000l, 16}, {1334856973000l, 23}, {1334857003000l, 24}, {1334857033000l, 36}, {1334857063000l, 14}, {1334857093000l, 1}};
model = new LineChartModel();
model.setTitle("Primefaces Chart");
model.setZoom(true);
LineChartSeries series = new LineChartSeries();
for (long[] line : lines) {
series.set(line[0], line[1]);
}
DateAxis xaxis = new DateAxis();
xaxis.setTickFormat("%e/%b %H:%M");
xaxis.setTickAngle(-30);
xaxis.setMin(1334856823000l); // if not set this, chart not work
model.getAxes().put(AxisType.X, xaxis);
Axis yaxis = new LinearAxis();
yaxis.setMin(0);
model.getAxes().put(AxisType.Y, yaxis);
model.addSeries(series);
}
public LineChartModel getModel() {
return model;
}
}
My jqplot native code:
<div id="chart" style="height: 400px"></div>
<script>
$(document).ready(function () {
$.jqplot.config.enablePlugins = true;
var lines = [[1334856823000, 2], [1334856853000, 1], [1334856883000, 0], [1334856913000, 4], [1334856914000, 13],
[1334856943000, 16], [1334856973000, 23], [1334857003000, 24], [1334857033000, 36], [1334857063000, 14], [1334857093000, 1]];
$.jqplot('chart', [lines], {
title: "Jqplot Native",
axes: {
xaxis: {
renderer: $.jqplot.DateAxisRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: {
formatString: '%e/%b %H:%M',
angle: -30
}
},
yaxis: {
renderer: $.jqplot.LinearAxisRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
min: 0
}
},
cursor: {zoom: true}
});
});
</script>
The sample project is: https://github.com/douglasjunior/PrimefacesChartZoomTest
Primefaces: 5.3
Java EE: 7.0
GlassFish: 4.1.1
I am researching a few days ago. What am I doing wrong? It's a limitation?
# UPDATE 2016-08-03:
Same problem with Primefaces 6.0
# UPDATE 2016-09-01:
Based on #lalitha ramakrishnan answer I make it work just including the jqplot.dateAxisRenderer.min.js file in xhtml page. For some bug, the Primefaces dont includes this automatically.
But now the lines was always smooth=true. I tried configure by lineSeries.setSmoothLine(false) and with extender, but not worked.
Bug report: https://github.com/primefaces/primefaces/issues/1736
You can specify xaxis renderer of your primefaces chart model to be $.jqplot.DateAxisRenderer in the javascript.
The following script will be invoked when model's extender property is set to "ext".
model.setExtender("ext");
function ext() {
//this = chart widget instance
//this.cfg = options
this.cfg.axes = {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
tickRenderer : $.jqplot.CanvasAxisTickRenderer,
tickOptions : {
formatString : "%b %#d, %H:%M:%S",
angle : -30
},
drawMajorGridlines : false
},
yaxis : {
// Other Options for Y Axis
}
};
}
See Also
How to solve primefaces xAxis overlapping Issue?
EDIT:
You need to include jqplot.dateAxisRenderer.min.js file in your xhtml page.
I trying to make custom button and few other elements styled as KDE 5 'Breeze' theme. I considered to make separated palette object (called BreezePalette.qml that contains a lot of readonly color properties) for all of this widgets (because I do not want them to be styled in any other way, that's thy they called Breeze). The main concept is to make palette as property of widgets and create one palette in main.qml where I can change property theme to light or dark. It looks to me rational, because I planning only include all subset of .qml files into project, without any other additional files to Qt itself (that making it portable and easy to deploy). Here is that I have, can someone let me know how can I forward palete as a property?
main.qml
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.1
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
menuBar: MenuBar{
Menu{
title: "File"
MenuItem{
text: "Exit"
onTriggered: Qt.quit()
}
}
}
BreezeButton{
x: 106
y: 82
palette: brPalette
onClicked: {
Qt.quit()
}
caption: "Button"
}
BreezePalette{
id: brPalette
theme: "light"
}
}
BreezePalette.qml
import QtQuick 2.2
QtObject {
id: palette
property string theme: "light"
readonly property color base: if (theme == "light"){
"#eff0f1"
} else if (theme == "dark"){
"#31363b"
}
readonly property color focus: "#3daee9"
readonly property color buttonText: if (theme == "light"){
"#31363b"
} else if (theme == "dark"){
"#eff0f1"
}
}
BreezeButton.qml
import QtQuick 2.2
import QtQuick.Window 2.0
import QtQuick.Layouts 1.1
Item {
id: root
implicitHeight: bodyText.font.pixelSize + 32
implicitWidth: bodyText.width + 32
property string caption: "Button"
property string iconSource
property int fontSize: 18
//I've tried to throw BreezePalette as a property to BreezeButton, but looks like my skills ended there (I have no any experience with js or qml before. I started learn it only few weeks)
property BreezePalette palette
signal clicked
Rectangle {
id: body
border {
width: 1
color: "#808e8e"
}
anchors{
fill: parent
}
gradient: Gradient {
id: bodyGradient
GradientStop { position: 0.4; color: "#4c4c4c" }
GradientStop { position: 0.9; color: "#31363b" }
}
MouseArea{
id: bodyMouseArea
z: bodyText.z + 1
anchors {
fill: parent
}
hoverEnabled: true
onEntered: {
body.border.color = "#3daee9"
}
onExited: {
body.border.color = "#7f8c8d"
}
onPressed: {
body.color = "#3daee9" // this one works, but I need to switching theme as you can see n `BreezePalette.qml`
//This one not working as expected, but seeing my properties as I need
//body.color = palette.focus
body.gradient = null
}
onReleased: {
body.color = "#4d4d4d"
body.gradient = bodyGradient
}
onClicked: {
root.clicked()
}
}
Text {
id: bodyText
anchors {
verticalCenter: body.verticalCenter
horizontalCenter: body.horizontalCenter
}
font.pointSize: fontSize
color: "#fcfcfc"
text: caption
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
}
Since stackexchange designed for sharing knowledge (or maybe even for ask for something you don't know well) I see it's rational to post it there because I need knowledge of experts. If you have any other point of view regarding this question I'll be glad to hear that. Appreciated any help.
Thanks
Svyatoslav
UPDATE:
Just found an answer, this code snippet working as well
property BreezePalette palette: BreezePalette
So, my second answer is - is that good to user this method? It's provide me thing I need, exactly as was expected.
Quite a late answer, but there is a module to have breeze theme.
qml-module-qtquick-controls-styles-breeze
How can i make AUI-datepicker to pop up on the focus of element. cuurrently it only pop up on click of element.
Here is code
Script:
YUI().use('aui-datepicker',
function(Y) {
new Y.DatePicker(
{
trigger: '.date-selector',
popover: {
zIndex: 1
},
}
);
}
);
and Tag
<aui:input id="startDate" name="startDate" cssClass="date-selector" label="startDate">
and one more thing how can i range date?
Try this something like this:
<aui:input name="taskStartDate" autocomplete="off" cssClass='font-size' id="taskStartDate" onFocus="onClickOfStartDate();" required="true" inlineLabel="true" label=" "/>
<aui:script>
function setactualStartDate(){
AUI().use('aui-datepicker', function(A) {
var simpleDatepicker1 = new A.DatePicker({
trigger: '#<portlet:namespace />taskActualStartDate',
mask: '%Y-%m-%d',
calendar: {
dateFormat: '%Y-%m-%d',
},
}).render('#<portlet:namespace />taskactualStartDatePicker');
});
}
function onClickOfStartDate(){
setStartDate();
}
</aui:script>
The Datepicker popup is handled by DatePickerPopover class of aui-datepicker module. There is show() method in datepicker class to open popup.
<input id="startDate" name="startDate" class="date-selector" onfocus="openDatePicker();">
<script>
var datePicker;
YUI().use('aui-base','aui-datepicker', function(Y) {
datePicker = new Y.DatePicker({
trigger: '#startDate',
popover: {
zIndex: 10,
},
calendar: {
maximumDate: new Date()
}
});
});
function openDatePicker() {
datePicker.getPopover().show();
}
</script>
Date can be ranged by adding maximumDate and minimumDate attribute.