i m working on a ZK project , using ZK MVC approach. what i did try to do is to initalize "a panel" after doAfterCompose a div , but the problem is that i got a "java.lang.NullPointerException"
and those are a simple exemple of what i did try to do . My view "mypage.zul"
<zk>
<borderlayout>
<west width="140px" splittable="true" collapsible="true" maxsize="140">
<div align="center" apply="dashboard.display">
<label value="WorkLoad"></label><checkbox></checkbox>
</div>
</west>
<center autoscroll="true" >
<div>
<portallayout id="portalLayout" maximizedMode="whole" width="100%" >
<portalchildren >
<panel id="panelworkload" >
<panelchildren>
<div width="100%" >
<charts id="workloadDay" type="column" />
</div>
</panelchildren>
</panel>
</portalchildren>
</portallayout>
</div>
</center>
</borderlayout>
</zk>
My conroler : "display"
public class display extends SelectorComposer<Div>{
#Wire
Checkbox objectif_checkbox;
#Wire
Panel panelworkload;
public void doAfterCompose(Div comp) throws Exception {
super.doAfterCompose(comp);
panelworkload.setTitle("hello workload");
}
}
and this is the exception that i got
java.lang.NullPointerException dashboard.display.doAfterCompose(display.java:24)
dashboard.display.doAfterCompose(display.java:1)
org.zkoss.zk.ui.impl.UiEngineImpl.doAfterCompose(UiEngineImpl.java:578)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild0(UiEngineImpl.java:880)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreateChild(UiEngineImpl.java:826)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreate0(UiEngineImpl.java:735)
org.zkoss.zk.ui.impl.UiEngineImpl.execCreate(UiEngineImpl.java:699)
what i have throught of it so far is that the div has been composed before the portallayout , that why the server cant reconize portallayout when div is created
can anyone help me pls ? i m kinda stuck here ...and thank you
The setTitle method for zk framework's Panel object is the following:
public void setTitle(String title) {
if (title == null)
title = "";
if (!Objects.equals(_title, title)) {
_title = title;
smartUpdate("title", _title);
}
}
There is nothing in there that would throw a NullPointerException. (And the stack trace would indicate it)
Therefore, the panelworkload should currently be null in the doAfterCompose(comp) object.
I would recommend you read through several of the answers on What is a NullPointerException, and how do I fix it? , although they do not do a great job of explaining how to diagnose a NullPointerException error, nor how to follow a stack trace.
Panel Source Reference
Related
Okay, I a wet-behind-the-ears newcomer to Spring and Thymleaf. I'm trying to do something so simple it should be a no-brainer. But I can't get it to work. The simple question is - how do you show a list of strings in an web page?
I have the following model
import java.util.List;
public class TestModel {
private List<String> list = null;
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<String> getList() { return list; }
public void setList(final List<String> list) {
this.list = list;
}
}
My web page contains the following:
<div th:if="${greeting.list != null}">
<h1>Result</h1>
<ul>
<th:block th:object="${greeting}" th:each="item : ${list}">
<li th:text="${item.name}">Item description here...</li>
</th:block>
</ul>
</div>
I added the ".name" to "item" only because I found a couple of examples where they had a list of strings and did something similar. But they had the ".name" on the object.
But it still doesn't work. The unordered list ends up empty. I.e. There isn't any list items inside the unordered tags.
What am I doing wrong? Pointers gladly accepted.
Since there's no example of filling model I supposed you put some strings into instance of TestModel's list field like this.
TestModel greeting= new TestModel();
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
model.addAttribute("greeting", greeting);
Then there are more errors in your Thymeleaf template example.
If you are using object selection through th:object you must at first place use asterix * to access object properties. Asterisk syntax evaluates expressions on selected objects instead of context variables map.
Object selection affects only children nodes in DOM.
In your example you want iterate over list of strings (List<String>) but you want to access property name which in fact don't exists on Java String object.
You must fix your Thymeleaf template in one way - see examples.
No object selection at all
<div th:if="${greeting.list != null}">
<h1>Result</h1>
<ul>
<li th:each="item : ${greeting.list}" th:text="${item}">Item description here...</li>
</ul>
</div>
Proper object selection
<div th:if="${greeting.list != null}">
<h1>Result</h1>
<ul>
<th:block th:object="${greeting}">
<li th:each="item : *{list}" th:text="${item}">Item description here...</li>
</th:block>
</ul>
</div>
<table th:object="${userList}" id="userTable" border="1">
<tr th:each="user :${userList}">
<td th:text="${user.getName()}"></td>
<td th:text="${user.getEmail()}"></td>
</tr>
</table>
Another example using table and Object. Might be useful to someone else.
In thymeleaf, if you are looking to create in a template a list of strings and compare it with a string, you can use the following structure.
th:if="${#lists.contains({'RO', 'UK', 'DE', 'BE'}, #session.getAttribute('country'))}"
Hello again JSF Gurus.
I am looking for help on custom renderers and ajax handlers. Our project cannot use the normal radio button and check box renderers as they render in tables and this is against our corporate standards. Neither can we use third party component libraries.
We have a custom renderer that we have used in a few projects now that works fine. However, on this particular project, I need to render the ajax click handler for some radio buttons. Following the advice in the answer to this question I have added the call to RenderKitUtils.renderSelectOnclick(); and whilst it appears to render the same javaScript as the standard renderer, and indeed, firebug network panel shows the outgoing request, my value change listener is not being fired and I am looking for help as to why (it fires perfectly well with the standard renderer)
Some code:
Firstly, the creation of the ajax handler (the radio button is created programatically)
AjaxBehavior valueChangeAction = (AjaxBehavior) FacesUtils.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
valueChangeAction.addAjaxBehaviorListener(new ProbeQuestionListener(currentQuestion, "probeDiv" + questionNumber,
probeDiv));
selectUI.addClientBehavior("valueChange", valueChangeAction);
valueChangeAction.setRender(Collections.singletonList("probeDiv" + questionNumber));
Wih the standard renderer, this produces:
<table id="answer_1" class="marginLeft1a">
<tbody>
<tr>
<td>
<input id="answer_1:0" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="0" name="answer_1">
<label for="answer_1:0"> Yes</label>
</td><td>
<input id="answer_1:1" type="radio" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" value="1" name="answer_1">
<label for="answer_1:1"> No</label>
</td>
</tr>
and all is well. The ajax request is posted and my server side listener gets fired.
The relevant parts of my custom renderer:
public void encodeEnd(final FacesContext p_context, final UIComponent p_component) throws IOException {
/* set up convenience fields */
context = p_context;
component = p_component;
componentId = component.getClientId(context);
// rendering divs etc omitted.
while (iterator.hasNext()) {
final UIComponent childComponent = iterator.next();
// irrelevant code omited
if ("javax.faces.SelectItem".equals(childComponent.getFamily())) {
renderSelectItem(idIndex, childComponent);
idIndex++;
}
}
}
private void renderSelectItem(final int p_idIndex, final UIComponent p_childComponent) throws IOException {
// unrelated code omitted
writer.startElement("input", component);
writer.writeAttribute("type", getInputType(), null);
writer.writeAttribute("id", p_childComponentId, "id");
writer.writeAttribute("name", componentId, "clientId");
RenderKitUtils.renderSelectOnclick(context, component, false);
writer.endElement("input");
// unrelated code omitted
}
Update: The decode method in the base class for my renderer is:
#Override
public void decode(final FacesContext p_context, final UIComponent p_component) {
final Map<String, String> valuesMap = p_context.getExternalContext().getRequestParameterMap();
final UIInput input = (UIInput) p_component; // NOSONAR
final Object value = valuesMap.get(input.getClientId(p_context));
// System.out.println("radio button decode: found " + value);
input.setSubmittedValue(value);
}
This renders as :
<span class="marginLeft1a" id="answer_1">
<label for="answer_1:0">
<input type="radio" value="0" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:0">
Yes
</label>
<label for="answer_1:1">
<input type="radio" value="1" onclick="mojarra.ab(this,event,'valueChange',0,'probeDiv2')" name="answer_1" id="answer_1:1">
No
</label>
</span>
As you can see, the javaScript click handler is identical, as are the name and id attribute values of the input tags. Although this triggers the Ajax request, the listener is not fired server side as it is with the first version.
Any ideas ?
The decode() method of the Renderer (or UIComponent if there's no renderer) is supposed to decode the ajax request based on javax.faces.behavior.event request parameter and trigger ClientBehavior#decode() on the matching client behaviors.
Basically, the logic is as follows:
Map<String, List<ClientBehavior>> behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
if (!behaviors.isEmpty()) {
Map<String, String> params = context.getExternalContext().getRequestParameterMap();
String behaviorEvent = params.get("javax.faces.behavior.event");
if (behaviorEvent != null) {
List<ClientBehavior> behaviorsForEvent = behaviors.get(behaviorEvent);
if (behaviorsForEvent != null && !behaviorsForEvent.isEmpty()) {
String behaviorSource = params.get("javax.faces.source");
if (isBehaviorSource(context, behaviorSource, component.getClientId())) {
for (ClientBehavior behavior: behaviorsForEvent) {
behavior.decode(context, component);
}
}
}
}
}
Given the fact that you're using RenderKitUtils and the generated HTML output contains mojarra.ab(), I'll assume that you're using Mojarra. In that case, it's perhaps wiser to extend your custom renderer from RadioRenderer instead which has all this logic already implemented in HtmlBasicRenderer and SelectManyCheckboxListRenderer so that you don't need to reinvent the wheel.
Ok, so I have spent way too much time on this already, but it is really bugging me! So, I have a page with a bunch of tabs on it. To keep things manageable, I want to turn each of those tabs into their own .zul page with their own ViewModel. I have implemented an EventQueue in order to pass the main object (the Tournament object) from the main page to all of the sup-pages.
The problem is, whenever the event is fired and it updates the Tournament object, the page will not refresh its data even though it has changed in the ViewModel. I have tried adding the #NotifyChange annotation with no success. While debugging, I have eliminated the extra .zul. See code below.
tournamentsTab.zul:
<tabpanel apply="org.zkoss.bind.BindComposer" viewModel="#id('bcvm') #init('com.cannon.tnt.trm.mvvm.BeltClassViewModel')">
<vlayout vflex="1">
<grid model="#load(bcvm.tournament.beltClasses)" emptyMessage="No belt ranks created yet." vflex="1">
<columns>
<column label="Name" align="center" width="200px"/>
<column label="Description" align="center"/>
<column label="Delete" align="center" width="120px"/>
</columns>
<template name="model">
<row>
<textbox value="#bind(each.name)" width="95%" onChanging="#command('setStateEditing')"/>
<textbox value="#bind(each.description)" width="95%"
onChanging="#command('setStateEditing')"/>
<button label="Delete" onClick=""/>
</row>
</template>
</grid>
</vlayout>
<!--<include src="beltClassPanel.zul"/>-->
</tabpanel>
BeltClassViewModel.java:
public class BeltClassViewModel {
private EventQueue eq;
private Tournament tournament;
#Init
public void init() {
eq = EventQueues.lookup("tournamentQueue");
eq.subscribe(new EventListener() {
public void onEvent(Event event) throws Exception {
setTournament((Tournament) event.getData());
}
});
}
public Tournament getTournament() {
return tournament;
}
#NotifyChange("{tournament}")
public void setTournament(Tournament selectedTournament) {
this.tournament = selectedTournament;
}
}
As I mentioned, the EventQueue part is working perfectly. The event is being fired and then received by the listener who makes the call to set the tournament object on the view model. The problem is, the referenced tournament object is not being updated in the UI. I have put a break point in the getTournament() call and verified that the ONLY time that gets called is when the page first loads.
PLEASE HELP!!! I know that usually these things are just something stupid I'm overlooking. Please prove my idiocy! :)
I suppose that you need to post notification manually, you can try something like this:
public void onEvent(Event event) throws Exception {
setTournament((Tournament) event.getData());
BindUtils.postNotifyChange(null, null, BeltClassViewModel.this, "tournament");
}
Eugene found the problem. A simple mistake. I had #NotifyChange("{tournament}") when it should have been #NotifyChange({"tournament"}). Thanks, Eugene and Stack Overflow!
I'm trying to implement an AJAXfied Wicket list view. On my research I stumbled upon the code on this site and modified it a bit.
The model is not updated properly. So whenever a value is entered in a text field, it is forgotten if the AJAX submit link is invoked (the text field is empty). Why does this happen? I don't see any issue with this code. Wicket version is 1.5.2.
Here is the Java code:
// Initialization of form
...
// List all rows
ArrayList<String> rows = new ArrayList<String>(2);
rows.add(new String());
rows.add(new String());
final ListView<String> lv = new ListView<String>("rows", rows) {
#Override
protected void populateItem(ListItem<String> item) {
int index = item.getIndex() + 1;
item.add(new Label("index", index + "."));
TextField<String> text = new TextField<String>("text", item.getModel());
item.add(text);
}
};
rowPanel.add(lv);
AjaxSubmitLink addLink = new AjaxSubmitLink("addRow", form) {
#Override
protected void onError(AjaxRequestTarget target, Form<?> form) {
if (target != null) target.add(rowPanel);
}
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
lv.getModelObject().add(new String());
if (target != null) target.add(rowPanel);
}
};
addLink.setDefaultFormProcessing(false);
rowPanel.add(addLink);
...
And here is the mark up:
<div wicket:id="rowPanel">
<span wicket:id="rows">
<span wicket:id="index">1.</span>
<input type="text" wicket:id="text"/>
</span>
Add row
</div>
My previous comment as anwser:
You may need to call setReuseItems(true) on the listview.
Another way of ajaxifying a listview can be found at the Wicket in Action blog
Your example would work fine if you hadn't added the following line:
addLink.setDefaultFormProcessing(false);
Your link doesnt process the form like he would normally do (update models etc, see IFormSubmitter)
You could use nested Forms to updated only the area you need and set defaultFormProcessing back to true.
Like:
<form wicket:id="form">
(...) <!-- (other form elements you dont want to get updated -->
<form wicket:id="repeaterForm"> <!-- form for your repeater textfields-->
<div wicket:id="refreshDiv">
<input type="textfield" wicket:id="repeaterText" />
</div>
<a wicket:id="addMoreLink>add more</a>
</form>
</form>
Wicket will make sure you don't actually have nested forms within your markup (it will replace the nested form with a div) because it ain't valid HTML. But it would work as if the forms are nested nevertheless.
You have to use the model from the target like this:
IModel model = target.getModel();
Then cast to the listView. I don't know if this works, but I have some similar code here.
Ok this is probably really simple but I have been staring at it for too long now.
I have an AJAX AsyncFileUpload control that when a file is selected I want the Image next to it to change. I tried it in Javascript and it did nothing, i have since tried it server-side and still nothing. here is the client side.
<asp:UpdatePanel runat="server" ID="upnlConfidential">
<ContentTemplate>
<td>
<asp:AsyncFileUpload ID="_flupCV" runat="server" OnUploadedComplete="AdminFileUpload" />
</td>
<td>
<asp:Image ID="imgCV" runat="server" Height="25px" Width="25px" ImageUrl="~/Images/Exclamation.png"/>
</td>
</ContentTemplate>
</asp:UpdatePanel>
and here is the server side
protected void AdminFileUpload(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
AjaxControlToolkit.AsyncFileUpload upload = (AjaxControlToolkit.AsyncFileUpload)sender;
if (upload.PostedFile != null)
{
switch (upload.ID)
{
case "_flupCV":
ImageCheckMark(imgCV);
break;
//etc...
}
}
}
private void ImageCheckMark(Image image)
{
image.Visible = true;
image.ImageUrl = "~/Images/CheckMark.png";
}
When the server side is called it sets the URL just fine but then nothing happens to the image, when I call the code again the URL is still the previous Exclamation image. its almost like its forgotten.
Can anybody help me on this please. Thanks in advance to all who contribute!
Use the OnClientUploadComplete event and jQuery :>