Hi

Finally I have found a way to handle the POST case. Take a look at this
example, written using jQuery:

<form jsf:id="mainForm">

    <input jsf:id="suggest" type="text" jsf:value="#{sayHelloBean.firstName}"/>

    <script type="text/javascript">
    $(document.getElementById("#{ma:clientId('suggest')}")).autocomplete({
        source: function (request, response) {
            $.post( "#{ma:sourceActionURL('renderOptions')}" ,
            $(document.getElementById("#{ma:parentFormId()}")).serialize(),
response);
        }
    });
    </script>

    <ma:defineAction id="renderOptions"
                     action="#{sayHelloBean.renderJSONForAutoComplete}"
                     execute="@form">
    </ma:defineAction>

</form>

First there is a JSF text input component, and below there are two parts: One
is the jQuery script that enables it as an autocomplete box and then there is
a component called ma:defineAction, which has the purpose to bind the
action, in this case render some JSON with the javascript using EL.

There are some EL functions:

#{ma:sourceActionURL('renderOptions') : render the URL of the action.
#{ma:clientId('suggest') : get the client id of the input component.
#{ma:parentFormId() : get the id of the closest parent form.

There is no any additional javascript function or library, so the POST is
done by jQuery.

This strategy has the following advantages/disadvantages:

* The final code can be easily reused. The EL functions help to fill the
gaps between the component tree and the client ids with the javascript, so
you can just copy/paste or encapsulate the code inside a composite
component.

* The component <ma:defineAction ...> helps to deal with the lifecycle
logic. For example, the "execute" attribute helps to define which
components need to be processed by the lifecycle before perform the action.
In this case, you can just take the value from the managed bean to render
the JSON according to the needs. The idea is also add a parameter called
<ma:actionParam> to send additional parameters in the action and process
them as f:viewParam does.

* The user has complete control about which params should be send with
each action from the javascript client. This has some risk because at the
same time JSF lose control, it is more likely the user send the wrong
parameters, or that could make the code a bit unstable if a new hidden
param for the context is added in the future.

* Since the action is defined in the view, the view must be restored
in order to process the action. That means javax.faces.ViewState and
javax.faces.ClientWindow parameters must be sent with the request. But
that also means the user should ensure the javascript code send the
params as well.

* The view state is not updated on the client, so changes done in the
component tree will not be saved and restored later. This can be a
disadvantage, but if you need to change something on the component tree
the workaround is execute the POST first and once the response has been
generated, send an ajax request to do the changes in the component tree.
This is the best we can do for the moment, to do something better it
should be done at spec level.

* If the view state is not updated on the client, if the view scope
is used by first time the view state will not hold the identifier for
the new view scope and the bean will not be saved. The solution is force
the view scope creation, maybe with a parameter in the action.


I think we can do something similar to what we used for @ViewAction in
the action. For example in #{sayHelloBean.renderJSONForAutoComplete}
we can write something like this on the bean:

    public ActionResponse renderJSONForAutoComplete()
    {
        return new TextResponse("[\"Option A\", \"Option B\"]",
                         "UTF-8", "application/json");
    }

or you can write it using externalContext methods if you want.

In my personal opinion, this looks good enough to continue. The next step
is write a functional prototype with some examples. It could be more ideas
to do in this part and more use cases but I consider what we have here
is enough to deal with most important or interesting cases.
Let's see what happen.

regards,

Leonardo Uribe

2014-05-15 12:43 GMT+02:00 Leonardo Uribe <lu4...@gmail.com>:
> Hi
>
> 2014-05-13 20:31 GMT+02:00 Dora Rajappan <dorarajap...@yahoo.com>:
> DR> How will  <a href="#{ma:getLink('mypage?action=exportExcel')}">Export
> DR> excel</a>
> DR> work when ViewAction is not defined as
> DR>
> DR> @ViewAction(value="/sayhello.xhtml",
> DR>                           params= {
> DR>                               @ViewParam(name="action",
> DR> expectedValue="exportExcel")
> DR>                           })
> DR>     public void method3(@ViewParam String param1,
> DR> @ViewParam("someOther") Integer param2)
> DR>     {
> DR> but  as @ViewAction("/section1/*", action="exportExcel")
> DR> Is the latter not supported now?
> DR>
>
> Good question. The idea is if you have two views on the same folder:
>
> /section1/page1.xhtml
> /section1/page2.xhtml
>
> The action will be added to both pages so it will be valid to call
>
> /section1/page1.xhtml?action=exportExcel or
> /section1/page2.xhtml?action=exportExcel.
>
> but if the page does not exists, the action will not be valid. So
> if the user calls
>
> /section1/nonexistentpage.xhtml?action=exportExcel
>
> nothing will happen.
>
> But if the user declares an action to a page that do not exists as a
> file in the path, for example:
>
> @ViewAction(value="/page_not_on_webapp_folder.xhtml",
>
> The logic will create an blank page with the view action and the
> view params declared. I have already tried it and it works well, it is
> useful in some cases when you need to include some logic before
> go into the real page, and with this you don't have to create it
> on the webapp folder. This logic is handled by a VDL wrapper.
>
> DR> facelet function getLink for action processing is not a bad idea.
>
> I think so too. It is simple to understand, but in some cases getLink(...)
> is not enough, for example when you have 2 or more parameters to
> include in the link, and you need to add some extra logic. In that
> case, a 2 step approach using a component and getLinkFrom(...)
> looks more clean and flexible. Note there is no way to add variable
> parameters with facelets EL functions, so an extended getLink(...)
> is not possible.
>
> regards,
>
> Leonardo
>
>> On Sunday, May 11, 2014 11:52 PM, Leonardo Uribe <lu4...@gmail.com> wrote:
>> Hi
>>
>> Ok, I think the idea about @ViewAction and @ViewParam is clear, I have
>> implemented a fast prototype and it works well, there is a lot of things we
>> can do for improvement, however we should focus the attention in other
>> areas so we can give the module a better structure.
>>
>> The next thing we need is how to combine javascript with JSF, specifically
>> in cases like this:
>>
>> <input id="search"/>
>> <script type="text/javascript">
>>     $('#search').autocomplete({
>>         source: "#{some EL that return a link to an action goes here}"
>>     });
>> </script>
>>
>> The idea is provide an input box and then write some javascript lines to
>> make the component an autocomplete box, but the problem is we need to
>> provide
>> a URL that can be used to retrieve the values to fill the box. In my
>> opinion,
>> mix EL and javascript is the best in these cases, but things get complex
>> quickly when you need to provide parameters and so on. So I would like to
>> propose these facelet functions (better with examples):
>>
>>     <a href="#{ma:getLink('mypage?action=exportExcel')}">Export excel</a>
>>
>> and
>>
>>     <ma:defineLink id="mylink">
>>         <f:param name="action" value="renderMessage"/>
>>     </ma:defineLink>
>>
>>     <a href="#{ma:getLinkFrom('mylink')}">Render url from EL expression</a>
>>
>> #{ma:getLink(...)} work just like h:link but receives the outcome as
>> parameter.
>> The function append the request path and the client window id, so the final
>> generated link will be something like this:
>>
>> http://localhost:8080/myfaces-mvc-examples/sayhello.jsf?id=5&jfwid=1di8uhetf9&action=exportExcel
>>
>> #{ma:getLinkFrom(...)} just inject the link from a component that works just
>> like h:link but it is just a wrapper, so the user can customize the
>> parameters,
>> when the EL function is called, the link is rendered taking the parameters
>> in the definition. The outcome by default is the page itself.
>>
>>
>> Please note this proposal is something different from the one that suggest
>> to
>> create the link just pointing to the method in the bean like
>> #{ma:getLink('mybean', 'mymethod', params)}. After thinking about it, the
>> problem with that approach is the difficulty to do the match between the
>> link
>> to generate and the method. EL does not consider annotated methods, so it is
>> not possible to scan the annotations from the EL unless you do a bypass over
>> CDI.
>>
>> I think the approach proposed is something simple to understand, and it has
>> the advantage that you can isolate the declaration of the link from the
>> rendering, so the final javascript code will be easier to read.
>>
>> Finally we need something for the POST case, so the idea is append something
>> like this:
>>
>>     <form action="#{ma:encodeActionURL()}"
>>           method="post"
>>           enctype="application/x-www-form-urlencoded">
>>         ....
>>     </form>
>>
>> #{ma:encodeActionURL()} do what h:form does for encode the action url. Then,
>> it is responsibility of the user to provide the view state and client window
>> token in the request as data, so the postback can be processed properly.
>> In this case, the idea is the view scope will be available, but the
>> component
>> tree state will not be updated when POST goes back to the client, so any
>> changes on the component tree in the action will be ignored.
>>
>> JSF does not make any difference between GET and POST, so viewParam will
>> work just the same. What defines a postback in JSF is if the view state
>> field is in the request or not. Theoretically, use #{ma:getLink(...)} should
>> work too, but I think there are different cases.
>>
>> There is a contradiction in this case. Send a POST, provide the view state
>> token, do not restore the view but restore the view scope bean. The problem
>> is
>> after you make changes on the view scope beans you need to save those
>> changes,
>> and that could mean update the view state token, even if the beans are
>> stored
>> in the server (remember the beans can be serialized, for example in a
>> cluster).
>>
>> If we take a look at the proposed goals:
>>
>> 1) possibility to use a normal JSF lifecycle for the first GET request
>> 2) allow action handling and custom response for POST actions
>> 3) normal action handling like in asp.net MVC + a EL util function to
>> generate the action URL
>>
>> we cannot really make number 2 exactly as POST actions. It doesn't fit
>> because
>> "... JSF’s core architecture is designed to be independent of specific
>> protocols and markup. ...".
>>
>> Really the problem proposed in number 2 is not simple and we should analyze
>> it
>> carefully. In which cases do we really need that kind of action handling? If
>> we are thinking for example in a JSF component that defines an endpoint with
>> a
>> custom response (for example a captcha component), we need a component
>> oriented
>> solution, something closer as what we have for ajax. What we have proposed
>> here with @ViewAction works in the case the user needs to define an endpoint
>> at the "page" level.
>>
>> Really the big problem is how to hook the javascript code, so the updates of
>> the view state on the client side can be properly chained. For example in
>> MyFaces there is a queue for all ajax request, but we need that the actions
>> sent that requires update the view state can be synchronized with that
>> ajax queue too.
>>
>> I think what we have already is enough useful for a module. After all, we
>> don't need to solve all the problems at once.
>>
>> Suggestions are welcomed.
>>
>> regards,
>>
>> Leonardo Uribe
>>
>> 2014-05-05 0:05 GMT+02:00 Leonardo Uribe <lu4...@gmail.com>:
>>> Hi Thomas
>>>
>>> TA>> AFAIR now, your solutions seems to be just a replacement for
>>> f:viewAction
>>> TA>> + allow different handlers via URL parameters.
>>> TA>> Its sound really lightweight and easy actually :)
>>> TA>> Does it cover all our requirements from the earlier mails?
>>> TA>>
>>>
>>> I think so, but we need to write some examples to be sure that the syntax
>>> cover
>>> all cases.
>>>
>>> Instead put a Front Controller on top of the lifecycle, we can go with
>>> this approach
>>> and provide some methods to call JSF algorithm inline. We already have
>>> some
>>> code in VDL.createComponent(...) that does inline compilation, so it
>>> is not really
>>> hard to write the necessary lines to do so (if the code is properly
>>> implemented
>>> of course). The idea could be provide something like:
>>>
>>> JSFUtils.generatePage("/mypage.xhtml", ....)
>>>
>>> and internally we call the algorithm, and deal with the potential
>>> problems.
>>>
>>> So, if the user really wants to go with a MVC framework and use JSF as
>>> template
>>> engine, it will be as simple as write the adapter for the framework.
>>> We should not
>>> reinvent the wheel in this case. So, all other cases not supported by
>>> f:viewAction/f:viewParam, which should be very, very few, should be done
>>> writing
>>> a servlet or using an MVC framework like JAX-RS, and if necessary calling
>>> JSF at render time.
>>>
>>> The nice part about reuse f:viewAction logic is that is something
>>> proved, everybody
>>> knows how it works, we are just extending the syntax to define
>>> f:viewAction in
>>> a more familiar way. In practice we need to write a custom component
>>> extending
>>> UIViewAction, but that's something easy, I have already done it and it
>>> works.
>>>
>>> That should cover most of the cases. There are other cases that are
>>> indirectly
>>> related to this one, but after some review, it doesn't seem to be so
>>> interesting
>>> or useful, or can be too complex to implement properly, so we need to
>>> wait and push
>>> it into the next spec. Sometimes less is more. Let's see what happen.
>>>
>>>>> Whats the syntax for multiple params? ->
>>>>> params="action=exportExcel&someOther=string"?
>>>>> Maybe we could think about a more typesafe and readable way. e.g.
>>>>>
>>>>> @ViewAction(value="my.xhtml", params = {
>>>>>      @ViewParam(name="action", value="exportExcel"),
>>>>>      @ViewParam(name="someOther", value="string")
>>>>> })
>>>
>>> I was thinking about this:
>>>
>>>    @ViewAction(value="/sayhello.xhtml", params="action=exportExcel")
>>>    public void method3(@ViewParam String param1,
>>> @ViewParam("someOther") Integer param2)
>>>    {
>>>
>>> The method has two parts: one define the parameters that should be present
>>> and the other define the activation conditions, in this case, when
>>> action=exportExcel. Please note to make @ViewParam("someOther"), we
>>> need to associate value to the key name. So we could do something
>>> like this:
>>>
>>>    @ViewAction(value="/sayhello.xhtml",
>>>                          params= {
>>>                                @ViewParam(name="action",
>>> expectedValue="exportExcel")
>>>                          })
>>>    public void method3(@ViewParam String param1,
>>> @ViewParam("someOther") Integer param2)
>>>    {
>>>
>>> I think in this way it looks better. Thanks for the suggestion.
>>>
>>> regards,
>>>
>>> Leonardo
>>
>>

Reply via email to