001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 002 // The Molly framework is freely distributable under the terms of an 003 // MIT-style license. For details, see the molly pages web site at: 004 // http://www.mollypages.org/. Use, modify, have fun ! 005 006 package fc.web.forms; 007 008 import javax.servlet.*; 009 import javax.servlet.http.*; 010 import java.io.*; 011 import java.util.*; 012 import java.sql.*; 013 014 import fc.jdbc.*; 015 import fc.io.*; 016 import fc.util.*; 017 018 /** 019 A dependency changes the values or state of some form element based 020 on the user selection or choice of some <i>other</i> form element. 021 <p> 022 A typical example includes filling later select/popup values based on 023 the user chosen value of an earlier select in the form. So, for example, 024 if the user chooses a country, then the later select shows the states 025 just for that country. 026 <p> 027 There are several ways to handle dependency changes: 028 <ol> 029 <li>The data for some fields (like database based lookup tables) can be 030 looked up every time. 031 <li>All possible options can be looked up ahead of time and then a 032 subset displayed accordingly. This can be done on the server side (on 033 form submit) or by client side javascript (using various javascript 034 arrays containing different sets of data, the arrays are written out 035 by the server as part of the page and swapped out by client side js). 036 <p> 037 Orthogonal to all this is field and form validation. Validation only 038 makes sense <b>after</b> we have displayed the updated fields to the user 039 For example, initially a country popup may be empty and a state popup 040 may be empty. When the user selects a country, then the form is submitted. 041 At that point, the states popup is still empty and we should *not* validate 042 the states data (i.e., not show the user a message that a state must be 043 chosen or show a validation error for any other fields which the user hasn't 044 filled out yet). 045 <p> 046 Validation can always be controlled by enabled/disabled flag on the field 047 since field validators are not run for fields that are disabled. In addition, 048 any time a field has new dependent values, the form is not validated by field 049 validators. 050 051 @author hursh jain 052 **/ 053 public interface Dependency 054 { 055 056 /** 057 Sets new values for target field in the FormData object. The target field 058 then uses those values to render itself to the client. The data should be 059 saved in FormData with the field name as the key. 060 <p> 061 <b>Note:</b>This method <blink>must</blink> invoke {@link FormData#setDependencyUpdated} 062 if it sets new values in the formdata object. New values are values that 063 are different from the values that were last displayed to the client. 064 <p> 065 There are 2 conditions that typically must be satisfied for this to be 066 true: 067 <ol> 068 <li><i>Source not null</i>: The source fields must have some data. For 069 example, a country popup needs to be selected to some country value before 070 the target dependent field (a state popup) can be populated. If no country 071 is selected, we cannot calculate a dependent state value. 072 </li> 073 <li><i>Source changed:</i> The source fields must have different data than 074 the last time the form was rendered (which means that the client made a 075 different selection/choice). For example, previously, the source field 076 could have been 'usa'. The client then either changes that to 'uk' or 077 leaves it alone. The last_value (which is rendered as a hidden field in the 078 form) in conjunction with the submittd value of the source field(s) can be 079 used to figure out if there was a dependency change. If the source value is 080 'usa' and the last_value is 'usa', then we know there is no need for any 081 dependency updates (since the usa values are already shown to the user). 082 </li> 083 </ol> 084 */ 085 public void updateValues(FormData fd, HttpServletRequest req) throws DependencyException; 086 087 /** 088 The inverse of {@link renderDependencyData}, sets any depedency data submitted 089 as part of the form. This data is set in the specified {@link FormData} object 090 and can be later used by the {@link updateValues} method. 091 */ 092 public void setDependencyDataFromSubmit(FormData fd, HttpServletRequest req); 093 094 /** 095 Writes out data to keep track of dependency state. This data is typically 096 the last selected values of some source field (say last selected source 097 country for a target dependent state field) and usually written out as a 098 hidden field in the form. 099 */ 100 public void renderDependencyData(FormData fd, Writer writer) 101 throws SQLException, IOException; 102 103 /** 104 Returns the initial values for the target field These are the values that 105 are displayed when the form is first rendered. The returned object is of a 106 type that is suitable for the data of the target field. (typically an instance 107 of a static inner data class of that field). 108 <p> 109 If there is no initial data, the returned object can also be <tt>null</tt> or 110 an empty data object, depending on what the target field expects when there 111 is no data. 112 */ 113 public Object getInitialValues(Field f); 114 115 /** 116 Returns true if the submitted values are in a valid range of values. 117 For ultra-secure applications, the validity can be computed every time by 118 recomputing/retrieving the dependent data and of-course, database 119 constraints should always be employed. 120 <p> 121 If this method is not applicable, this method should return 122 <tt>true</tt> every time. 123 */ 124 public boolean isSubmitDataValid(FormData fd); 125 } 126