dynamic richfaces dataTable, ajax4jsf, and reRendering - datatable

I have a rich dataTable that's defined inside of an a4j:outputPanel, and that's bound to a session-scoped backing bean that creates the HtmlDataTable. By itself, that part of my code is working fine, and the dataTable looks good.
On another part of the page, there are some basic text links that I'm creating as a4j:commandLinks, and when those are clicked, the dataTable should be re-rendered with new row and column data. The row data's updating fine, but the column data (header text, width, etc.) isn't.
After digging around the code for a bit, it seems that the call to the backing bean for the HtmlDataTable isn't being made during the reRendering of that table, but it is reRendered if the whole page is reloaded; so it seems that it's just the ajax4jsf/reRendering portion that's biting me here.
Is there any way that I can force the reRender process to invalidate the dataTable structure so that it will call the backing bean again for it?
If it means anything, I'm also using Seam; so if there's a solution to be found using it, that'd be helpful, too.
Thanks!

For posterity's sake, I've found the solution: Whenever the a4j request is made to my action listener bean, I have it tell the dataTable-building bean to flush its table. That bean then does a simple myDataTable.getParent().getChildren().remove(myDataTable). This page helped me figure it out: http://www.coderanch.com/t/213312/JSF/java/dynamic-datatable-binding.

In your action just remove the session scoped bean from your contexts.
For example:
<a:commandLink action="#{someBean.perform}" value="Submit" reRender="myTable"/>
and the action:
#Name("someBean")
public class SomeBean {
public void perform() {
//do stuff
Contexts.removeFromAllContexts("myBean");
}
}
Othewrwise if your dataTable is populated with a list then it's probably as easy as just calling the search() or whatever method loads the data.

Related

Clarification needed in using Ajax forms and Partial Page

I am newbie to MVC and Web App.
Recently I have went through the article
http://www.c-sharpcorner.com/UploadFile/pmfawas/Asp-Net-mvc-how-to-post-a-collection/
It uses the Ajax Form, to do the partial update towards a particular region alone..
But I have a doubt in that example...
I have seen the partial Page inside the Div with Id "AllTweets"....
<div id="AllTweets">
#Html.Partial("_AllTweets", Model) ***** (XXX)
</div>
And also in the controller action,
try
{
viewModel.Tweets.Add(viewModel.Tweet);
return PartialView("_AllTweets", viewModel); **** (YYYYY)
}
Now my question is,
They are returning the partial view along with the data from the action in the controller.
Whatever the data returned from the controller, the engine will place that data, inside the target div with id "AllTweets"...
But still, why I have to have the statement, #Html.Partial("_AllTweets", Model) inside the Div, since already I am returning the data from the controller...
And also in some of the examples, i have seen the same kind of the code..
But, even if I have removed the code "#Html.Partial("_AllTweets", Model)" inside the div, the code still works fine, and without any problem and i can able to post the data to the action in the controller.
I got totally stuck at this point.
May I kindly know, what is the reason behind it and why so.... So I can understand it more better.
Thanks in advance...
But, even if I have removed the code #Html.Partial("_AllTweets",
Model) inside the div, the code still works fine, and without any
problem and i can able to post the data to the action in the
controller.
Yes it will work fine. The Html.Partial("_AllTweets",Model) renders the partial with the specified model on every page load. After page is loaded, then ajax is used to fill the div with id AllTweets.
Html.Partial("_AllTweets",Model) is usefull when you want to display, for example, already saved tweets from your database to user when the page first loads. And then ajax takes care of later updates.

Rendering collection view in CompositeView triggered constructor?

I have a composite view which has a task, and it's comments. I put it onto a contentRegion to display. When rendering model alone, it works fine. However when come to collection, it behaves really strange. console.log shows initialize function has been triggered twice. The first time is when define the view
taskView = new MyProject.Views.Task
model : task
collection : comments
I then do a MyProject.contentRegion.show(taskView) in order to render the model view. After that, I just call comments.fetch() to get all the comments. Then comes the problem, it re-initialized my taskView and the template keep complaining xxx is undefined.
Any thoughts? I know it's weird because another CompositeView in my project works great.
NathanInMac, I've done a little testing from your suggestion of using an itemView and found some interesting stuff.
Was your problem involving nested compositeviews'? As mine was but I'm unsure if that affects anything.
What solved the problem was initially trying a collectionView which couldn't find the itemView so I moved the definition of the itemView for the collectionView/compositeView to before the definition of the collectionView(or extended).
This seems to be a working fix and just a misleading bug with compositeView's double initializing instead of displaying some exception or error.

Refreshing Partial View in MVC 3

I have a partial view that I have included on my _Layout.cshtml. It simply has a javascript function that changes an image based on the state of my system. I don't need to reload any data, I don't need to go to the code of the controller for anything, I simply need to reload that partial view.
I tried many of the examples that I found here but couldn't get any of them to work. I felt as if they were too complex for what I was doing anyway. Any guidance would be appreciated.
Thanks,
Steve
If the partial is loaded into the layout directly then there's no straightforward way to refresh it, because it's basically a part of the complete rendered page.
Your best bet is to render the partial using $.load or whatever equivalent you have available by hitting a controller method and rendering the result into a container (like a div). You would have to do this within a script that is loaded with the layout itself, by observing document.ready or something like that. Once you have that in place then it's trivial to keep reloading or refreshing the contents by hitting the controller method as many times as you need. For example in jQuery:
$(document).ready(function () {
RefreshPartial();
window.setInterval(RefreshPartial, 10000);
});
function RefreshPartial() {
$('#container').load('/some/controller/endpoint', {parameters});
}
This will call the controller method, and set the inner contents of the element identified with #container. You can call RefreshPartial as many times as you want.
Partial views only exist on the server. The only way to "refresh" the partial is to go back to the server to get it again.
Obviously, you must be doing something in the partial that needs refreshing. Whatever that is, should be callable from javascript to do the refresh.

How do I add ajax behavior to a dynamically created component in a backing bean?

In respose to Infragile's request in another thread, I am asking this as a separate question rather than a followup.
Here is the problem I am attempting to address:
I'm migrating from JSF1.2 to JSF2. Everything worked fine in JSF1.2.
I have rewritten a critical item to be a composite component which is basically a panel created in my backing bean by adding components in code.
In particular, I have h:inputText and h:selectOneMenu components that I create in code along with an "Apply" h:commandButton.
The "Apply" button has an action listener that checks for the values in the h:inputText and h:selectOneMenu components. All this works fine, but when I fetch the values in the h:inputText or h:selectOneMenu components I get the original values, not the new values that were entered by the user. Like I said, this worked fine in JSF1.2 (i got the new values), but not in JSF2 for some reason.
I have tried several things to get around this that haven't worked, so I figured I would add ajax behavior to the h:inputText and h:selectOneMenu items and when the values in these components change, I could call another backing bean listener for the ajax behavior to fetch the new values.
I am trying to add ajax behavior to a component I create in code (not bound to a page component). I can create the component with no problem. However, the problem that I am having is how to add the ajax behavior to the component.
Could someone post sample code to add an ajax behavior for a value change or blur event? Here is the code I use to create the component in code - how would I need to modify it to add the ajax behavior?
hpg = new HtmlPanelGrid();
children = hpg.getChildren();
children.clear();
....
input = new HtmlInputText();
....
children.add(input);
What code would I have to add to replace the "add ajax behavior here" line, and what would the arguement for the listener method be (arguement for the method to replace the ????? below)?
public void myAjaxListener(?????) { ...... {
I have been trying to get a handle on this for some time now. I feel that I am pretty close, but don't know the syntax I need. I can provide more information on how I am fetching the component Ids and searching for the values in my action listener if that will help.
Thanks
This is how you can add dynamically AjaxBehaviorListener to yor component:
...
HtmlInputText inpuText = new HtmlInputText();
AjaxBehavior blurBehavior = new AjaxBehavior();
blurBehavior.addAjaxBehaviorListener(new BlurListener());
blurBehavior.setTransient(true);
inputText.addClientBehavior("blur", blurBehavior)
...
public class BlurListener implements AjaxBehaviorListener {
public BlurListener() {
}
#Override
public void processAjaxBehavior(AjaxBehaviorEvent event) {
// do your job
HtmlInputText inputText = event.getComponent(); // your input text component
...
}
}
"blur" represents event when this listener will be triggered. Remember that JSF Component must support this event, otherwise it won't work.
(Here you can see under covers and how to build custom AJAX component http://weblogs.java.net/blog/driscoll/archive/2009/10/09/jsf-2-custom-java-components-and-ajax-behaviors?force=670 )
However in your case I think problem is that buttons ActionListener is triggered before actual component values are submited. You can solve it by moving your ActionListener logic to button action, by aformentioned AJAX, maybe by findinng actual values in UIComponents (HtmlInputText, UISelectOne), not sure but immediate attribute can also influence it.

JSF f:event preRenderView is triggered by f:ajax calls and partial renders, something else?

So we have an f:event:
<f:metadata>
<f:event type="preRenderView" listener="#{dashboardBacking.loadProjectListFromDB}"/>
</f:metadata>
Which is triggered as desired on initial page load (render).
However this preRenderView event is also triggered by an ajax partial page render, which re-renders an h:panelgroup with the id projectListing, as below.
<h:commandButton action="#{mrBean.addProject}" value="Create Project"
title="Start a new project">
<f:ajax render="projectListing" />
</h:commandButton>
I only want the dashboardBacking.loadProjectListFromDB to be called for the initial page render, but not when there is an ajax partial render. Is there a more appropriate event or method I could be using?
I had the same need not too long ago. I ended up using something suggested by BalusC.
There is a method in the FacesContext class that lets you know if you're dealing with a full blown request or a partial processing of some sort:
FacesContext.getCurrentInstance().isPostback()
This way you can still use the preRenderView technique and check if it's a postback in the listener. I found that particularly useful because I needed a session bean as the user had to navigate to another page and come back. If I used view scoped beans (like suggested above by Brian), I'd lose the info I had before navigating away.
Another option would be to put your preRenderView functionality in a #PostConstruct method of a ViewScoped managed bean. This logic would be executed when the bean is initialized, and you you maintain the same instance of the bean for all your ajax requests until you change views.
Another possibility is to check if the request is an ajax one or not in the preRenderView method. You can also perform the load conditionally considering other factors such as if the request is a GET or not and if validation failed or not (view params validation can fail on GET page).
boolean getMethod = ((HttpServletRequest) fc.getExternalContext().getRequest()).getMethod().equals("GET") ? true : false;
boolean ajaxRequest = fc.getPartialViewContext().isAjaxRequest();
boolean validationFailed = fc.isValidationFailed();
The "new-age" way of handling this is described here:
http://www.coderanch.com/t/509746/JSF/java/duplicate-call-preRenderView-event#2634752
You could try attaching the preRenderView event listener to an individual component, rather than the page. Choose a component that is not rendered during an Ajax request.
One small problem is that the view parameters have not been set when the #PostConstruct method is called so I had to get them explicitly:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("theParam");
update: actually, I ended up doing the #PostConstruct thing, its much cleaner.
I had exactly the same issue today with a session-scoped backing bean. Namely, I had registered an event-listener method on the backing session-scoped bean that was registered with the preRenderView. But I found that it was also fired on some Ajax sorting operations on a PrimeFaces 3 dataTable component. So, what I ended up doing was using a boolean instance variable on the session-scoped backing bean to make sure the body of the event-listener method executed only the first time (the boolean acted as a flag). I am sure it's rather naive and probably broken on certain cases so I would be interested to know why and how this simplistic approach might fail.

Resources