【发布时间】:2011-11-11 11:19:54
【问题描述】:
我的域看起来像这样:
ProductLine hasMany Topic(s) hasMany Subtopic(s).
在 Subtopic create.gsp 视图中,我希望有两个下拉菜单 - 第一个用于选择 ProductLine,然后在第二个中我想显示属于先前选择的 ProductLine 的主题。如何实现?
【问题讨论】:
标签: javascript grails drop-down-menu
我的域看起来像这样:
ProductLine hasMany Topic(s) hasMany Subtopic(s).
在 Subtopic create.gsp 视图中,我希望有两个下拉菜单 - 第一个用于选择 ProductLine,然后在第二个中我想显示属于先前选择的 ProductLine 的主题。如何实现?
【问题讨论】:
标签: javascript grails drop-down-menu
将两个下拉框链接在一起并不太难,但第一次将三个或更多下拉框链接起来可能会很困难。下面我将三个下拉框链接在一起,但是您应该能够从这个示例中得出如何将任意数量的下拉框链接在一起。
在我的Load 类中,当我创建一个新实例时,我需要知道货物提供者是谁,使用了什么货物源,以及货物是什么。例如,假设我有一个名为 ACME Rock 的货运供应商。然后想象 ACME Rock 有两个提供货物的地点,123 Somewhere Road 和 456 Nowhere Road。这些位置将代表货物来源。最后想象每个货源提供不同的货物。我们可以想象 123 Somewhere Road 只生产 Rock 而 456 Nowhere Road 只生产 Dirt。说了这么多,我的Load 类的创建视图 (create.gsp) 中的下拉框看起来像这样。
<tr class="prop">
<td valign="top" class="name">
<label for=cargoProvider"><g:message code="load.cargoProvider.label" default="Cargo Provider"/></label>
</td>
<td valign="top" class="value ${hasErrors(bean: loadInstance, field: 'cargoProvider', 'errors')}">
<g:select from="${cargoProviders}" id="cargoProvider.id" name="cargoProvider.id" noSelection="['':'-Select-']" optionKey="id" optionValue="${{it.businessName?.toString() + ': ' + it?.toString()}}" value="${loadInstance?.cargoProvider?.id}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="cargoSource"><g:message code="load.cargoSource.label" default="Cargo Source"/></label>
</td>
<td id="cargoSourceCell" valign="top" class=" value ${hasErrors(bean: loadInstance, field: 'cargoSource', 'errors')}">
<g:select from="${loadInstance?.cargoSource}" id="cargoSource.id" name="cargoSource.id" optionKey="id" value="${loadInstance?.cargoSource?.id}"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="cargo"><g:message code="load.cargo.label" default="Cargo"/></label>
</td>
<td id="cargoCell" valign="top" class="value ${hasErrors(bean: loadInstance, field: 'cargo', 'errors')}">
<g:select from="${loadInstance?.cargo}" id="cargo.id" name="cargo.id" optionKey="id" value="${loadInstance?.cargo?.id}"/>
</td>
</tr>
我们开始将这些下拉框与位于同一页面 (create.gsp) 上的一些 JavaScript 链接在一起。请记住将您的 JavaScript 放在关闭 body 元素的 </body> 标记之前。请注意,我使用的是 jQuery,而不是 Prototype。
<g:javascript>
$(document).ready(function() {
$("#cargoProvider\\.id").change(function() {
var cargoSourceValue = $("#cargoSource\\.id").val();
$.ajax({
url: "/truckingmanagement/load/getCargoSources",
data: "id=" + this.value,
dataType: 'html',
cache: false,
success: function(result) {
$("#cargoSourceCell").html(result);
$("#cargoSource\\.id").val(cargoSourceValue);
$("#cargoSource\\.id").trigger('change');
}
});
});
});
</g:javascript>
<g:javascript>
function updateCargoes() {
var data = ($("#cargoSource\\.id").val() == null) ? "" : $("#cargoSource\\.id").val();
var cargoValue = $("#cargo\\.id").val();
$.ajax({
url: "/truckingmanagement/load/getCargoes",
data: "id=" + data,
dataType: 'html',
cache: false,
success: function(result) {
$("#cargoCell").html(result);
$("#cargo\\.id").val(cargoValue);
}
});
}
</g:javascript>
乍一看,updateCargoes 函数似乎没有做任何事情,但实际上确实如此。当在第一个下拉框中进行选择时,第二个下拉框将填充我的 Load 控制器中的 Grails render 语句生成的 HTML。这实质上是用一个新的下拉框替换了原来的下拉框,因此我最初写入下拉框中的任何属性都将丢失,除非它们也包含在render 语句中。这就是为什么您会在下面我的负载控制器的getCargoSources 操作的render 语句中看到onchange: 'updateCargoes();,以及正确执行我的应用程序所需的其他属性。您包含的属性将根据您想要在视图中执行的操作而有所不同,而我选择的属性非常标准。将属性写入两次很麻烦,但它比在页面加载时将整个数据集加载到下拉框中要好,根据您拥有的数据量,这种行为可能非常低效。
def getCargoSources = {
if(params.id == ""){
render g.select(name: 'cargoSource.id', onchange: 'updateCargoes(); updateTotal()')
return
}
def getCargoes = {
if(params.id == ""){
render g.select(name: 'cargo.id', onchange: 'updateTotal()')
return
}
def cargoSource = Address.get(params.id)
def cargoes = Cargo.findAll("from Cargo as cargoes where cargoes.cargoSource=:cargoSource", [cargoSource: cargoSource])
render g.select(from: cargoes, name: 'cargo.id', noSelection: noSelection, onchange: 'updateTotal()', optionKey: 'id')
}
此时,您的链接下拉框应该可以正常工作了。
【讨论】: