Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  // Copyright 2006, 2007, 2008, 2009, 2010 The Apache Software Foundation
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
 package org.apache.tapestry5.corelib.components;
 
 
An HTML form, which will enclose other components to render out the various types of fields.

A Form emits many notification events. When it renders, it fires a org.apache.tapestry5.EventConstants.PREPARE_FOR_RENDER notification, followed by a EventConstants.PREPARE notification.

When the form is submitted, the component emits several notifications: first a EventConstants.PREPARE_FOR_SUBMIT, then a EventConstants.PREPARE: these allow the page to update its state as necessary to prepare for the form submission, then (after components enclosed by the form have operated), a EventConstants.VALIDATE event is emitted (followed by a EventConstants.VALIDATE_FORM event, for backwards compatibility), to allow for cross-form validation. After that, either a EventConstants.SUCCESS OR EventConstants.FAILURE event (depending on whether the ValidationTracker has recorded any errors). Lastly, a EventConstants.SUBMIT event, for any listeners that care only about form submission, regardless of success or failure.

For all of these notifications, the event context is derived from the context parameter. This context is encoded into the form's action URI (the parameter is not read when the form is submitted, instead the values encoded into the form are used).

 
         . })
 public class Form implements ClientElementFormValidationControl
 {
    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
 
     public static final String PREPARE_FOR_RENDER = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
 
     public static final String PREPARE_FOR_SUBMIT = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
 
    public static final String PREPARE = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
    public static final String SUBMIT = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
    public static final String VALIDATE_FORM = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
    public static final String SUCCESS = .;

    

Deprecated:
Use constant from org.apache.tapestry5.EventConstants instead.
    public static final String FAILURE = .;

    
Query parameter name storing form data (the serialized commands needed to process a form submission).
    public static final String FORM_DATA = "t:formdata";

    
Used by Submit, etc., to identify which particular client-side element (by element id) was responsible for the submission. An empty hidden field is created, as needed, to store this value.

Since:
5.2.0
    public static final String SUBMITTING_ELEMENT_ID = "t:submit";

    
The context for the link (optional parameter). This list of values will be converted into strings and included in the URI. The strings will be coerced back to whatever their values are and made available to event handler methods.
    @Parameter
    private Object[] context;

    
The object which will record user input and validation errors. The object must be persistent between requests (since the form submission and validation occurs in a component event request and the subsequent render occurs in a render request). The default is a persistent property of the Form component and this is sufficient for nearly all purposes (except when a Form is rendered inside a loop).
    @Parameter("defaultTracker")
    private ValidationTracker tracker;
    @Inject
    private boolean clientLogicDefaultEnabled;

    
If true (the default) then client validation is enabled for the form, and the default set of JavaScript libraries (Prototype, Scriptaculous and the Tapestry library) will be added to the rendered page, and the form will register itself for validation. This may be turned off when client validation is not desired; for example, when many validations are used that do not operate on the client side at all.
    @Parameter
    private boolean clientValidation = ;

    
If true (the default), then the JavaScript will be added to position the cursor into the form. The field to receive focus is the first rendered field that is in error, or required, or present (in that order of priority).

    @Parameter
    private boolean autofocus = ;

    
Binding the zone parameter will cause the form submission to be handled as an Ajax request that updates the indicated zone. Often a Form will update the same zone that contains it.
    @Parameter(defaultPrefix = .)
    private String zone;

    
Prefix value used when searching for validation messages and constraints. The default is the Form component's id. This is overridden by BeanEditForm.

    @Parameter
    private String validationId;

    
Object to validate during the form submission process. The default is the Form component's container. This parameter should only be used in combination with the Bean Validation Library.
    @Parameter
    private Object validate;
    @Inject
    private Logger logger;
    @Inject
    private Environment environment;
    @Inject
    private ComponentResources resources;
    @Inject
    private Messages messages;
    private JavaScriptSupport jsSupport;
    @Inject
    private Request request;
    @Inject
    private ComponentSource source;
    @Inject
    private String preselectedFormNames;
    private Element form;
    private Element div;
    // Collects a stream of component actions. Each action goes in as a UTF
    // string (the component
    // component id), followed by a ComponentAction
    @Mixin
    @SuppressWarnings("unchecked")
    @Inject
    private String clientId;
    // Set during rendering or submit processing to be the
    // same as the VT pushed into the Environment
    {
        return .getId();
    }
    {
        return .getContainer();
    }

    
Returns a wrapped version of the tracker parameter (which is usually bound to the defaultTracker persistent field). If tracker is currently null, a new instance of org.apache.tapestry5.ValidationTrackerImpl is created. The tracker is then wrapped, such that the tracker parameter is only updated the first time an error is recorded into the tracker (this will typically propagate to the defaultTracker persistent field and be stored into the session). This means that if no errors are recorded, the tracker parameter is not updated and (in the default case) no data is stored into the session.

Returns:
a tracker ready to receive data (possibly a previously stored tracker with field input and errors)
See also:
TAP5-979
    {
        ValidationTracker innerTracker =  == null ? new ValidationTrackerImpl() : ;
        ValidationTracker wrapper = new ValidationTrackerWrapper(innerTracker)
        {
            private boolean saved = false;
            private void save()
            {
                if (!)
                {
                     = getDelegate();
                     = true;
                }
            }
            @Override
            public void recordError(Field fieldString errorMessage)
            {
                super.recordError(fielderrorMessage);
                save();
            }
            @Override
            public void recordError(String errorMessage)
            {
                super.recordError(errorMessage);
                save();
            }
        };
        return wrapper;
    }
    {
        return ;
    }
    public void setDefaultTracker(ValidationTracker defaultTracker)
    {
        this. = defaultTracker;
    }
    void setupRender()
    {
        FormSupport existing = .peek(FormSupport.class);
        if (existing != null)
            throw new TapestryException(.get("nesting-not-allowed"), existingnull);
    }
    void beginRender(MarkupWriter writer)
    {
        // Pre-register some names, to prevent client-side collisions with function names
        // attached to the JS Form object.
        IdAllocator allocator = new IdAllocator();
        preallocateNames(allocator);
        if ( != null)
            linkFormToZone(link);
         = getWrappedTracker();
        .push(FormSupport.class);
        if ()
        {
            ValidationDecorator autofocusDecorator = new AutofocusValidationDecorator(
                    .peek(ValidationDecorator.class), );
            .push(ValidationDecorator.classautofocusDecorator);
        }
        // Now that the environment is setup, inform the component or other
        // listeners that the form
        // is about to render.
        // Save the form element for later, in case we want to write an encoding
        // type attribute.
         = writer.element("form""id""method""post""action"link);
        if (( != null || ) && !.isXHR())
            writer.attributes("onsubmit".);
        .renderInformalParameters(writer);
         = writer.element("div""class".);
        for (String parameterName : link.getParameterNames())
        {
            String value = link.getParameterValue(parameterName);
            writer.element("input""type""hidden""name"parameterName"value"value);
            writer.end();
        }
        writer.end(); // div
        .peek(Heartbeat.class).begin();
    }
    private void linkFormToZone(Link link)
    {
        .linkZone(link);
    }

    
Creates an org.apache.tapestry5.corelib.internal.InternalFormSupport for this Form. This method is used by FormInjector.

This method may also be invoked as the handler for the "internalCreateRenderTimeFormSupport" event.

Parameters:
clientId the client-side id for the rendered form element
actionSink used to collect component actions that will, ultimately, be written as the t:formdata hidden field
allocator used to allocate unique ids
Returns:
form support object
    @OnEvent("internalCreateRenderTimeFormSupport")
            IdAllocator allocator)
    {
        return new FormSupportImpl(clientIdactionSinkallocator,
                );
    }
    void afterRender(MarkupWriter writer)
    {
        .peek(Heartbeat.class).end();
        .executeDeferred();
        String encodingType = .getEncodingType();
        if (encodingType != null)
            .forceAttributes("enctype"encodingType);
        writer.end(); // form
        .element("input""type""hidden""name""value".getClientData());
        if ()
            .pop(ValidationDecorator.class);
    }
    void cleanupRender()
    {
        .pop(FormSupport.class);
         = null;
        .pop(ValidationTracker.class);
         = null;
        .pop(BeanValidationContext.class);
    }
    { "unchecked""InfiniteLoopStatement" })
    @Log
    Object onAction(EventContext contextthrows IOException
    {
         = getWrappedTracker();
        .clear();
        .push(FormSupport.class);
        Heartbeat heartbeat = new HeartbeatImpl();
        .push(Heartbeat.classheartbeat);
        heartbeat.begin();
        try
        {
            if (.isAborted())
                return true;
            if (.isAborted())
                return true;
            executeStoredActions();
            heartbeat.end();
            .executeDeferred();
            fireValidateFormEvent(context);
            if (.isAborted())
                return true;
            // Let the listeners know about overall success or failure. Most
            // listeners fall into
            // one of those two camps.
            // If the tracker has no errors, then clear it of any input values
            // as well, so that the next page render will be "clean" and show
            // true persistent data, not value from the previous form
            // submission.
            if (!.getHasErrors())
                .clear();
                    : .context);
            // Lastly, tell anyone whose interested that the form is completely
            // submitted.
            if (.isAborted())
                return true;
            return .isAborted();
        }
        finally
        {
            .pop(Heartbeat.class);
            .pop(FormSupport.class);
            .pop(ValidationTracker.class);
            .pop(BeanValidationContext.class);
             = null;
        }
    }
    private void fireValidateFormEvent(EventContext contextTrackableComponentEventCallback callback)
            throws IOException
    {
        fireValidateEvent(.contextcallback);
        if (callback.isAborted())
            return;
        fireValidateEvent(.contextcallback);
    }
    private void fireValidateEvent(String eventNameEventContext contextTrackableComponentEventCallback callback)
    {
        try
        {
            .triggerContextEvent(eventNamecontextcallback);
        }
        catch (RuntimeException ex)
        {
            ValidationException ve = ExceptionUtils.findCause(exValidationException.class);
            if (ve != null)
            {
                ValidationTracker tracker = .peek(ValidationTracker.class);
                tracker.recordError(ve.getMessage());
                return;
            }
            throw ex;
        }
    }

    
Pulls the stored actions out of the request, converts them from MIME stream back to object stream and then objects, and executes them.
    private void executeStoredActions()
    {
        String[] values = .getParameters();
        if (!.getMethod().equals("POST") || values == null)
            throw new RuntimeException(.format("invalid-request"));
        // Due to Ajax (FormInjector) there may be multiple values here, so
        // handle each one individually.
        for (String clientEncodedActions : values)
        {
            if (InternalUtils.isBlank(clientEncodedActions))
                continue;
            .debug("Processing actions: {}"clientEncodedActions);
            ObjectInputStream ois = null;
            Component component = null;
            try
            {
                ois = .decodeClientData(clientEncodedActions);
                while (!.isAborted())
                {
                    String componentId = ois.readUTF();
                    ComponentAction action = (ComponentActionois.readObject();
                    component = .getComponent(componentId);
                    .debug("Processing: {} {}"componentIdaction);
                    action.execute(component);
                    component = null;
                }
            }
            catch (EOFException ex)
            {
                // Expected
            }
            catch (Exception ex)
            {
                Location location = component == null ? null : component.getComponentResources().getLocation();
                throw new TapestryException(ex.getMessage(), locationex);
            }
            finally
            {
                InternalUtils.close(ois);
            }
        }
    }
    public void recordError(String errorMessage)
    {
        getActiveTracker().recordError(errorMessage);
    }
    public void recordError(Field fieldString errorMessage)
    {
        getActiveTracker().recordError(fielderrorMessage);
    }
    public boolean getHasErrors()
    {
        return getActiveTracker().getHasErrors();
    }
    public boolean isValid()
    {
        return !getActiveTracker().getHasErrors();
    }
    {
        return  != null ?  : getWrappedTracker();
    }
    public void clearErrors()
    {
        getActiveTracker().clear();
    }
    // For testing:
    void setTracker(ValidationTracker tracker)
    {
        this. = tracker;
    }

    
Forms use the same value for their name and their id attribute.
    public String getClientId()
    {
        return ;
    }
    @Inject
    private void preallocateNames(IdAllocator idAllocator)
    {
        for (String name : TapestryInternalUtils.splitAtCommas())
        {
            idAllocator.allocateId(name);
        }
        Component activePage = .getActivePage();
        // This is unlikely but may be possible if people override some of the standard
        // exception reporting logic.
        if (activePage == null)
            return;
        ComponentResources activePageResources = activePage.getComponentResources();
        try
        {
            activePageResources.triggerEvent(.new Object[]
            { idAllocator }, null);
        }
        catch (RuntimeException ex)
        {
            .error(
                    String.format("Unable to obtrain form control names to preallocate: %s",
                            InternalUtils.toMessage(ex)), ex);
        }
    }
New to GrepCode? Check out our FAQ X