myfaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sylvain Vieujot <svieu...@apache.org>
Subject Re: New "initId" attribute
Date Mon, 20 Jun 2005 23:54:34 GMT
I just find maybe a more elegant way to solve this.
It still involves using dynamically setting the clientId, but instead of
adding a new attribute to the components, we could add a new rowId
attribute to the x:dataTable :
<x:dataTable var="email" rowId="#{email.unid}" ...>

As dataTable is a namingContainer (I guess), we could override
namingContainer.getClientId(context) to use the given EL formula instead
of the row1, row2, ... counter.

I didn't check it all yet, but if this works, it would be less
disruptive, and have a similar effect.

Sylvain.

On Mon, 2005-06-20 at 18:06 -0400, Sylvain Vieujot wrote:

> Hello John,
> 
> Thanks for your nice summary of the problem.
> The solution you propose with an attached state is the same as the
> x:dataTable's preserveDataModel attribute which solves the problem
> by ... storing the data model.
> And that's precisely what I want to avoid as in many cases it's either
> impossible or just a bad idea.
> 
> The core of the problem is exactly this : the only links between the
> view and the data model if you don't store the data model are the
> posted request parameters names (i.e. component's clientIds).
> 
> So, if you can store the data model, no change is needed right now.
> Using preserveDataModel="true" should work.
> However, if you can't store the data model, then you have to have some
> control over the component's id's. So the only solution is to have a
> way use EL to set component's ids.
> 
> Sylvain.
> 
> P.S. Just for the story, you don't need to have two clients to get
> this problem. If you receive a spam between the 2 requests, you end up
> deleting the wrong email too ;-)
> 
> On Mon, 2005-06-20 at 20:36 +0000, John Fallows wrote: 
> 
> > Gang,
> > 
> > I agree with Kalle.  This sounds like a real problem, but with a
> > proposed fix at the wrong layer of abstraction.
> > 
> > It made me think of the following...
> > 
> > The dataTable value attribute is pointing to a DataModel via an EL
> > binding, and the UIData component saveState method saves the "attached
> > state" for each EL binding that points to an object implementing
> > StateHolder.
> > 
> > Let's say that it is the responsibility of the DataModel to provide a
> > stable index across requests.
> > 
> > Could this stability be achieved, even for a mutating list, by having
> > the particular DataModel implement StateHolder, and manage the mapping
> > between row index and row key?
> > 
> > For example, say on initial render we get the following:
> > 
> > row index=0 key=emailX
> > row index=1 key=emailY
> > row index=2 key=emailZ
> > 
> > where the "attached state" for the DataModel retains the knowledge
> > that the keys were intially observed as ["emailX", "emailY",
> > "emailZ"].
> > 
> > Now, using a different email client, I delete emailX, so that emailY
> > is moved up to row index 0, and emailZ is moved up to row index 1.
> > 
> > Then, using the initially rendered web mail page, which is still
> > displaying 3 rows, I choose to delete emailY (which is still showing
> > as row index 1, even though the back end has been modified
> > concurrently).
> > 
> > This posts back a request to delete row 1, which would normally cause
> > emailZ to be deleted, because it resides at row 1 after emailX was
> > deleted.
> > 
> > However, the attached state is restored to the DataModel during
> > RestoreView phase.
> > 
> > ["emailX", "emailY", "emailZ"].
> > 
> > So, it is understood that this is not a request to delete row 1, but a
> > request to delete "emailY".
> > 
> > Then "emailY" is deleted, and the page is re-rendered showing only
> > "emailZ", since "emailY" has just been deleted, and "emailX" was
> > previously deleted concurrently.
> > 
> > Thoughts?
> > 
> > Kind Regards,
> > John Fallows.
> > 
> > On 6/20/05, Korhonen, Kalle <kkorhone@cisco.com> wrote:
> > >  
> > >  
> > >  ________________________________
> > >  From: Sylvain Vieujot [mailto:svieujot@apache.org] 
> > > Subject: RE: New "initId" attribute
> > >  
> > > For my specific email problem, sure I could find a solution.
> > > But the problem is that the solution wouldn't be straightforward and would
> > > cause other problems.
> > > Plus it's quite hard to debug as the problem isn't easy to reproduce. It can
> > > also have really bad consequences once in production (as it did for me).
> > > For me, this is problem is really a deficiency of JSF.
> > > The initId is the best solution I've found so far, and it should prevent
> > > other similar bugs.
> > >   
> > > To me, it sounds like you are trying to do a conceptually wrong thing, i.e.
> > > trying to control a mutating list with a static list, and then trying to fix
> > > the problem with applying "glue" to something it wasn't intended for, not an
> > > actual deficiency in the framework. If people would follow the design
> > > principle to create a separate UI list, similar problems wouldn't arise. All
> > > this from my own o-o programming skewed view of the world of course :) 
> > >   
> > > Kalle
> > >  
> > >  
> > >  On Mon, 2005-06-20 at 09:40 -0700, Korhonen, Kalle wrote: 
> > > Ok, I understand that you might have a big problem if the list actually
> > > changes between the requests - but that's something you can control. You
> > > could argue that it shouldn't change between the requests, because it
> > > represents conceptually a different object: a list of items displayed to the
> > > user, not a list of business items that are constantly changing. Couldn't
> > > you make a displayedMails list from your mailsInInbox list and then deal
> > > with the UI list instead of dealing with the back-end list, no? Of course,
> > > the objects themselves wouldn't need to be copied, only references to them,
> > > so performance/memory consumption -wise it shouldn't be that bad. 
> > >  
> > > Kalle 
> > > 
> > >  
> > >  
> > >  ________________________________
> > >  
> > > From: Sylvain Vieujot [mailto:svieujot@apache.org] 
> > > Sent: Monday, June 20, 2005 9:09 AM
> > > To: MyFaces Development
> > > Subject: RE: New "initId" attribute
> > > 
> > > 
> > >  
> > >  
> > > 
> > >  
> > >  
> > > I agree with the general statement, but it just doesn't work 
> > > If you just use <x:selectBooleanCheckbox value="#{email.checked}"/> and
the
> > > emails list changes between your 2 requests, then the action isn't performed
> > > on the proper email.
> > > That's the all problem I'm facing.
> > > 
> > > By default, the id's are attributed according to the row number.
> > > So, using the email's id makes sure that the the email's checkbox matching
> > > is preserved.
> > > Whether we use the a value linked to the business logic or to the ui isn't
> > > the point.
> > > The point is that we have to be able to set an id that is unique for the
> > > given email, and not one that's linked to the email's position in the list.
> > > And to do this, you need to be able to set the checkbox's id with an EL
> > > formula.
> > > 
> > > Note that this is not special to checkbox.
> > > 
> > > Sylvain.
> > > 
> > > On Mon, 2005-06-20 at 08:26 -0700, Korhonen, Kalle wrote: 
> > > Just to comment on the "row numbers required" discussion in general. A
> > > row number is a UI thing and you business logic shouldn't need to care
> > > on which row an object was. You seem to be fixated on identifying the
> > > object based on its row number when a much better practice is to use
> > > unique id of an object for identifying it. If you do that, then your
> > > backend bean also doesn't need to care whether that object was being
> > > displayed on a list or not, it just acts based on the given object id.
> > > If the objects you are displaying don't have a unique id, of course you
> > > can (and should) create a thin wrapper for them in the *back-end* code
> > > that includes a unique id for the objects. The whole point of JSF is to
> > > provide means to clearly separate UI logic from business logic and
> > > generating ids for your objects on the UI doesn't sound like its
> > > following that paradigm too well. Furthermore, the id of the checkbox
> > > shouldn't matter, it's the property that you bind your component value
> > > that matters - and to refer to that property, you should be able and you
> > > *should* use the unique id of the object.
> > > 
> > > As far as I can see, in the mail example you mentioned, you don't need
> > > to worry about unique ids at all. If in your datatable the var name is
> > > "email", the last column could be just:
> > > <h:column>
> > >  <x:selectBooleanCheckbox value="#{email.checked}"/>
> > > </h:column>
> > > 
> > > Then in the delete/move action you would just iterate over the
> > > collection of your mail objects and execute the action on the objects
> > > that have the property "checked" set to true.
> > > 
> > > Kalle
> > > 
> > > 
> > > ________________________________
> > > 
> > >  From: Sylvain Vieujot [mailto:svieujot@apache.org] 
> > >  Sent: Sunday, June 19, 2005 11:35 PM
> > >  To: MyFaces Development
> > >  Cc: craigmcc@apache.org
> > >  Subject: New "initId" attribute
> > >  
> > >  
> > > 
> > >  The new attribute 
> > > 
> > >  The id can't be initialized with an EL expression, and we can't
> > > allow it if we want to keep all chances to pass the TCK tests.
> > >  But the possibility to initialize a component's id with a
> > > runtime computed value is quite crucial (see bellow).
> > >  
> > >  So I propose to add a new attribute for the x: components that
> > > allow the id to be initialized with a VB expression like :
> > >  <x:myFacesComponent initId="CMP_#{rowVar.id}" .../>
> > >  
> > >  This would set the component's id on creation. Once set, the id
> > > is never changed.
> > >  
> > >  
> > > 
> > >  Why we need it 
> > > 
> > >  In dataTables, you sometime need to set the component's ids.
> > >  But as the ids have to be unique, if you can use only constants,
> > > you can't set the ids.
> > >  
> > >  Here is an example where this is highly needed :
> > >  A webmail application displays the inbox with emails received
> > > (last received first).
> > >  On each inbox's row displays the email subject and a checkbox to
> > > be able to delete the email right from the inbox view.
> > >  At the bottom of the page is an update bottom to show the
> > > updated inbox, and to delete checked for delete emails.
> > >  If you check the email on row 3 for deletion and if before you
> > > press the update button, you receive a new email, then when your request
> > > is submitted email #3 is former email #2.
> > >  As the checkbox id's are based on the row number, you end-up
> > > unintentionally deleting the wrong email.
> > >  The best fix to this problem is to set the checkboxes' ids to a
> > > unique string depending upon the email, like : 
> > >  <x:selectBooleanCheckbox initId="Delete_#{email.primaryKey}_CB"
> > > value="#{inboxFace.removeEmailUnid[email.unid]}"/>
> > >  That way, application has no unexpected behavior.
> > >  
> > >  Craig suggested an alternative approach to this particular
> > > problem, involving a hidden field (see bellow).
> > >  I didn't find how to use this, and I'm not sure it's really
> > > feasible.
> > >  Anyway, even if it turns out it could work, it would be a tricky
> > > solution to a commonly found problem.
> > >  Using this initId attribute would be a more elegant and general
> > > solution for this kind of problems.
> > >  
> > >  Any thought ?
> > >  
> > >  Sylvain.
> > >  
> > >  -------- Forwarded Message --------
> > >  From: Sylvain Vieujot <svieujot@apache.org
> > > <mailto:Sylvain%20Vieujot%20%3csvieujot@apache.org%3e> >
> > >  Reply-To: MyFaces Discussion <users@myfaces.apache.org
> > > <mailto:MyFaces%20Discussion%20%3cusers@myfaces.apache.org%3e>
> > > >
> > >  To: craigmcc@apache.org
> > >  Cc: martin@marinschek.com, MyFaces Discussion
> > > <users@myfaces.apache.org
> > > <mailto:MyFaces%20Discussion%20%3cusers@myfaces.apache.org%3e>
> > > >
> > >  Subject: Re: ForcedID is not working
> > >  Date: Mon, 13 Jun 2005 17:51:20 -0400
> > >  
> > >  Hello Craig,
> > >  
> > >  I understand your concern about the TCK tests.
> > >  But I don't see how to use the hidden field you suggest.
> > >  
> > >  In the table, I have a checkbox for each email, and each email
> > > whose check box is checked should be deleted.
> > >  I had a similar problem with a list of images whose titles could
> > > be edited directly in the table.
> > >  I don't see how with a hidden field (or hidden fields) you can
> > > fix the problem.
> > >  
> > >  Could you give me a clue ?
> > >  
> > >  Thanks,
> > >  
> > >  Sylvain.
> > >  
> > >  On Mon, 2005-06-13 at 09:45 -0700, Craig McClanahan wrote: 
> > > 
> > >  On 6/13/05, Sylvain Vieujot <svieujot@apache.org> wrote:
> > >  > I'm just getting in a problem because the id doesn't
> > > support EL right now.
> > >  > 
> > >  > I have a table that displays a webmail inbox.
> > >  > On each row, I have a delete this email checkbox.
> > >  > 
> > >  > It works fine except that it you receive a new email
> > > before you submit your
> > >  > form, the wrong email is deleted, as the checkbox's
> > > name is based on the row
> > >  > number, and the emails have all been shifted one row
> > > down.
> > >  > 
> > >  > The only solution I've found to this (and other
> > > similar) problem(s) is to
> > >  > use the email's id in the checkbox's id :
> > >  > <x:selectBooleanCheckbox id="Delete_#{email.unid}_CB"
> > >  > value="#{inboxFace.removeEmailUnid[email.unid]}"/>
> > >  > 
> > >  > This doesn't work right now, but I think the only
> > > solution to this problem
> > >  > IS TO ALLOW EL in id attributes.
> > >  > 
> > >  > The 1.1 & 1.2PR Spec. section 3.1.4 says that "all
> > > properties other than id
> > >  > and parent, are value binding enabled".
> > >  > But we could partialy enable it. I mean use the value
> > > binding the first
> > >  > time the component's id is used, and then freeze this
> > > value.
> > >  > 
> > >  > Any thoughts ?
> > >  > 
> > >  
> > >  If the TCK inludes tests to verify that "id" is *not*
> > > value binding
> > >  enabled (which wouldn't surprise me since it is a stated
> > > spec
> > >  requirement), then this solution would just have to be
> > > undone again in
> > >  order to pass the tests.
> > >  
> > >  An alternative appropach would be to include a hidden
> > > field in one of
> > >  the columns that contains the information you need to
> > > identify the
> > >  correct model data (the message identifier for a mailbox
> > > screen, for
> > >  example). As decoding occurs and events are fired, the
> > > value of this
> > >  hidden field (along with all the others on the current
> > > row) will have
> > >  been restored to what it was, so that if the checkbox is
> > > checked you
> > >  can go find the relevant message to update or delete.
> > >  
> > >  Craig
> > >  
> > >  > 
> > >  > On Tue, 2005-06-07 at 22:01 +0200, Martin Marinschek
> > > wrote: 
> > >  > rational explanation:
> > >  > 
> > >  > a value in a value-binding can change
> > >  > 
> > >  > - the unique id must stay the same over the whole
> > > lifetime of a view,
> > >  > if not, where will you post the value of an input to
> > > if its id has
> > >  > changed?
> > >  > 
> > >  > regards,
> > >  > 
> > >  > Martin
> > >  > 
> > >  > On 6/7/05, Mike Burati <mburati@bowstreet.com> wrote:
> > >  > > 
> > >  > > > The #{}-expression isn't evaluated in the
> > > id-attribute, why not???
> > >  > > 
> > >  > > The #{} expression support for Value Binding is a
> > > runtime/request-time
> > >  > > facility.
> > >  > > 
> > >  > > The id attributes are used as component identifiers,
> > > by JSF, to build up
> > >  > > a component tree with unique identifiers per naming
> > > container.
> > >  > > 
> > >  > > See Section 3.1 of the JSF1.1 specification for more
> > > information on
> > >  > > component identifiers and value binding. Per the
> > > spec, the id and
> > >  > > parent are the only attributes of the UI components
> > > not enabled for
> > >  > > value binding...
> > >  > > 
> > >  > > 
> > >  > > **********************************
> > >  > > Michael Burati
> > >  > > Senior Software Engineer
> > >  > > Bowstreet
> > >  > > 200 Ames Pond Drive
> > >  > > Tewksbury, MA 01876
> > >  > > T 978-863-1512
> > >  > > F 978-863-1555
> > >  > > www.bowstreet.com
> > >  > > 
> > >  > > Get the latest information on Bowstreet's events and
> > > web seminars.
> > >  > > 
> > >  > > 
> > >  > > 
> > >  > > -----Original Message-----
> > >  > > From: hendrik-neumann@web.de
> > > [mailto:hendrik-neumann@web.de]
> > >  > > Sent: Tuesday, June 07, 2005 3:28 PM
> > >  > > To: MyFaces Discussion
> > >  > > Subject: Re: ForcedID is not working
> > >  > > 
> > >  > > *lol*, thanks I'll give it a try ;)
> > >  > > 
> > >  > > By the way: why can't I do something like <tag
> > >  > > id="category-#{node.identifier}" />
> > >  > > 
> > >  > > The #{}-expression isn't evaluated in the
> > > id-attribute, why not???
> > >  > > 
> > >  > > Am Dienstag, 7. Juni 2005 20:03 schrieb Korhonen,
> > > Kalle:
> > >  > > > true to
> > >  > > > guide MyFaces to leave the id as is, to whatever
> > > you've set it to.
> > >  > > > Granted, the name is misleading IMHO as well.
> > >  > >
> > >  > 
> > >  >
> > >  
> > > 
> > >

Mime
View raw message