Primefaces timeline onchanged executes but does not call method on bean - spring

I am attempting to add primefaces to an existing Spring/JSF (myfaces) project. I have the actual timeline component working (or at least loading with the correct data), but the event listeners don't seem to work correctly. I have tried a number of configurations but can't seem to resolve this issue.
<p:timeline id="timeline1"
value="#{timelineView.getModel(searchFacade.dataModel)}"
editable="true" eventMargin="10" eventMarginAxis="0"
start="#{timelineView.start}"
end="#{timelineView.end}"
showNavigation="true" showButtonNew="true"
axisOnTop="true" stackEvents="false"
oncomplete="styleEvents();">
<p:ajax event="changed" listener="#{timelineView.onEdit()}" oncomplete="restyleTimeline()" />
</p:timeline>
In the above code the changed event is triggered and there is an AJAX call made. In the network pane of the browser I can see that the AJAX call is always to the URL of the current page (so like /mypage.jsf?conversationCode=a - I'm also using Apache Orchestra obviously)
The actual form data being sent for the changed event looks like this:
javax.faces.partial.ajax:true
javax.faces.source:timeline1
javax.faces.partial.execute:timeline1
javax.faces.behavior.event:changed
javax.faces.partial.event:changed
timeline1_eventIdx:0
timeline1_startDate:1498881600000
timeline1_endDate:1510894800000
timeline1_group:<div class='timeline-group'><div class='timeline-row timeline-row-group'>Group One/div><div class='timeline-row timeline-row-sub'>Group One subtitle</div><div class='timeline-row timeline-row-details'>Group One details</div></div>
mainForm:j_id_mt_SUBMIT:1
javax.faces.ViewState: Big hash as usual
The bizarrely long group name is because I am formatting the output group names into a more detailed title for the row btw.
The bean in the back (imports and package omitted):
public class TimelineView<T> implements Serializable {
private static final long serialVersionUID = 1L;
TimelineView<T> timelineView;
public TimelineModel getModel() {
return timelineView.getModel();
}
public TimelineModel getModel(ListDataModel<? extends Row<T>> results) {
return timelineView.getModel(results);
}
public void setTimelineView(TimelineView<T> timelineView) {
this.timelineView = timelineView;
}
public Date getStart() {
return timelineView.getStart();
}
public Date getEnd() {
return timelineView.getEnd();
}
public void onEdit(TimelineModificationEvent e) {
timelineView.onEdit(e);
}
public void onSelect(TimelineSelectEvent e) {
timelineView.onSelect(e);
}
}
The functionality and code inside these methods doesn't matter because when I set a breakpoint I can see that the onEdit method is never called and neither was the onSelect method when I had a select event in the timeline.
Since I have Spring handling all beans, my configuration was just this, located in the ApplicationContext.xml file:
<bean id="timelineView" class="com.mycompany.projectone.view.timeline.TimelineView" />
I have tried adding a form around the timeline, which made no difference, and have also tried adding process=":form_id", which caused the error "Cannot find component for expression ":form_id"".
As an alternative that would also suit my needs, does anyone know how to send primefaces events to a javascript function to be handled? For example, if the user moves the start and end points of the item in the timeline I would like to update the displayed start and end dates.
I would also like to change or intercept the delete behavior and modify what occurs when the delete link is clicked.
Any help would be hugely appreciated. Thanks.
EDIT
The suggested potential duplicate does not address the symptoms nor the actual solution - see answer below.

Okay, so the answer turns out to be that the Primfaces timeline component must have a widgetVar set in order for the p:ajax and pe:javascript calls to work. Incredibly simple solution but so infuriatingly difficult to find.

Related

What determines which event will run first?

I've created a test plugin as a science project to try and determine if 2 of the same event are called at the same time, which will be executed first.
public class TestPlugin extends JavaPlugin implements Listener {
public void onEnable() {
Bukkit.getPluginManager().registerEvents(this, this);
}
#EventHandler(priority = EventPriority.HIGHEST)
public void event1(PlayerInteractEvent e) {
System.out.println("event 1");
}
#EventHandler(priority = EventPriority.HIGHEST)
public void event2(PlayerInteractEvent e) {
System.out.println("event 2");
}
}
the output that the plugin produced are
[17:01:51 INFO]: event 2
[17:01:51 INFO]: event 1
if event1 is listed first in the class file, why is it that event2 is fired first?
This is very hard to determine. Since registerEvents leads to the function createRegisteredListeners of https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
In there they use a HashSet to store the Methods of your Listener-class. So it is the pseudo random hash they give each method to store it that determines which event gets registered first.
I'm not sure but I guess that each and every time you register the events it's kind of random which gets registered first. This is why you should use different eventPriorities in order to determine which is called first.
If you really want to get deeper you have to tear apart the function createRegisteredListeners of the github-link I posted earlier in this reply. But I guess it woll never be totally certain because of the HashSet used in line 235 of the JavaPluginLoader.java:
methods = new HashSet<Method>(publicMethods.length, Float.MAX_VALUE);
As Methods are added to the set it never is certain in which position in the RAM they end up.
I hope I could help you with this post even though it doesn't really answer your original question.

How can I make changes in the GUI with background work in JavaFX?

From all the searching and reading it’s clear that I need to call Platform.runLater() to change the GUI. It also appears I need to use the Runnable interface. Perhaps I should also use Tasks?
But I can’t figure out how exactly I should use them. Plus, I’m not sure which class I should put them in. I’m super new to JavaFX.
My trial JavaFX project has only a Label and a TextField. Label contains a question and the TextField is for answering. Simple enough.
I ran into the problem here:
The answer checking method is in a separate class. I can’t figure out how I can access the components of the GUI/FXML and change them. The methods in the other classes are static while the components of the GUI/FXML are non-static.
Since my actual project would have many quizzes, I'm keen on using separate classes for checking answers.
Only 3 small classes are relevant here:
The “Launcher” class which contains the main method.
The “ViewController” class for the FXML file as well as some methods.
The “Ans” class which has a method to check the answer input.
In which class should I put the Platform.runLater()? And how would the code be?
I’ll just share the code of the “Ans” and the “ViewController” classes.
Ans (The background works are supposed to happen in this file. In the comments, I've mentioned what I want to do but unable to do. For example, I want to set the Label text from there but I can't. Since I have no idea how to do it I've just put a System.out.Println there. In the comments next to it, I've mentioned what I actually want to do.)
package com.dan.ans;
import com.dan.qn.Qn;
import com.dan.view.ViewController;
public class Ans {
public static void checkAns() {
// Checks if the ans is correct.
if (ViewController.getTextFieldInput().equalsIgnoreCase(Qn.getAns())) {
System.out.println("Correct!"); // Here I want the label to say 'Correct!' rather than it be print out in the console.
Qn.setQuestion(); // This gets the next question from the database. But again, I don't know how to make the changes show on the screen. (In the actual code I'd have a separate Label for each of these things)
} else { // Runs if it's not correct.
System.out.println("Incorrect!"); // Here I want the label to say 'Incorrect' rather than it be print out in the console.
}
}
}
ViewController
package com.dan.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import com.dan.ans.Ans;
import com.dan.qn.Qn;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class ViewController implements Initializable {
private static String textFieldInput; // I don't know how to access the typed info in the textField from another class. So I store it here and get it from it.
// This is the getter I use for it. (See above)
public static String getTextFieldInput() {
return textFieldInput;
}
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
Qn.setQuestion(); // This method is in the Qn class. It retrieves data from the db file and keeps them in variables.
label.setText(Qn.getQn()); // This sets the label's text using the retrieved data. So you see the first question when the program opens.
}
// Event Listener on TextField[#textField].onAction
public void enter(ActionEvent event) throws IOException {
textFieldInput = textField.getText(); // Stores the typed info in the variable to be accessed from elsewhere.
Ans.checkAns(); // Runs the checkAns to check if the typed answer is correct or not.
}
}
The “Launcher” method just looks like any method with a main class. So I haven’t shared its code here.
Could someone please show me how I can update the components in the GUI from other classes such as “Ans”? I’m pretty sure I should use Platform.runLater() and Runnable. Also may be Tasks. I’ve seen several examples but it’s not clear how I can use it this context.
Thanks a lot in advance! :)
It's not really particularly clear what the issue is here. The natural (to me, anyway) approach would simply be to make the checkAnswer(...) method a method that simply "does what it says on the box", i.e. that takes an answer as a parameter, checks it, and returns a value to the caller indicating if it is correct.
That way you can also avoid all the ugly static hacks.
public class Ans {
public boolean checkAns(String answer) {
// not really sure what Qn is here, but you can also clean this up and
// get rid of the static methods
if (answer.equalsIgnoreCase(Qn.getAns()) {
// not sure if this really belongs here?
Qn.setQuestion(); // really takes no parameters? Sets it to what, then?
return true ;
} else {
return false ;
}
}
}
And then in your controller, you can just do
public class ViewController implements Initializable {
private Ans ans ;
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
ans = new Ans();
// ...
}
// ...
public void enter(ActionEvent event) {
if (ans.checkAns(textField.getText())) {
// update UI to show answer was correct, etc
} else {
// update UI to show answer was incorrect...
}
}
// ...
}
Note how this allows you to maintain proper separation of concerns: the Ans class doesn't need to know anything at all about the UI (which it should not know about at all), and all the UI-specific code is encapsulated in the controller class where it belongs.
It's not really clear why you are asking about Platform.runLater(...) and using Task, since none of the code you posted appears to involve any background threads (i.e. none of this code seems to take an appreciable amount of time to run). If, for example, the checkAns(...) method was doing some remote lookup and did take time to run, you would execute it in a Task and update the UI from the task's onSucceeded handler. See, e.g. Using threads to make database requests. Your question really seems to be more about basic OO design and how to define the relationships between different objects, though; I don't think you are actually asking about threading at all.

rxBindings - How to know what consumer type should be when debouncing click events?

using rxBindings im trying to slow down a click event but i would like to know what the parameter is need.
For example, here is a call i am doing on a imageview. So ImageView v;
RxView.clicks(v)
.throttleFirst(400, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe(new Consumer<Object>() {
#Override
public void accept(#io.reactivex.annotations.NonNull Object v) throws Exception {
showBottomSheet(getAdapterPosition());
}
});
but im im not sure what the parameter in accept should be ?
I was expecting i would get the view here but when i try changing the type to View i get an error of no such method.
If you look at the source code of the Observable generate using RxView.clicks(), you will see that when the click happens, the following code is triggered:
observer.onNext(Notification.INSTANCE);
that is defined in the library, as:
public enum Notification {
INSTANCE
}
It is just a convenient way for indicating that the event happened, it doesn't carry any extra information.

GWT: React to a click on a SafeHTML in a cell of a CellTable?

I am using a CellTable to display results of a query and I need these results to be shown as (html) links. I would like to react to a click on these links. So far, I had implemented it like this:
// ClickHandler on CellTable
cellTable.addCellPreviewHandler(new Handler<OperationalItemMultipleSearchRowData>() {
#Override
public void onCellPreview(CellPreviewEvent<OperationalItemMultipleSearchRowData> event) {
boolean isClick = "click".equals(event.getNativeEvent().getType());
if (isClick)
AdminUtils.EVENT_BUS.fireEvent(new SimpleSearchEvent(event.getValue().getName()));
}
});
The Problem is that this reacted to a Click on the whole row instead of the link. Due to architectural restrictions, the link itself is not a real html link, but a SafeHtml link that leads nowhere. I just needed the look&feel of a Link:
Column<OperationalItemMultipleSearchRowData, SafeHtml> nameColumn = new Column<OperationalItemMultipleSearchRowData, SafeHtml>(new SafeHtmlCell()) {
#Override
public SafeHtml getValue(final OperationalItemMultipleSearchRowData object) {
return new SafeHtml() {
#Override
public String asString() {
return "" + object.getName() + "";
}
};
}
};
How can I react to a click on this link only ? (instead of the whoel row)
Is there a more elegant way to implement this ?
Cheers
As with any other use of event delegation, the basic idea is to find walk up the hierarchy starting from the target of the event up until you find the link element you're looking for, or some other element that signals the search is over and the click was targetted outside the link (e.g. you reached the cell, the row or the table).
That being said, I think you should merge your behavior inside a specific Cell implementation rather than using a CellPreviewHandler (copy/paste the ActionCell or TextButtonCell as a starting point).
As a side note, I also believe you should not use a link when you're not actually linking anywhere, or try to provide a target for the link if the behavior is the one of a link (that way, right-clicking, middle-clicking or ctrl-clicking will Just Work™). If you want the look of a link (without the "feel"), then just use an ActionCell or TextButtonCell and style it accordingly.

How can a JSF/ICEfaces component's parameters be updated immediately?

I have an ICEfaces web app which contains a component with a property linked to a backing bean variable. In theory, variable value is programmatically modified, and the component sees the change and updates its appearance/properties accordingly.
However, it seems that the change in variable isn't "noticed" by the component until the end of the JSF cycle (which, from my basic understanding, is the render response phase).
The problem is, I have a long file-copy operation to perform, and I would like the the inputText component to show a periodic status update. However, since the component is only updated at the render response phase, it doesn't show any output until the Java methods have finished executing, and it shows it all changes accumulated at once.
I have tried using FacesContext.getCurrentInstance().renderResponse() and other functions, such as PushRenderer.render(String ID) to force XmlHttpRequest to initialize early, but no matter what, the appearance of the component does not change until the Java code finishes executing.
One possible solution that comes to mind is to have an invisible button somewhere that is automatically "pressed" by the bean when step 1 of the long operation completes, and by clicking it, it calls step 2, and so on and so forth. It seems like it would work, but I don't want to spend time hacking together such an inelegant solution when I would hope that there is a more elegant solution built into JSF/ICEfaces.
Am I missing something, or is resorting to ugly hacks the only way to achieve the desired behavior?
Multithreading was the missing link, in conjunction with PushRenderer and PortableRenderer (see http://wiki.icesoft.org/display/ICE/Ajax+Push+-+APIs).
I now have three threads in my backing bean- one for executing the long operation, one for polling the status, and one "main" thread for spawning the new threads and returning UI control to the client browser.
Once the main thread kicks off both execution and polling threads, it terminates and it completes the original HTTP request. My PortableRenderer is declared as PortableRender portableRenderer; and in my init() method (called by the class constructor) contains:
PushRenderer.addCurrentSession("fullFormGroup");
portableRenderer = PushRenderer.getPortableRenderer();
For the threading part, I used implements Runnable on my class, and for handling multiple threads in a single class, I followed this StackOverflow post: How to deal with multiple threads in one class?
Here's some source code. I can't reveal the explicit source code I've used, but this is a boiled-down version that doesn't reveal any confidential information. I haven't tested it, and I wrote it in gedit so it might have a syntax error or two, but it should at least get you started in the right direction.
public void init()
{
// This method is called by the constructor.
// It doesn't matter where you define the PortableRenderer, as long as it's before it's used.
PushRenderer.addCurrentSession("fullFormGroup");
portableRenderer = PushRenderer.getPortableRenderer();
}
public void someBeanMethod(ActionEvent evt)
{
// This is a backing bean method called by some UI event (e.g. clicking a button)
// Since it is part of a JSF/HTTP request, you cannot call portableRenderer.render
copyExecuting = true;
// Create a status thread and start it
Thread statusThread = new Thread(new Runnable() {
public void run() {
try {
// message and progress are both linked to components, which change on a portableRenderer.render("fullFormGroup") call
message = "Copying...";
// initiates render. Note that this cannot be called from a thread which is already part of an HTTP request
portableRenderer.render("fullFormGroup");
do {
progress = getProgress();
portableRenderer.render("fullFormGroup"); // render the updated progress
Thread.sleep(5000); // sleep for a while until it's time to poll again
} while (copyExecuting);
progress = getProgress();
message = "Finished!";
portableRenderer.render("fullFormGroup"); // push a render one last time
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
});
statusThread.start();
// create a thread which initiates script and triggers the termination of statusThread
Thread copyThread = new Thread(new Runnable() {
public void run() {
File someBigFile = new File("/tmp/foobar/large_file.tar.gz");
scriptResult = copyFile(someBigFile); // this will take a long time, which is why we spawn a new thread
copyExecuting = false; // this will caue the statusThread's do..while loop to terminate
}
});
copyThread.start();
}
I suggest looking at our Showcase Demo:
http://icefaces-showcase.icesoft.org/showcase.jsf?grp=aceMenu&exp=progressBarBean
Under the list of Progress Bar examples is one called Push. It uses Ajax Push (a feature provided with ICEfaces) to do what I think you want.
There is also a tutorial on this page called Easy Ajax Push that walks you through a simple example of using Ajax Push.
http://www.icesoft.org/community/tutorials-samples.jsf

Resources