You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Werner Punz <we...@gmx.at> on 2005/06/23 10:43:16 UTC

x:dataScroller how to preserve the state

Hi, I have a problem regarding the x:dataScroller component, which I try 
to figure out.

I have a problem of having a table with a datascroller and a backend model.
The table is filled correctly, the scroller works as supposed.
But I now have an action link in the table, which does some actions (in
my case marking a dataset for operation)
This also works as long as I am on page 1 of the scroller.
But strange things happen as soon as I try to do it at a subsequent page.

The operation is triggered and works according to the code perfectly, 
and as soon as I return, the scroller basically resets to page 1.
I am not quite sure how to resolve this, a quick look at the code
showed me that I could trigger the same links as the scroller does, or
misuse the binding var.

But is there a standardized easy way to do this.

x:saveState on the binding var, does not really seem to work in thise case.


Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Werner Punz wrote:
> Since nobody answers I try to reformulate the question differently.
> The datascroller basically uses the pageIndexVar to set the position.
> If I scroll everything is fine.
> But as soon as I do a form submit outside of the datascroller,
> the pageIndex var is reset to the first position.
> My question is, is there a way to prevent this reset of the scroller 
> page index? x:saveState does not seem to work in this case.
> 
> 
> Werner
> 
> 
Ok I have solved it myself...
You can reference the pageCount variable by messing directly with the 
request map.
Following scenario is possible...
You can access the pageCount variable from the scroller the following way:

Object scrollerState = ...getRequest().getAttribute("pageCount");
(your pagecount Variable name may vary)
at the restore attributes phase (basically at the backend bean creation 
time if you are in the request scope)

You can then store it away in the session or a cache
and once you trigger an operation which needs a saved state of the
scroller you can push the last page count from your cache back
into the request by using the setAttribute.

This solution is somewhat messy, but it works.
There would be a possible szenario with a pageCount controller backend 
bean with a session scope, which could to the storing and expose a 
preserveState method, which pushes the pageCount back from the stack
into the request.





Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Martin Marinschek wrote:
> Sorry, 
> 
> don't know so many details about the data-scroller, but I think Thomas
> said that this is a problem still to be overcome.
> 
For some strange kind of reason it does not work with an external bean...
I really have to look into that seriously

 > Maybe you would want to work on that and provide a patch?
 >
If time allows it :-)


Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Werner Punz wrote:

> 
> I think I found the affected part of the datascroller.
> The think is, that the datascroller saves the current scroller
> position over its id in the request parameter map.
> 
> But once the event is not triggered by the scroller,
> the position is not saved over its name in the global request parameter 
> map and basically the scrollers position setting routines in the
> renderer are not triggered that way.
> 
> I will try to fix that in the weekend against the 1.0.9 sources.
> I am not entirely sure about the best way to fix that.
> But my best guess is the introduction of a saveState attribute, which
> restores last position state from the session, if set to true, once the
> renderer of the scroller runs against an empty attribute.
> 
> That way you can turn on the savestate restoration selectively upon a
> given state of a backend bean.
> Because often you dont really want to have the state safed.
> 
> I would rather not having to doctor around at the original sources yet 
> or having to implement yet another component, since my schedule still is 
> too tight, but oh well... That´s life.
> 
Guess I have to answer myself again.

Well as it seems it is not really fixable by me at the moment, the 
problem is tied to the way JSF manages the requests. I am sure somebody 
with more knowledge about the internals might be able to fix it, but 
with my limited knowledge of things it would take too long.

There might be a workaroud however to get around that problem.
First of all you normally have those form like operations within a data 
table for triggering a small operation.
I noticed that the datatable/datascroller unlike plain forms stays at 
the last stage at a page refresh and does not go back to the state 
before, like most pages/components do.
The workaround to the problem of keeping a constant state of the 
scroller wile triggering operations might be, to bind ajax to checkboxes 
and send requests via ajax to the server, which marks the affected 
datasets in the session.

Then you can trigger the operation as well via ajax and after the 
operation is successfully finished a simple page refresh is possible.
The datamodel in the backend however probably has to be refreshed
by the ajax code if it is buffered or cached.

This solution should work around this rather nasty problem.


Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Martin Marinschek wrote:
> Sorry, 
> 
> don't know so many details about the data-scroller, but I think Thomas
> said that this is a problem still to be overcome.
> 
> Maybe you would want to work on that and provide a patch?
> 

I think I found the affected part of the datascroller.
The think is, that the datascroller saves the current scroller
position over its id in the request parameter map.

But once the event is not triggered by the scroller,
the position is not saved over its name in the global request parameter 
map and basically the scrollers position setting routines in the
renderer are not triggered that way.

I will try to fix that in the weekend against the 1.0.9 sources.
I am not entirely sure about the best way to fix that.
But my best guess is the introduction of a saveState attribute, which
restores last position state from the session, if set to true, once the
renderer of the scroller runs against an empty attribute.

That way you can turn on the savestate restoration selectively upon a
given state of a backend bean.
Because often you dont really want to have the state safed.

I would rather not having to doctor around at the original sources yet 
or having to implement yet another component, since my schedule still is 
too tight, but oh well... That´s life.




Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Martin Marinschek wrote:
> Sorry, 
> 
> don't know so many details about the data-scroller, but I think Thomas
> said that this is a problem still to be overcome.
> 
> Maybe you would want to work on that and provide a patch?
> 
I solved the problem by making my own scroller controller class
which has a request scope, the scroller controller delivers
the page count var name via: pageIndexVar="#{scrollerController.scroller}"

this one is called whenever the page counter is initialized or set
at that stage I pull the value out of the local scope
push it into a session scope and
then I can access it from outside and push it back into the request
cyle at a different time, sort of hackish but seems to work, since
the scroller checks if the pageCount already is set in the request cycle 
or not.


Re: x:dataScroller how to preserve the state

Posted by Martin Marinschek <ma...@gmail.com>.
Sorry, 

don't know so many details about the data-scroller, but I think Thomas
said that this is a problem still to be overcome.

Maybe you would want to work on that and provide a patch?

regards,

Martin

On 6/23/05, Werner Punz <we...@gmx.at> wrote:
> Since nobody answers I try to reformulate the question differently.
> The datascroller basically uses the pageIndexVar to set the position.
> If I scroll everything is fine.
> But as soon as I do a form submit outside of the datascroller,
> the pageIndex var is reset to the first position.
> My question is, is there a way to prevent this reset of the scroller
> page index? x:saveState does not seem to work in this case.
> 
> 
> Werner
> 
> 
> 
> Werner Punz wrote:
> > Hi, I have a problem regarding the x:dataScroller component, which I try
> > to figure out.
> >
> > I have a problem of having a table with a datascroller and a backend model.
> > The table is filled correctly, the scroller works as supposed.
> > But I now have an action link in the table, which does some actions (in
> > my case marking a dataset for operation)
> > This also works as long as I am on page 1 of the scroller.
> > But strange things happen as soon as I try to do it at a subsequent page.
> >
> > The operation is triggered and works according to the code perfectly,
> > and as soon as I return, the scroller basically resets to page 1.
> > I am not quite sure how to resolve this, a quick look at the code
> > showed me that I could trigger the same links as the scroller does, or
> > misuse the binding var.
> >
> > But is there a standardized easy way to do this.
> >
> > x:saveState on the binding var, does not really seem to work in thise case.
> >
> >
> 
>

Re: x:dataScroller how to preserve the state

Posted by Werner Punz <we...@gmx.at>.
Since nobody answers I try to reformulate the question differently.
The datascroller basically uses the pageIndexVar to set the position.
If I scroll everything is fine.
But as soon as I do a form submit outside of the datascroller,
the pageIndex var is reset to the first position.
My question is, is there a way to prevent this reset of the scroller 
page index? x:saveState does not seem to work in this case.


Werner



Werner Punz wrote:
> Hi, I have a problem regarding the x:dataScroller component, which I try 
> to figure out.
> 
> I have a problem of having a table with a datascroller and a backend model.
> The table is filled correctly, the scroller works as supposed.
> But I now have an action link in the table, which does some actions (in
> my case marking a dataset for operation)
> This also works as long as I am on page 1 of the scroller.
> But strange things happen as soon as I try to do it at a subsequent page.
> 
> The operation is triggered and works according to the code perfectly, 
> and as soon as I return, the scroller basically resets to page 1.
> I am not quite sure how to resolve this, a quick look at the code
> showed me that I could trigger the same links as the scroller does, or
> misuse the binding var.
> 
> But is there a standardized easy way to do this.
> 
> x:saveState on the binding var, does not really seem to work in thise case.
> 
> 


Re: Antwort: Re: Antwort: Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
mathias.werlitz@daimlerchrysler.com wrote:
> 
> Thanks for the info. Important to know.
> But I would expect this behavior, because the component and its state 
> should be preserved with the instance in the bean.
The problem is not that the component does not preserve the state, but 
the problem is much deeper in the request cycle.
The problem is, if you send an request which is not covered by the 
faces-config navigation, a simple refresh, the datamodel is basically 
the same between encodebegin and encodechildren

if you do it over a faces-config nav refresh, the datamodel gets 
rendered and then is lost to the scroller, for some strange kind of reason.

So what happens, the state basically is preserved, but the datamodel 
gets lost between two rendering phases.



Antwort: Re: Antwort: Re: x:dataScroller how to preserve the state - finally solved

Posted by ma...@daimlerchrysler.com.
Thanks for the info. Important to know.
But I would expect this behavior, because the component and its state 
should be preserved with the instance in the bean.

Re: Antwort: Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
mathias.werlitz@daimlerchrysler.com wrote:
> 
> Just an idea: you could bind the component itself to a session scoped 
> bean or save that bean with the <x:saveState> component between requests.
> I have not tried this, but I guess that should avoid loosing the state 
> between multiple requests even with page navigation.

Unfortunately that does not work... tried that a while ago.


Antwort: Re: x:dataScroller how to preserve the state - finally solved

Posted by ma...@daimlerchrysler.com.
Just an idea: you could bind the component itself to a session scoped bean 
or save that bean with the <x:saveState> component between requests.
I have not tried this, but I guess that should avoid loosing the state 
between multiple requests even with page navigation.

Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
Enrique Medina wrote:
> Just some clarification...
> 
> I told you to check whether it works with preserveDataModel set to
> false, due to the fact that preserveDataModel set to true does not
> work with checkboxes placed inside the table (as the typical way to
> select some rows to, for example, delete all selected).
> 
> It seems that there is an order problem when MyFaces serializes them
> to preserve the dataModel, so the checkboxes get mixed between
> requests...
> 
That is one of the reasons why I implemented my own event based 
checkboxing system for datatables, as you can see in the code I posted 
before... :-)

The state saving is done via some kind of caching on the backend
side of things, so nothing can get mixed up in my case...


Re: x:dataScroller how to preserve the state - finally solved

Posted by Enrique Medina <e....@gmail.com>.
Just some clarification...

I told you to check whether it works with preserveDataModel set to
false, due to the fact that preserveDataModel set to true does not
work with checkboxes placed inside the table (as the typical way to
select some rows to, for example, delete all selected).

It seems that there is an order problem when MyFaces serializes them
to preserve the dataModel, so the checkboxes get mixed between
requests...

Have you faced that problem?

2005/6/28, Werner Punz <we...@gmx.at>:
> Enrique Medina wrote:
> > Fantastic. NULL tells JSF just to stay in the same page, so it should
> > work as you have tested. But the problem still remains when navigating
> > to another page, doesn't it?
> >
> Yes that is a huge problem, but the problem is bigger than it seems, it
> is basically the old scope problem, which means that you basically loose
> all the values unless you traverse it, because we do not have a scope
> system between request and session, and add to that some weirdness in
> the behavior between the datatable and the scroller and you run into
> this mess.
> 
> Shale can solve that to some degree, but I rather doubt it will solve it
> for the datatable, the problem is sort of much more fundamental.
> 
> I will try to explain what happens and why the values are lost between
> faces-config navigations:
> 
> What happens in a null:
> 
> The values are cleard the form values are refilled, the parameters are
> passed via a submit...
> The datatable is generated
> the scroller is generated does an encodebegin with all the needed
> calculations passes it to the datatable for further reference,
> the datatable is rendered
> and then the scroller does its rendering.
> 
> What happens if you dont do the refresh but a faces-config based traversal:
> 
> The steps until the encodebegin are identical, but then the problem
> arises in between encodebegin and renderchildren, the datamodel is lost
> along the way and a new one is generated, which is not the same as the
> rendered one, thus passing the values, altering the states, etc... does
> not have any effect on the rendering and the table->scroller subsystem
> resets to the first page.
> 
> I tried to fix that, but I ran against my limited knowledge of JSF.
> Probably to fix that a new datatable and scroller maybe a combined
> component has to be implemented.
> Trying to fix it from outside with a bunch of listeners which hook into
> the component definitely wont help neither does altering the scroller
> rendering code, because the problem is nested much much deeper.
> 
>

Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
Enrique Medina wrote:
> Fantastic. NULL tells JSF just to stay in the same page, so it should
> work as you have tested. But the problem still remains when navigating
> to another page, doesn't it?
> 
Yes that is a huge problem, but the problem is bigger than it seems, it 
is basically the old scope problem, which means that you basically loose 
all the values unless you traverse it, because we do not have a scope 
system between request and session, and add to that some weirdness in 
the behavior between the datatable and the scroller and you run into 
this mess.

Shale can solve that to some degree, but I rather doubt it will solve it 
for the datatable, the problem is sort of much more fundamental.

I will try to explain what happens and why the values are lost between 
faces-config navigations:

What happens in a null:

The values are cleard the form values are refilled, the parameters are 
passed via a submit...
The datatable is generated
the scroller is generated does an encodebegin with all the needed 
calculations passes it to the datatable for further reference,
the datatable is rendered
and then the scroller does its rendering.


What happens if you dont do the refresh but a faces-config based traversal:

The steps until the encodebegin are identical, but then the problem 
arises in between encodebegin and renderchildren, the datamodel is lost 
along the way and a new one is generated, which is not the same as the 
rendered one, thus passing the values, altering the states, etc... does 
not have any effect on the rendering and the table->scroller subsystem
resets to the first page.

I tried to fix that, but I ran against my limited knowledge of JSF.
Probably to fix that a new datatable and scroller maybe a combined 
component has to be implemented.
Trying to fix it from outside with a bunch of listeners which hook into 
the component definitely wont help neither does altering the scroller 
rendering code, because the problem is nested much much deeper.


Re: x:dataScroller how to preserve the state - finally solved

Posted by Enrique Medina <e....@gmail.com>.
Fantastic. NULL tells JSF just to stay in the same page, so it should
work as you have tested. But the problem still remains when navigating
to another page, doesn't it?

Thanks Werner.

2005/6/28, Werner Punz <we...@gmx.at>:
> Enrique Medina wrote:
> > Hi Werner,
> >
> > Do you mean that returning NULL from the action method would be sufficient?
> >
> > And another comment, does it work if you set preserveDataModel to false?
> >
> Just tried it out, at least on my system preserveDataModel to false and
> returning a null from the action does not make any difference, the
> system preserves the positional state as long as you dont run into
> any mapped action value (null seems to be covered in this case
> by the subsystem as navigational value)
> 
> So things look pretty good.
> 
>

Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
Enrique Medina wrote:
> Hi Werner,
> 
> Do you mean that returning NULL from the action method would be sufficient?
> 
> And another comment, does it work if you set preserveDataModel to false?
> 
Just tried it out, at least on my system preserveDataModel to false and 
returning a null from the action does not make any difference, the 
system preserves the positional state as long as you dont run into
any mapped action value (null seems to be covered in this case
by the subsystem as navigational value)

So things look pretty good.


Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
Enrique Medina wrote:
> Hi Werner,
> 
> Do you mean that returning NULL from the action method would be sufficient?
> 
not sure if a returning null would not cause a nullpointer, since I am 
working on it now I will give it a try, hold on.

> And another comment, does it work if you set preserveDataModel to false?
> 
I will try it, hold on for a few minutes...

Werner


Re: x:dataScroller how to preserve the state - finally solved

Posted by Enrique Medina <e....@gmail.com>.
Hi Werner,

Do you mean that returning NULL from the action method would be sufficient?

And another comment, does it work if you set preserveDataModel to false?

2005/6/28, Werner Punz <we...@gmx.at>:
> It seems that I finally have found an easy solution to the problem.
> 
> The state of the datamodel and the datscroller seems to be preserved
> if there is no explicit forwarding set in the faces-config, thus
> only a refresh with different parameters is issued.
> 
> I will try to give an example: I have a datatable with a connected
> datascroller with a paginator:
> 
> The table has a command link somewhere
> 
> <h:commandLink action="#{DiffsyschangelogMaster.selectForOperation}">
>         <h:outputText id="selected" value="[x]"
>                         rendered="#{bean.selectedForOperation}" />
>         <h:outputText id="notselected" value="[ ]"
>                 rendered="#{!bean.selectedForOperation}" />
>         <f:param name="beanId" value="#{bean.id}" />
> </h:commandLink>
> 
> The problem is now, if there is an explicit action from
> #{DiffsyschangelogMaster.selectForOperation} value which is covered by
> the faces-config, a full cycle is issued, that means that model
> scroller resets to 1 due to internal handling of the objects (there
> seems to be an interim page, which resets the data model position and
> generates new models between encodeBeging and renderChildren, this looks
> like a bug or unwanted sidebehavior to me).
> 
> The main difference is if you set the result value to something bogus,
> which is not covered by the faces config... a simple form refresh with
> is issued which recoveres the old model values if the
> preserveDataModel="true" is set to true and hence the scroller position
> is recovered and rendered anew with the old and the changed values.
> 
> No patch to the current sourcebase is needed nor do we need a new
> scroller, the existing one seems to do the job just fine.
> 
> Werner
> 
>

Re: x:dataScroller how to preserve the state - finally solved

Posted by Werner Punz <we...@gmx.at>.
It seems that I finally have found an easy solution to the problem.

The state of the datamodel and the datscroller seems to be preserved
if there is no explicit forwarding set in the faces-config, thus
only a refresh with different parameters is issued.

I will try to give an example: I have a datatable with a connected
datascroller with a paginator:

The table has a command link somewhere

<h:commandLink action="#{DiffsyschangelogMaster.selectForOperation}">
	<h:outputText id="selected" value="[x]"
			rendered="#{bean.selectedForOperation}" />
	<h:outputText id="notselected" value="[ ]"
		rendered="#{!bean.selectedForOperation}" />
	<f:param name="beanId" value="#{bean.id}" />
</h:commandLink>

The problem is now, if there is an explicit action from 
#{DiffsyschangelogMaster.selectForOperation} value which is covered by 
the faces-config, a full cycle is issued, that means that model
scroller resets to 1 due to internal handling of the objects (there 
seems to be an interim page, which resets the data model position and 
generates new models between encodeBeging and renderChildren, this looks 
like a bug or unwanted sidebehavior to me).

The main difference is if you set the result value to something bogus, 
which is not covered by the faces config... a simple form refresh with 
is issued which recoveres the old model values if the 
preserveDataModel="true" is set to true and hence the scroller position 
is recovered and rendered anew with the old and the changed values.

No patch to the current sourcebase is needed nor do we need a new 
scroller, the existing one seems to do the job just fine.

Werner