It's very simple and fast because the data query is done by server side. I call it shadow clone jutsu like the one in Naruto. There is an actual list name='maker_name' in view and it's switching to ajax one when first selection is made, then switch back to actual one when page is submitted.
SCREENSHOT
WORKING SAMPLE
MODEL - db.py
# -*- coding: utf-8 -*-
db = DAL('sqlite://storage.sqlite')
response.generic_patterns = ['*'] if request.is_local else []
# Foreign key is used for good practice but not required to use ajax casading drop down
db.define_table('Category',
Field('Name'))
db.define_table('Maker',
Field('Name'),
Field('Category_ID', db.Category),
Field('Note', 'text'))
db.define_table('Product',
Field('Part_Number'),
Field('Maker_ID', db.Maker),
Field('List_Price', 'decimal(13,2)'),
Field('Special_Price', 'decimal(13,2)'))
db.Category.Name.requires = IS_NOT_EMPTY()
db.Maker.Name.requires = IS_NOT_EMPTY()
db.Maker.Category_ID.requires = IS_IN_DB(db, db.Category.id, '%(Name)s')
db.Product.Part_Number.requires = IS_NOT_EMPTY()
db.Product.Maker_ID.requires = IS_IN_DB(db, db.Maker.id, '%(Name)s')
# Insert test data - you can delete the line below if it's not necessary
if db(db.Category.id>0).count() == 0:
db.Category.insert(Name='PC')
db.Category.insert(Name='Smart Phone')
db.Maker.insert(Name='Toshiba', Category_ID=1, Note='Good Maker')
db.Maker.insert(Name='HP', Category_ID=1, Note='Good Maker')
db.Maker.insert(Name='Dell', Category_ID=1, Note='Good Maker')
db.Maker.insert(Name='Apple', Category_ID=2, Note='Good Maker')
db.Maker.insert(Name='Samsung', Category_ID=2, Note='Good Maker')
db.Product.insert(Part_Number='Toshiba Product A', Maker_ID=1, List_Price=1000, Special_Price=500)
db.Product.insert(Part_Number='Toshiba Product B', Maker_ID=1, List_Price=1500, Special_Price=1000)
db.Product.insert(Part_Number='Toshiba Product C', Maker_ID=1, List_Price=2000, Special_Price=1500)
db.Product.insert(Part_Number='Toshiba Product D', Maker_ID=1, List_Price=2500, Special_Price=2000)
db.Product.insert(Part_Number='Toshiba Product E', Maker_ID=1, List_Price=3000, Special_Price=2500)
db.Product.insert(Part_Number='Toshiba Product F', Maker_ID=1, List_Price=3500, Special_Price=3500)
db.Product.insert(Part_Number='HP Product A', Maker_ID=2, List_Price=1000, Special_Price=500)
db.Product.insert(Part_Number='HP Product B', Maker_ID=2, List_Price=1500, Special_Price=1000)
db.Product.insert(Part_Number='HP Product C', Maker_ID=2, List_Price=2000, Special_Price=1500)
db.Product.insert(Part_Number='HP Product D', Maker_ID=2, List_Price=2500, Special_Price=2000)
db.Product.insert(Part_Number='HP Product E', Maker_ID=2, List_Price=3000, Special_Price=2500)
db.Product.insert(Part_Number='HP Product F', Maker_ID=2, List_Price=3500, Special_Price=3500)
db.Product.insert(Part_Number='Dell Product A', Maker_ID=3, List_Price=1000, Special_Price=500)
db.Product.insert(Part_Number='Dell Product B', Maker_ID=3, List_Price=1500, Special_Price=1000)
db.Product.insert(Part_Number='Dell Product C', Maker_ID=3, List_Price=2000, Special_Price=1500)
db.Product.insert(Part_Number='Dell Product D', Maker_ID=3, List_Price=2500, Special_Price=2000)
db.Product.insert(Part_Number='Dell Product E', Maker_ID=3, List_Price=3000, Special_Price=2500)
db.Product.insert(Part_Number='Dell Product F', Maker_ID=3, List_Price=3500, Special_Price=3500)
db.Product.insert(Part_Number='Apple Product A', Maker_ID=4, List_Price=1000, Special_Price=500)
db.Product.insert(Part_Number='Apple Product B', Maker_ID=4, List_Price=1500, Special_Price=1000)
db.Product.insert(Part_Number='Apple Product C', Maker_ID=4, List_Price=2000, Special_Price=1500)
db.Product.insert(Part_Number='Apple Product D', Maker_ID=4, List_Price=2500, Special_Price=2000)
db.Product.insert(Part_Number='Apple Product E', Maker_ID=4, List_Price=3000, Special_Price=2500)
db.Product.insert(Part_Number='Apple Product F', Maker_ID=4, List_Price=3500, Special_Price=3500)
db.Product.insert(Part_Number='Samsung Product A', Maker_ID=5, List_Price=1000, Special_Price=500)
db.Product.insert(Part_Number='Samsung Product B', Maker_ID=5, List_Price=1500, Special_Price=1000)
db.Product.insert(Part_Number='Samsung Product C', Maker_ID=5, List_Price=2000, Special_Price=1500)
db.Product.insert(Part_Number='Samsung Product D', Maker_ID=5, List_Price=2500, Special_Price=2000)
db.Product.insert(Part_Number='Samsung Product E', Maker_ID=5, List_Price=3000, Special_Price=2500)
db.Product.insert(Part_Number='Samsung Product F', Maker_ID=5, List_Price=3500, Special_Price=3500)
CONTROLLER - default.py
# -*- coding: utf-8 -*-
def index():
if request.vars.maker_name:
lists = db(db.Product.Maker_ID==request.vars.maker_name).select(db.Product.ALL)
themakers = db(db.Maker.id==request.vars.maker_name).select(db.Maker.ALL)
else:
lists = db(db.Product.Maker_ID==1).select(db.Product.ALL)
themakers = db(db.Maker.id==1).select(db.Maker.ALL)
categories = db().select(db.Category.ALL)
if request.vars.category_name:
makers = db(db.Maker.Category_ID==request.vars.category_name).select(db.Maker.ALL)
else:
makers = db(db.Maker.Category_ID==1).select(db.Maker.ALL)
return dict(lists=lists, categories=categories, makers=makers, themakers=themakers)
def maker():
makers = db(db.Maker.Category_ID==request.vars.category_name).select(db.Maker.ALL)
result = "<select name='maker_name'>"
for maker in makers:
result += "<option value='" + str(maker.id) + "'>" + maker.Name + "</option>"
result += "</select>"
return XML(result)
VIEW - default/index.html
{{extend 'layout.html'}}
<form enctype="multipart/form-data" action="{{URL()}}" method="post">
<select name='category_name'
onchange="jQuery(maker_name).remove();
ajax('maker', ['category_name'], 'shadow_clone');">
{{for category in categories:}}
<option value="{{=category.id}}"
{{=" selected='selected'" if str(category.id)==request.vars.category_name else ""}}>
{{=category.Name}}
</option>
{{pass}}
</select>
<span id='shadow_clone'></span>
<select name='maker_name' >
{{for maker in makers:}}
<option value="{{=maker.id}}"
{{=XML(" selected='selected'") if str(maker.id)==request.vars.maker_name else ""}}>
{{=maker.Name}}</option>
{{pass}}
</select>
<input type="submit" value='Submit'>
</form>
<hr>
<div id="left_price">
<div id="effective_price">
{{for themaker in themakers:}}
<p>{{=themaker.Note}}</p>
{{pass}}
</div>
<table class="pricetable">
<tr>
<th class="priceleft">Part Number</th>
<th class="priceright">List ($)</th>
<th class="priceright">Special ($)</th>
</tr>
</table>
<div id="table_price">
<table class="pricetable">
{{for list in lists:}}
<tr>
<td class="priceleft">{{=list.Part_Number}}</td>
<td class="priceright">{{=list.List_Price}}</td>
<td class="priceright">{{=list.Special_Price}}</td>
</tr>
{{pass}}
</table>
</div>
</div>
<div id="right_price">
</div>
CSS - base.css (Not required) This is not required for the function. I just add it for my view.
/*For Ajax Cascading Drop Down - Omi Chiba */
#left_price {
width: 55%;
float:left;
}
#right_price {
width: 40%;
float:left;
margin-left:5%;
}
#table_price {
width: 500px;
height: 420px;
overflow: auto;
}
#effective_price {
width: 475px;
text-align: right;
}
.pricetable {
width: 480px;
}
.priceleft {
width: 160px;
text-align: left;
}
.priceright {
width: 80px;
text-align: right;
}
Comments (2)
0
ochiba77 12 years ago
0
kmouts 12 years ago
"selected" option is easy to be chosen in the initial form. Otherwise the "for" loop must be broken,
to add an