Geoff, I always try to follow you suggested pattern, but unfortunately I
don't think it's always possible. I'd like to present a use case scenario
and perhaps maybe you guys can break me out of my current design rut.

*Use case 1*

1. My navigation bar is contained within my layout component which is
available to all pages. The navigation bar contains an ajax link called
login. When the user clicks the login link, it triggers an event in the
layout.java called onShowLoginRegister.

Layout.java

public void onShowLoginRegister() {
        function = Function.LOGIN;

        if (request.isXHR()) {
            ajaxResponseRenderer.addRender(loginRegisterModalZone);
        }
}

2. Also contained within layout is a component called LoginRegister which
is nested within a modal dialog box surrounded by a zone which is triggered
by the onShowLoginRegister response.

<t:zone t:id="loginRegisterModalZone">
        <t:if test="isFunction('login')">
            <t:modaldialog title="Sign in or Register" modalId="loginModal">
                <t:loginregister/>
            </t:modaldialog>
        </t:if>
</t:zone>

3. LoginRegister contains all the authentication code enabling users to log
in inline despite what page they may be on.
4. When the user has been successfully authenticated, I then trigger
another event in the layout to close the LoginRegister modal dialog as well
as update the the user name in the navbar via a zone.

LoginRegister.java

Object onSuccessFromLoginForm() {
        // We want to tell our containing page explicitly what person we've
updated, so we trigger a new event with a
        // parameter. It will bubble up because we don't have a handler
method for it.
        componentResources.triggerEvent(LOGIN, null, null);

        // We don't want the original event to bubble up, so we return true
to
        // say we've handled it.
        return true;
 }

Layout.java

void onLoginFromLoginRegister() {
        modalDialog.hide();

        if (request.isXHR()) {

ajaxResponseRenderer.addRender(loginRegisterModalZone).addRender(loginNavZone);
        }
}

So far everything works perfectly. Now comes the tricky part, updating page
content.

Now lets say I'm on a page that has actions or other content hidden to a
non authenticated user. When I log in through my loginregister modal
dialog, not only do I need to update the username contained within the
layout navbar component, I also need to update a zone contained within the
page to show actions now available to the authenticated user. Now I know
you say everything should be controlled through the page, but in this
scenario the event is being fired from the navbar contained within the
layout component.

MyPage.tml

<t:layout>
    //actionZone should be triggered when the user has been successfully
authenticated by loginregister. Ideally it should be updated with
ajaxResponseRenderer within onLoginFromLoginRegister()
   <t:zone t:id="actionZone">
        <t:if test="authenticated">
             //some actions that need to be displayed to authenticated
users.
        </t:if>
   </t:zone>
</t:layout

How would you recommend updating a zone within the page? If I moved the
LoginRegister into the page, I would then be required to have to do that to
every page in the application which seems like the wrong approach.

*Use case 2*

1. Now my last use case might be an instance where an action contained
within a page or component requires authentication. When you click the
action, I need to fire the onShowLoginRegister() event contained within
layout.
Example, When a user starts to post a new listing, but have yet to login or
register a new account. When the user completes the creation of their
listing, prior to saving the listing to the database I prompted the
LoginRegister dialog box for them to either login in or create a new
account. Once they are authenticated I call the onLoginFromLoginRegister
event along with a callback to redirect the user to the next page.

LoginRegister.java

//note: LoginType args actually exist in use case 1, but were removed to
simplify my example. They are only used to pick proper ajaxResponseRenderer
in the onLoginFromLoginRegister method.
boolean onSuccessFromLoginForm(LoginType loginType) {
        // We want to tell our containing page explicitly what person we've
updated, so we trigger a new event with a
        // parameter. It will bubble up because we don't have a handler
method for it.
        componentResources.triggerEvent(LOGIN, new Object[] { loginType },
null);

        // We don't want the original event to bubble up, so we return true
to
        // say we've handled it.
        return true;
}


Layout.java

void onLoginFromLoginRegister(LoginType loginType) {
        modalDialog.hide();

        if (request.isXHR()) {
            if(LoginType.LOGIN.equals(loginType)) {

ajaxResponseRenderer.addRender(loginRegisterModalZone).addRender(loginNavZone);
            } else if(LoginType.LOGIN_CREATE_LISTING.equals(loginType)) {


ajaxResponseRenderer.addRender(loginRegisterModalZone).addRender(loginNavZone).addCallback(redirectToPhotos());
            }
        }
}

private JavaScriptCallback redirectToPhotos() {
        return new JavaScriptCallback() {
            @Override
            public void run(JavaScriptSupport javascriptSupport) {
                javascriptSupport.addScript("$(\"#form\").submit();");
            }
        };
}



I guess I'm just not sure how you can accomplish both use cases without
running into an area where a component would not need to command it's
container.

I'm very interested in hearing your thoughts. I'm not opposed to changing
my design to make everything work properly.

Reply via email to