Actually, that is likely the correct URL.   The stuff on the end-- the #.#.#.#
stuff-- is the element ID portion of the URL.

As WebObjects renders a particular "page", it starts at the application, then
session, then top level component, then all sub-components/elements and calls
-appendToResponse:inContext: on each.

The order in which each component/element is invoked/rendered is depth-first.  That
is, it invokes teh method on the outermost component.  Then that component invokes
it on the first element contained within... that component or element invokes on
the first contained within, etc... When the "bottom" is hit, i.e. when a component
or element with no children is hit, the parent component then invokes
-appendToResponse:inContext: on the NEXT contained element or component.  This
continues until all elements/components are visited.

The same thing happens for -takeValuesFromRequest and -invokeActionForRequest;   in
all three cases, WO does a depth first traversal of the elements/components.

Consider a page with a Main component that contains a nav bar with three items in a
repetition and a search component (both the nav bar and the search component are
contained in Main).

The element ID and element/component traversal would look like (for all three
phases of request/response):

Main:    0
NavBar:    0.0
First Repetition:    0.0.0
First Hyperlink In Rep:    0.0.0.0
Second Repetition:    0.0.1
Second Item In Rep:    0.0.1.0
Third Repetition:    0.0.2
Third Item In Rep:    0.0.2.0
Search Component:    0.1
Field In Search:    0.1.0
Check box in search:    0.1.1
Submit Button In Search:    0.1.2

(as you can see, even things that don't emit HTML may affect the element ID-- like
the repetition in the above example)

When the values are consumed from a request, each element/component has the same
element ID.  This is how WO figures out that the value entered into the field by
the user should be assigned to some variable in your component (simplistic view--
see below).

With action processing, WO keeps traversing the component/elements as it would
above until it finds the element that has the same element ID as the hyperlink.
When it does, that elements action method is invoked-- this is how a repetition can
tell that the second item was clicked-- the element ID indicates as much.

Advanced Concepts:

(1) Request/Response is only appropriate when considering things like memory
management and other aspects of the NSRunLoop.   It is also useful to think of it
as a Response/Request loop.  That is, WO generates a response, processes the
request and, finally, invokes the action all based on the state set up in the
response.   As such, it is quite evil to change the value of, say, a Conditional or
Repetition as part of -takeValuesFromRequest:-- if you do so and the hyperlink the
user clicked was INSIDE the rep or conditional, it is likely that -invokeAction...
won't find it!

In terms of a normal GUI application, you typically:
- update the display with current state
- wait for user input
- digest user input
- respond to user input
- update current state
- repeat ad infinitum

The web works the same way except that the "wait for user input" may take minutes
or even hours between events (instead of miliseconds) and may involve many
hundrends of bits of input (instead of discrete events).   The other key difference
is that "wait for user input" may actually mean that the user has gone away
entirely-- i.e. there is no positive feedback.

(2) In WO 4.0, there has been considerable optimization to this process.  In take
values and invoke action, it is common for elements and components to be skipped
entirely because they are known to not be a part of that phase of event
processing.   For example, there is no point in calling -takeValues on a
WOString... it only emits values to the user!  Likewise, there is no point in
calling -invokeAction on the all-but-one element in a WORepetition-- the element ID
in the URL indicates exactly which element in the requesting URL is the candidate
for action processing.

(3) - invokeActionForRequest:inContext: does not necessarily invoke the action!  It
will only do so if the element ID of the thing executing the
-invokeActionForRequest:inContext: method matches the element ID in the incoming
request.   If it doesn't, and the thing in question CONTAINS other
elements/components, it may invoke -invokeActionForRequest:inContext: on the
children elements (and they will test).  By doing this, -ivokeAction... works just
like -takeValues and -appendToResponse.

(4) WO will NOT stop searching for something to invoke an action on until it sees a
non-nil return value from an -invokeActionForRequest:inContext:.   This is why it
is a BUG to "return nil;" from an action method to have the same page re-render
itself.  WO will happily continue looking for something to invoke the action on.
If your action method does something like:

- myAction
{
    ... delete objects from various arrays/containers ...
    return nil; // update same page with new contents
}

WO may continue to try and traverse the arrays/containers and can very likely walk
off the end of one and generate an exception.

Instead, return [[self context] page];   This does the same thing as return nil,
but also terminates action processing!

(5) related to (4) and (3) and (1).  Do NOT modify the state of your application in
either -takeValuesFromRequest:.   By doing so, you run the risk of causing a
different componet/element traversal order and causing -invokeactionforrequest to
not fire the action or to misfire the WRONG action.

(6) like (5), but more subtle.  Do NOT modify the state of your application in
-appendToResponse:inContext: AFTER invoking super's -appendToResponse:inContext:.
It is tempting to do:

- appendToResponse: r inContext: c
{
    .... set up some instance variables based on session state ...
    displayArray = [session ...];
    [super appendToResponse: r inContext: c];
    ... set instance variables to nil, etc...
    displayArray = nil;
}

Remember, -takeValues and -invokeAction expect the state of the components to be
the same.   Likely, displayArray was used in a repetition.... by setting it to nil
in the last line, it will be nil for takeValues and invokeAction and something very
wrong will happen.

hope that helps,
b.bum

Michael Brian Bentley wrote:

> Hi,
>
> Is there a wierd thing with buttons in the NT WO4? If I click on a
> hyperlink, it takes me to:
>
> http://localhost:8765/scripts/WebObjects.exe/myApp.woa/wo/F00000RN400aE1002/
> 0.1.10.2
>
> If I click on a button (in the underlying form, multipleSubmit = "YES",
> btw), it tries to take me to:
>
> http://localhost:8765/scripts/WebObjects.exe/myApp.woa/wo/F00000RN400aE1002/0.1
>
> Sorta looks like it lops off the tail end in the second case.
>
> The two objects use the same action procedure.
>
> ??
>
> -mike

Reply via email to