cherrypy/mako dynamic form

617 views
Skip to first unread message

clewis1573

unread,
May 25, 2012, 9:50:56 AM5/25/12
to cherrypy-users
I am trying to configure a dynamic form such that, when I select
dropdown A, I can select all values associated with it for dropdown B

IE

#python code generate dictionary as below:
dicta = {'fruit':['apple','orange'], 'vegetable':['pea', 'potato']}

#mako code from python controller
loader = TemplateLookup(directories=templateDir)
tmpl = loader.get_template('index.html')
return tmpl.render(data=dicta)


=========================
index.html snippet
=========================

<form name="test" action="/TestAction" method="POST">

<label>FirstLabel:
<select name="dropdown">
% for f in data:
<option value="">${f}</option>
%endfor
</select>
</label>
<label>SecondLabel:
<select name="dropdown">
% for y in data[f]:
<option value="">${y}</option>
% endfor
</select>
</label>

</form>

========================

The above code gives me "Fruit" or "Vegetable" in FirstLabel and
Random in SecondLabel

I would like the option I choose in First Label to give me the
specific options from the dictionary in the SecondLabel.

Any help appreciated.

Thanks

Chris






Tim Roberts

unread,
May 29, 2012, 3:10:00 PM5/29/12
to cherryp...@googlegroups.com
clewis1573 wrote:
> I am trying to configure a dynamic form such that, when I select
> dropdown A, I can select all values associated with it for dropdown B
>
> IE
>
> #python code generate dictionary as below:
> dicta = {'fruit':['apple','orange'], 'vegetable':['pea', 'potato']}
>
> #mako code from python controller
> loader = TemplateLookup(directories=templateDir)
> tmpl = loader.get_template('index.html')
> return tmpl.render(data=dicta)

You need to think about what things happen in the server, and what
things have to happen in the browser. When the user picks an item from
the dropdown, that's all happening in their browser. Your CherryPy code
is not involved.

If you want that loading to happen automatically, without requiring a
trip back to the server, then you will have to write Javascript code to
handle it. You would need to embed your dictionary in the page as a
Javascript array, then write an onChange handler for the first drop down
that populates the second drop down.

--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

morecowbell

unread,
Jun 2, 2012, 2:15:17 AM6/2/12
to cherryp...@googlegroups.com
chris,

you may want to look at ajax calls to dynamically inject the option elements into your DOM.
you'd probably want to utilize something like jquery to lighten the load. in your html header you'd need something like this:
<script type="text/javascript">
$(document).ready(function(){
                
                //this catches the onChange for all select elements of class dynamic-select
$(".dynamic-select").change(function(){
                        //here we construct a param string from the chosen select (jquery) object attributes and data and append it to cp method ajax
var url_params = '?' + $(this).attr('name') + '=' + $(this).val() + '&sid=' + $(this).attr('id');
                        //this is a shorhand ajax json get call with a callback function retuning a json doc as data
$.getJSON( 'ajax' + url_params,function(data) {
                                //here we extract the key-value and replace the corresponding select element
                               //you'd need to iterate through a list, if your json doc was set up for it. look at $.each() function
                               // you can also append, prepend, inject js code with different (jquery) functions.
                              //also, there a multiple ways to cache the results locally ... but that should get you going
$("#"+ data.element_id).replaceWith(data.data);
});
});
});
</script>

which would call a cp method, ajax, that replies with a json document comprised of the element_id to be replaced and the (html) data. e.g., 

@cherrypy.expose
def ajax(self, *args, **kwargs):
    '''
        deliberately verbose and not optimized. you can shorten that quite a bit.
        not tested against your code snippet
    '''
    if kwargs.get('fruit') is not None:
        s = '<select name="%s" class="%s" id="%s">'%('vegetable', 'dynamic-select', 'vegetable')
        s += '<option value="#">Select Vegetable</option>'
        for opts in dicta['vegetables']:
            s += '<option value="%s">%s</option>'%(opts, opts)
        s += '</select>'
    
        cherrypy.response.headers['Content-Type'] = 'application/json' 
        r = {'element_id':'vegetable', 'data': s}
        return json.dumps(r)

you can do that without json but you loose a lot of flexibility, e.g. use a 'other' options element which then triggers a replacement of the select element with 
an input element, and portability, i.e., the json approach translates very well into the mobile (web) app realm.


your actual html select div would like:
<div name="dropdown-snippet">
<fieldset>
<legend>Dynamic Selects</legend>
                        <form ....>
<select class="dynamic-select" id="fruit" name ="fruit">
                                        <option value="#">Select Fruit Option</option>
<option value="apple">Apple</option>
<option value="orange">Orange</option>
</select>
<select class="dynamic-select" id="vegetable" name="vegetable">
<option value="#">Select Fruit Option First</option>
</select>
                        </form>
</fieldset>
</div>

obviously, you can dynamically populate  your form/select elements at the start-up. note that the hashmarked option elements are necessary to
kick off the change event unless you want to keep the default opt params in your session dict.

clewis1573

unread,
Jul 25, 2012, 7:57:24 AM7/25/12
to cherryp...@googlegroups.com
Sorry for the delay.  

Ajax seemed the way forward so that's helped me a lot.

Appreciate the replies.
Reply all
Reply to author
Forward
0 new messages