You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Andrew Robinson <an...@gmail.com> on 2006/04/17 19:06:32 UTC

Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

Okay, I had to make a workaround and posting this here as an FYI to
anyone who wants to do the same (or if someone has a better idea). The
problem is the the default HtmlDataScroller sets the first to a
integer. I needed the ability to have an EL expression so I could
get/set this value in a backing bean.

In the JSF I had:

<t:dataTable first="#{bean.firstRow}"

This worked fine until the data scroller was used. The EL expression
was never used again since the UIData now had a "local" value of
first.

Here is my workaround so that EL would always be used for first.

1) create a new class that extends
org.apache.myfaces.component.html.ext.HtmlDataTable
2) Override setFirst:
  @Override
  public void setFirst(int first)
  {
    ValueBinding vb = getValueBinding("first");
    if (vb != null)
    {
      vb.setValue(getFacesContext(), first);
      return;
    }
    else
      super.setFirst(first);
  }

3) created a new tag in my taglib.xml file (this is because I don't
want all tables to behave this way)
4) set the new tag's component type to a new type
5) registered the new tag's component type in my faces-config.xml to
point to the new component

Now the value is always set on my backing-bean and always retrieved
from my backing bean. Therefore, I can have code in the
actionListener/action that is able to change the first row of the
UIData without using component binding.

-Andrew

Re: Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

Posted by Andrew Robinson <an...@gmail.com>.
I presume you modified your faces-config.xml to tell JSF to use your
component instead of HtmlDataTable? Example (note, I use facelets, and
if you don't you will also probably need to subclass the tag as well):

  <component>
    <component-type>com.somecompany.ExtendedELTable</component-type>
    <component-class>com.somecompany.ExtendedELUIData</component-class>
  </component>

custom.taglib.xml:
...
  <tag>
    <tag-name>dataTableEl</tag-name>
    <component>
      <component-type>com.somecompany.ExtendedELTable</component-type>
      <renderer-type>org.apache.myfaces.Table</renderer-type>
    </component>
  </tag>
...

Java:

public class ExtendedELUIData
  extends HtmlDataTable
{
  /**
   * @see javax.faces.component.UIData#setFirst(int)
   */
  @Override
  public void setFirst(int first)
  {
    ValueBinding vb = getValueBinding("first");
    if (vb != null)
    {
      vb.setValue(getFacesContext(), first);
      return;
    }
    else
      super.setFirst(first);
  }
}

That should be all that you need. You can add a System.out in your
constructor to make sure you component is getting created. Also check
the logs to make sure your component is getting used.

-Andrew

On 5/1/06, agdibugdi <sa...@avaya.com> wrote:
>
> I extended HtmlDataTable with the override function for setFirst ( as
> suggested), but it never got executed.
>
> <snip>
> <x:dataTable id="resourceData" var="MR"
>         value="#{MR.resources}" rows="10"
>         columnClasses="columnspacer_5,leftcolumn,leftcolumn"
>         headerClass="sortHeader" rowClasses="oddrow, evenrow" width="100%"
>         sortColumn="#{MR.sort}"
>         sortAscending="#{MR.ascending}"
>         preserveDataModel="true" preserveSort="true"
>         first="#{MR.searchPageIndex}"
>         binding="#{MR.mrDataTable}">
> </snip>
>
> Any Help ?
> Is it possible to post the code ?
>
> Thanks a bunch,
>
> vinod
> --
> View this message in context: http://www.nabble.com/Making-sure-DataTable%27s-first-always-uses-EL-was-Re%3A-Facelets-1.0.14-causes-duplicate-IDs...-t1462743.html#a4172242
> Sent from the MyFaces - Users forum at Nabble.com.
>
>

Re: Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

Posted by agdibugdi <sa...@avaya.com>.
I extended HtmlDataTable with the override function for setFirst ( as
suggested), but it never got executed.

<snip>
<x:dataTable id="resourceData" var="MR"	
	value="#{MR.resources}" rows="10"
	columnClasses="columnspacer_5,leftcolumn,leftcolumn"
	headerClass="sortHeader" rowClasses="oddrow, evenrow" width="100%"
	sortColumn="#{MR.sort}"
	sortAscending="#{MR.ascending}"
	preserveDataModel="true" preserveSort="true"
	first="#{MR.searchPageIndex}"
	binding="#{MR.mrDataTable}">
</snip>

Any Help ?
Is it possible to post the code ?

Thanks a bunch,

vinod
--
View this message in context: http://www.nabble.com/Making-sure-DataTable%27s-first-always-uses-EL-was-Re%3A-Facelets-1.0.14-causes-duplicate-IDs...-t1462743.html#a4172242
Sent from the MyFaces - Users forum at Nabble.com.


Re: Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

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

JSF has this concept of an EditableValueHolder - only components
implementing this interface really change the value of the backing
bean they belong to. All other values are just fetched from the
backing bean, but never set to the backing bean.

There is more to it then just setting the backing bean value - the
question is in what phase to set this, what will happen on repost,
decode, validation, etc. The EditableValueHolder interface takes care
of this for the component value, it doesn't for each of the properties
of the component.

regards,

Martin

On 4/17/06, Andrew Robinson <an...@gmail.com> wrote:
> That is the way it behaves. My problem was how HtmlDataScroller interacts
> with HtmlDataTable for the functionality I needed.
>
> THe HtmlDataScroller calls the setFirst(new Integer(#)) method on UIData
> (HtmlDataTable). This erases the EL binding of the HtmlDataTable's first
> attribute.
>
> UIData:
> public int getFirst()
> {
>  if (_first != null) return first.intValue();
> ...
> }
>
> So, I wanted the "_first" to be always null (I always wanted the first to
> come from my backing bean, even after the data scroller had been used).
> Therefore, by extending the HtmlDataTable, I could see if the attribute was
> value bound, and if so, set the value using that value binding instead of
> retaining the integer value passed in. So for my custom circumstance, I
> never wanted _first to come from an integer, instead I wanted it to come
> from my EL expression and get set via my EL expression.
>
> Summary:
> There is nothing wrong with the datascroller. The only "short comming" is
> that it stops value binding expressions from being evaluated on the table
> once it sets a value on the table due to the way the attributes are checked.
>
> Question:
> In property getters of components, the code looks like (taken from UIData):
>         if (_rows != null)
>             return _rows.intValue();
>         ValueBinding vb = getValueBinding("rows");
>         Number v = vb != null ? (Number) vb.getValue(getFacesContext()) :
> null;
>         return v != null ? v.intValue() : DEFAULT_ROWS;
>
> In the set method, it simply has:
>         _rows = new Integer(rows);
>         if (rows < 0)
>             throw new IllegalArgumentException("rows: " + rows);
>
> Out of curiosity why is this not:
> Getter:
>         ValueBinding vb = getValueBinding("rows");
>          Number v = vb != null ? (Number) vb.getValue(getFacesContext()) :
> null;
>          return v != null ? v.intValue() : (_rows != null) ?
> _rows.intValue() : DEFAULT_ROWS;
>  Setter:
>         ValueBinding vb = getValueBinding("rows");
>         if (vb != null)
>           vb.setValue(getFacesContext(), rows);
>         else
>         {
>           _rows = new Integer(rows);
>            if (rows < 0)
>                throw new IllegalArgumentException("rows: " + rows);
>         }
>
> This way, if the component is bound using EL, anyone setting the value sets
> the value of the value expression instead of overriding the value with a
> static value?
>
> I'm sure there is a good reason, but I can't think of one off the top of my
> head besides the fact that not all properties have the ability to set (which
> could be coded around I'm sure).
>
> -Andrew
>
>
> On 4/17/06, Mike Kienenberger <mk...@gmail.com> wrote:
> > On 4/17/06, Andrew Robinson <an...@gmail.com> wrote:
> > > Okay, I had to make a workaround and posting this here as an FYI to
> > > anyone who wants to do the same (or if someone has a better idea). The
> > > problem is the the default HtmlDataScroller sets the first to a
> > > integer. I needed the ability to have an EL expression so I could
> > > get/set this value in a backing bean.
> > > [...]
> > > Here is my workaround so that EL would always be used for first.
> > >
> > > 1) create a new class that extends
> > > org.apache.myfaces.component.html.ext.HtmlDataTable
> > > 2) Override setFirst:
> > >   @Override
> > >   public void setFirst(int first)
> > >   {
> > >     ValueBinding vb = getValueBinding("first");
> > >     if (vb != null)
> > >     {
> > >       vb.setValue(getFacesContext(), first);
> > >       return;
> > >     }
> > >     else
> > >       super.setFirst(first);
> > >   }
> >
> > The way we've typically handled this situation of
> > EL-expression-or-constant in other attributes is:
> >
> >     public String getOperator()
> >     {
> >         if (_operator != null) return _operator;
> >         ValueBinding vb = getValueBinding("operator");
> >         return vb != null ?
> > _ComponentUtils.getStringValue(getFacesContext(), vb) :
> null;
> >     }
> >
> >     public void setOperator(String operator)
> >     {
> >         this._operator = operator;
> >     }
> >
> > Then in the component code, we only use "getOperator()" rather than
> > directly access the _operator instance variable.
> >
> > If datascroller isn't working this way, please open a JIRA issue with
> > a similar patch.
> >
>
>


--

http://www.irian.at

Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German

Professional Support for Apache MyFaces

Re: Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

Posted by Andrew Robinson <an...@gmail.com>.
That is the way it behaves. My problem was how HtmlDataScroller interacts
with HtmlDataTable for the functionality I needed.

THe HtmlDataScroller calls the setFirst(new Integer(#)) method on UIData
(HtmlDataTable). This erases the EL binding of the HtmlDataTable's first
attribute.

UIData:
public int getFirst()
{
 if (_first != null) return first.intValue();
...
}

So, I wanted the "_first" to be always null (I always wanted the first to
come from my backing bean, even after the data scroller had been used).
Therefore, by extending the HtmlDataTable, I could see if the attribute was
value bound, and if so, set the value using that value binding instead of
retaining the integer value passed in. So for my custom circumstance, I
never wanted _first to come from an integer, instead I wanted it to come
from my EL expression and get set via my EL expression.

Summary:
There is nothing wrong with the datascroller. The only "short comming" is
that it stops value binding expressions from being evaluated on the table
once it sets a value on the table due to the way the attributes are checked.

Question:
In property getters of components, the code looks like (taken from UIData):
        if (_rows != null)
            return _rows.intValue();
        ValueBinding vb = getValueBinding("rows");
        Number v = vb != null ? (Number) vb.getValue(getFacesContext()) :
null;
        return v != null ? v.intValue() : DEFAULT_ROWS;

In the set method, it simply has:
        _rows = new Integer(rows);
        if (rows < 0)
            throw new IllegalArgumentException("rows: " + rows);

Out of curiosity why is this not:
Getter:
        ValueBinding vb = getValueBinding("rows");
        Number v = vb != null ? (Number) vb.getValue(getFacesContext()) :
null;
        return v != null ? v.intValue() : (_rows != null) ? _rows.intValue()
: DEFAULT_ROWS;
Setter:
        ValueBinding vb = getValueBinding("rows");
        if (vb != null)
          vb.setValue(getFacesContext(), rows);
        else
        {
          _rows = new Integer(rows);
          if (rows < 0)
              throw new IllegalArgumentException("rows: " + rows);
        }

This way, if the component is bound using EL, anyone setting the value sets
the value of the value expression instead of overriding the value with a
static value?

I'm sure there is a good reason, but I can't think of one off the top of my
head besides the fact that not all properties have the ability to set (which
could be coded around I'm sure).

-Andrew

On 4/17/06, Mike Kienenberger <mk...@gmail.com> wrote:
>
> On 4/17/06, Andrew Robinson <an...@gmail.com> wrote:
> > Okay, I had to make a workaround and posting this here as an FYI to
> > anyone who wants to do the same (or if someone has a better idea). The
> > problem is the the default HtmlDataScroller sets the first to a
> > integer. I needed the ability to have an EL expression so I could
> > get/set this value in a backing bean.
> > [...]
> > Here is my workaround so that EL would always be used for first.
> >
> > 1) create a new class that extends
> > org.apache.myfaces.component.html.ext.HtmlDataTable
> > 2) Override setFirst:
> >   @Override
> >   public void setFirst(int first)
> >   {
> >     ValueBinding vb = getValueBinding("first");
> >     if (vb != null)
> >     {
> >       vb.setValue(getFacesContext(), first);
> >       return;
> >     }
> >     else
> >       super.setFirst(first);
> >   }
>
> The way we've typically handled this situation of
> EL-expression-or-constant in other attributes is:
>
>     public String getOperator()
>     {
>         if (_operator != null) return _operator;
>         ValueBinding vb = getValueBinding("operator");
>         return vb != null ?
> _ComponentUtils.getStringValue(getFacesContext(), vb) : null;
>     }
>
>     public void setOperator(String operator)
>     {
>         this._operator = operator;
>     }
>
> Then in the component code, we only use "getOperator()" rather than
> directly access the _operator instance variable.
>
> If datascroller isn't working this way, please open a JIRA issue with
> a similar patch.
>

Re: Making sure DataTable's first always uses EL [was] Re: Facelets 1.0.14 causes duplicate IDs...

Posted by Mike Kienenberger <mk...@gmail.com>.
On 4/17/06, Andrew Robinson <an...@gmail.com> wrote:
> Okay, I had to make a workaround and posting this here as an FYI to
> anyone who wants to do the same (or if someone has a better idea). The
> problem is the the default HtmlDataScroller sets the first to a
> integer. I needed the ability to have an EL expression so I could
> get/set this value in a backing bean.
> [...]
> Here is my workaround so that EL would always be used for first.
>
> 1) create a new class that extends
> org.apache.myfaces.component.html.ext.HtmlDataTable
> 2) Override setFirst:
>   @Override
>   public void setFirst(int first)
>   {
>     ValueBinding vb = getValueBinding("first");
>     if (vb != null)
>     {
>       vb.setValue(getFacesContext(), first);
>       return;
>     }
>     else
>       super.setFirst(first);
>   }

The way we've typically handled this situation of
EL-expression-or-constant in other attributes is:

    public String getOperator()
    {
        if (_operator != null) return _operator;
        ValueBinding vb = getValueBinding("operator");
        return vb != null ?
_ComponentUtils.getStringValue(getFacesContext(), vb) : null;
    }

    public void setOperator(String operator)
    {
        this._operator = operator;
    }

Then in the component code, we only use "getOperator()" rather than
directly access the _operator instance variable.

If datascroller isn't working this way, please open a JIRA issue with
a similar patch.