Log in |
Using selection listsVersion 0.3This howto show basic ways to implement a selection list (i.e. a drop-down list or multiline selection area) in a form. Most information were found on the [email protected] list and looking at the Zope UI pages. Feel free to send me your feedback. Version History
Using the SELECT tag in formsTo create a drop-down list, use a SELECT tag within FORM tags. In SELECT tags, each option is itemized by an OPTION tag. These tags are not Zope-specific; they are standard HTML tags. For more information, see the HTML 4 Specification or an HTML tutorial. Let's create a basic selection list with hard-coded options. <FORM action="myMethod"> ... <SELECT name="myList"> <OPTION value="optionName1">optionValue1</option> <OPTION value="optionName2">optionValue2</option> <OPTION value="optionName3">optionValue3</option> <OPTION value="optionName4">optionValue4</option> </SELECT> ... </FORM> The displayed part is optionValueN. The SELECT structure need to be located in FORM tags. I will omit the FORM tags below for short. Within the SELECT tag, you can specify attributes (these are standard HTML attributes):
Example: <SELECT name="myList" multiple size="4"> <OPTION value="optionName1">optionValue1</OPTION> <OPTION value="optionName2">optionValue2</OPTION> <OPTION value="optionName3">optionValue3</OPTION> <OPTION value="optionName4">optionValue4</OPTION> </SELECT> Additionally, DTML allows to specify the type of the data returned by the list. To specify a type, append a colon (:) and a type name to the list name. Example: <SELECT name="myList:list" multiple size="4"> <OPTION value="optionName1" selected>optionValue1</OPTION> <OPTION value="optionName2">optionValue2</OPTION> <OPTION value="optionName3" selected>optionValue3</OPTION> <OPTION value="optionName4">optionValue4</OPTION> </SELECT> Here the myList selection will be returned in list format. You can specify other types. For more information about these types in forms, see the Form Variable Types and Typechecking Howto. Within the OPTION tag, you can also specify attributes (standard HTML attributes here too):
Example: <SELECT name="myList" multiple size="4"> <OPTION value="optionName1" selected>optionValue1</OPTION> <OPTION value="optionName2">optionValue2</OPTION> <OPTION value="optionName3" selected>optionValue3</OPTION> <OPTION value="optionName4">optionValue4</OPTION> </SELECT> Here option 1 and 4 are preselected and displayed in a 4-line selection box. Filling lists from loopsUsing loopsYou can fill a list from a loop. You use the dtml-in tag to specify the object to loop on. When looping on an object, you can directly access its properties within the dtml-in tags. For more information about this tag, see the Z Document Template Markup Language Guide. The following code creates a selection list of DTML document titles: <SELECT name="myList"> <dtml-in "objectValues(['DTML Document'])"> <OPTION value='<dtml-var id>'><dtml-var title></OPTION> </dtml-in> </SELECT> For more information about loops, see the Looping in DTML Howto. You can also loop on a list of hard-coded values. Example: <SELECT name="myList"> <dtml-in "('un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf', 'dix')"> <OPTION value="<dtml-var sequence-item>"><dtml-var sequence-item></OPTION> </dtml-in> </SELECT> You get a nice list with French figure names. How wonderful for you. You can also specify a list of figures. Example: <SELECT name="myList:int"> <dtml-in "(0, 1, 2, 3, 4, 5 ,6, 7, 8, 9)"> <OPTION value="<dtml-var sequence-item>"><dtml-var sequence-item></OPTION> </dtml-in> </SELECT> Testing and excluding valuesYou can use Python expressions to test values. This allows you to preselect or filter out values from your list. Example: <SELECT name="myList"> <dtml-in "objectValues(['News'])"> <dtml-if "id() == 'foo'"> <OPTION SELECTED VALUE='<dtml-var id>'> <dtml-var title_or_id></OPTION> <dtml-else> <OPTION VALUE='<dtml-var id>'> <dtml-var title_or_id></OPTION> </dtml-if> </dtml-in> </SELECT> The following example exclude objects whose type is "News". <SELECT name="myList"> <dtml-in objectItems> <dtml-if "meta_type != 'News'"> <OPTION><dtml-var id></OPTION> </dtml-in> </dtml-in> </SELECT> Note you need to use a special syntax to test the sequence-item variable because of naming conventions. <dtml-if "_['sequence-item']=='foo'"> Example: <SELECT NAME="myList:list" SIZE="5" MULTIPLE> <dtml-in valid_roles> <dtml-if "_['sequence-item'] != 'Anonymous'"> <dtml-if "_['sequence-item'] != 'Shared'"> <OPTION VALUE="<dtml-var sequence-item html_quote>"> <dtml-var sequence-item></OPTION> </dtml-if> </dtml-if> </dtml-in> </SELECT> dtml-if tests can check values against a list: <SELECT name="myList:list" size="5" multiple> <dtml-in valid_roles> <dtml-if "_['sequence-item'] not in ('Anonymous', 'Shared')"> <OPTION value="<dtml-var sequence-item html_quote>"> <dtml-var sequence-item></OPTION> </dtml-if> </dtml-in> </SELECT> Filling lists from propertiesCreate a property with type lines. For instance, you can assign this property to the folder that holds your form. Fill in several lines item for testing. Let's call this property my_subjects. Back in the form, enter the following code: <SELECT NAME="myList"> <dtml-in my_subjects> <OPTION VALUE="<dtml-var sequence-index>"> <dtml-var sequence-index>: <dtml-var sequence-item></OPTION> </dtml-in> </SELECT> sequence-index is the line number (1st line is 0). sequence-item is the actual line text. The code described above will create a list with the following content : 0: Your 1st line Filling lists from TinyTablesTinyTable is a product that allows you to create table objects in Zope. You can download it from here. After installing the product, create a new TinyTable (choose TinyTable in the object list). Enter an ID (let's use myTable) and column names (subject_id and subject_name, for instance). In the Data area, enter a few lines in comma-separated format: on each line, enter an id and a name as in the following example:
"my_id_1", "This is subject 1" Click on the View tab to check your entry. You should see a nice table with your data. Back in your form, enter the following code: <SELECT NAME="myList"> <dtml-in myTable> <OPTION VALUE="<dtml-var subject_id>"> <dtml-var subject_name></OPTION> </dtml-in> </SELECT> That's all: you get a selection list based on your TinyTable. So you can easily avoid hard-coding list options in your forms. Filling lists from SQL methodsBelieve it or not, this is easy. You'll need a working database, database connection and SQL query. You'll find below a very short summary of the process. For more information, see the Z SQL Methods User's Guide. There are also several howtos about ZSQL Methods.
SELECT * FROM myTable Let's imagine your table (myTable) has two columns, Field1 and Field2. This simple code fills up your list from your table through the SQL query:
Filling lists from DTML methodsYou can generate list data in a DTML method and pass it to the selection list in a form. The code is a bit more complex because you need to define a variable to store the data. [Todo: Is there a better way? Please fill in.]
First example: passing one variableCreate a DTML Method called myMethod and enter the following code: <dtml-call "REQUEST.set('myOptionList',[])"> <dtml-in "objectValues(['News', 'DTML Document'])"> <dtml-call "myOptionList.append(title_or_id)"> </dtml-in> <dtml-return myOptionList> myOptionList is a Python list. The 1st dtml-call tag creates an empty list. The second call appends a value (titles or IDs for DTML documents or News document in the current directory) to the list. The list is then returned by the method. In your form, enter the following code for the selection list: <SELECT NAME="myList" multiple> <dtml-in myMethod> <OPTION value="<dtml-var sequence-index>"> <dtml-var sequence-index>: <dtml-var sequence-item></OPTION> </dtml-in> </SELECT> The values displayed in the list will look like 1: My title or id. Second example: passing two or more variablesSuppose I need to pass several properties per document listed by the method? I guess we can store them as lists within a list. Here's how. In myMethod, enter the following code: <dtml-call "REQUEST.set('myOptionList',[])"> <dtml-in "objectValues(['DTML Document'])"> <dtml-call "REQUEST.set('myIDTitle',[id(), title_or_id()])"> <dtml-call "myOptionList.append(myIDTitle)"> </dtml-in> <dtml-return myOptionList> Here we loop on DTML document objects in the current directory, we retrieve their IDs and titles, we store both properties in a list (myIDTitle), then we store these lists in a larger list (myOptionList) which is returned by the method. In your form, enter the following code: <SELECT NAME="myList" multiple> <dtml-in myMethod> <dtml-in sequence-item> <dtml-if "_['sequence-index']==0"> <OPTION "<dtml-var sequence-item>"> <dtml-else> <dtml-var sequence-item></OPTION> </dtml-if> </dtml-in> </dtml-in> </SELECT> The first dtml-in tag loops on the 1st, larger Python list. For each option line in the selection list, it extract a smaller, two-item list (stored in the first sequence-item). The second dtml-in tag loops on this smaller list. If list index is 0 (1st item, i.e. the document ID), the value is used for the OPTION tag. If list index is 1 (2nd item, i.e. the document title), the value is used for the displayed list text. [I suppose there is a better way. How can I access a list within a list? Could I pass the data in another structure, a dictionary for instance?] Filling lists from External methodsExternal methods are Python code module that are stored in the Extensions subdirectory of your Zope server. With External methods, you can create complex scripts and call them from your DTML pages. For more information, see the Using External Methods Howto. You can fill a selection list with data returned by an external method. Here's how:
Filling lists from Python methodsPythonMethods is a product that allows you to create Python script objects from the Zope Web UI and to call them from any other object. With this product you can use safe Python scripts in your server; you don't need file access on the server to create or edit the scripts. You can download the product from here. When you have installed the product, create a new Python method: in the Available Objects list, choose Python Method. In the Id field, enter myPythonMethod. In the Parameter list, enter: fromNumber=10, toNumber=100, myStep=10 In the Python function body area, enter the following code: """Returns a list of numbers.""" myList=[] for i in range(fromNumber, toNumber, myStep): myList.append(i) return myList Note I just reused the example from the External Method section of this howto. Save and close the object. Reopen it and click on the Try It tab to test it. The method should return the following data based on the parameter default values: [10, 20, 30, 40, 50, 60, 70, 80, 90] In your form, enter the following code: <SELECT NAME="myList"> <dtml-in "myPythonMethod(100, 200, 10)"> <OPTION "<dtml-var sequence-index>"> <dtml-var sequence-item></OPTION> </dtml-in> </SELECT> You get a selection list with values between 100 and 200 incremented by 10. Remember to use quotes in the dtml-in tag when passing parameters. Retrieving list selectionsSimple selectionTo retrieve the selection your form can call a handler method.
Here is an example from myForm: <FORM action="myHandlerMethod"> <P><SELECT NAME="myList1"> <OPTION VALUE="1">Choice 1</OPTION> <OPTION VALUE="2">Choice 2</OPTION> <OPTION VALUE="3">Choice 3</OPTION> </SELECT></P> <P><SELECT NAME="myList2"> <OPTION>Choice 1</OPTION> <OPTION>Choice 2</OPTION> <OPTION>Choice 3</OPTION> </SELECT></P> <INPUT type="submit" name="submit" value=" OK "> </FORM> If your select Choice 2 in both lists, myList1 will return 2 and myList2 will return Choice 2. In myHandlerMethod, you can catch the return values with simple <dtml-var myList1> and <dtml-var myList2> tags. You don't need to specify an object, since the result values are stored in the REQUEST object which is implicit. Multiple selectionIf you use the multiple attribute to allow multiple selections, by default the list returns a Python list of values in the [value1, value2, value3, ...] format. <FORM action="myHandlerMethod"> <P><SELECT NAME="myList1" multiple size="3"> <OPTION VALUE="1">Choice 1</OPTION> <OPTION VALUE="2">Choice 2</OPTION> <OPTION VALUE="3">Choice 3</OPTION> </SELECT></P> <P><SELECT NAME="myList2" multiple size="3"> <OPTION>Choice 1</OPTION> <OPTION>Choice 2</OPTION> <OPTION>Choice 3</OPTION> </SELECT></P> <INPUT type="submit" name="submit" value=" OK "> </FORM> If you select the last two items, the lists return ['2', '3'] and ['Choice 2', 'Choice 3'] respectively. Note that myList1 returns quoted figures because the return type defaults to string. You can specify a type in the name attribute as in NAME="myList1:int" so that value are automatically converted. Now myList1 returns [1, 2]. Note the values aren't quoted any more. You can specify other types: tuple (you get ('Choice 1', 'Choice 2', 'Choice 3')), etc. For more information, see the Form Variable Types and Typechecking Howto. If you want to process or display the return list values, you can loop on them in the handler method. Example: <OL> <dtml-in myList2> <LI><dtml-var sequence-item> </dtml-in> </OL> Note that string values cannot be used with a dtml-in tag (integer values are OK). You'll get an error if you don't specify a type such as NAME="myList2:list" in the form. Useful listsHere are a series of code snippets I copied from existing products. Most of them were shamelessly stolen from the Zope UI pages. All lists have tested OK at least once on my box. I do not really grok them all; however, I think these code cuts can be useful as a starting point when experimenting. List of permission settings<SELECT name="myList:list"> <dtml-in permission_settings mapping> <OPTION VALUE="<dtml-var name html_quote>"> <dtml-var name></OPTION> </dtml-in> </SELECT> Another example where permissions acquired are preselected. <SELECT name="myList:list" multiple size=10> <dtml-in permission_settings mapping> <OPTION <dtml-if acquire>SELECTED</dtml-if>> <dtml-var name></OPTION> </dtml-in> </SELECT> [I do not grok the mapping bit. Can anyone explain?] List of possible permissions<SELECT name=myList> <dtml-in possible_permissions> <OPTION><dtml-var sequence-item></OPTION> </dtml-in> </SELECT> List of user roles<SELECT NAME="myList:list"> <dtml-in valid_roles> <OPTION value="<dtml-var sequence-item html_quote>"> <dtml-var sequence-item></OPTION> </dtml-in valid_roles> </SELECT> Another example where two roles are excluded from the list: <SELECT NAME="myList:list" SIZE="5" MULTIPLE> <dtml-in valid_roles> <dtml-if "_['sequence-item'] != 'Anonymous'"> <dtml-if "_['sequence-item'] != 'Shared'"> <OPTION VALUE="<dtml-var sequence-item html_quote>"> <dtml-var sequence-item> </dtml-if> </dtml-if> </dtml-in valid_roles> </SELECT> List of user IDsThis code displays a list of valid user IDs in the current directory: <SELECT name="myList" size="5"> <dtml-in get_valid_userids> <OPTION value="<dtml-var sequence-item html_quote>"> <dtml-var sequence-item></OPTION> </dtml-in> </SELECT> List of roles that have a permissionThis code preselects roles that have the permission "Add Folders" in the current directory. In my server, it preselected "Manager". <SELECT name=myList:list multiple size=10> <dtml-in expr="rolesOfPermission('Add Folders')" mapping=1> <OPTION <dtml-var selected>> <dtml-var name></OPTION> </dtml-in> </SELECT> List of permissions linked to a roleThis code preselects the permissions associated with a role (Manager here). <select name=myList:list multiple size=10> <dtml-in expr="permissionsOfRole('Manager')" mapping=1> <option <dtml-var selected>> <dtml-var name></option> </dtml-in> </select> List of all object types<SELECT NAME="myList:list" SIZE="4" MULTIPLE> <OPTION VALUE="all" SELECTED> All types</OPTION> <dtml-in all_meta_types mapping> <OPTION VALUE="<dtml-var name html_quote>"> <dtml-var name></OPTION> </dtml-in> </SELECT> List of allowed object typesFiltered list of allowed object types for the current user sorted by object name: <SELECT NAME="myList:list"> <dtml-in "filtered_meta_types(AUTHENTICATED_USER)" mapping sort=name> <OPTION value="<dtml-var action fmt="url-quote">"> <dtml-var name>"></OPTION> </dtml-in> </SELECT> Here the value is an URL to the forms that allow to create the corresponding object. List of object IDs from the current directoryNote that one type is excluded here: <SELECT name="myList"> <dtml-in objectItems> <dtml-if "meta_type != 'Principia Factory'"> <OPTION><dtml-var sequence-key></OPTION> </dtml-if> </dtml-in> </SELECT> List of searchable objectsOn my box, this code cut returns the name of my Catalog and of Confera and Squishdot top objects. <SELECT name="myList:list" size=4 multiple> <dtml-in ZQueryIds> <OPTION><dtml-var sequence-item></OPTION> </dtml-in> </SELECT> List of SQL connectionsAFAIK, this code lists database connections. It listed a Z ODBC Database Connexion ID in my server. <select name="myList"> <dtml-in SQLConnectionIDs> <option value="<dtml-var sequence-item html_quote>"> <dtml-var sequence-key></option> </dtml-in> </SELECT> |