首先自定义input表单:
class TaxonSelectInput < SimpleForm::Inputs::CollectionSelectInput
include ActionView::Helpers::FormTagHelper
def input(wrapper_options = nil)
data = options[:data] || {}
class_name = self.class.name.underscore.dasherize
template.content_tag(:div, class: "taxon-picker #{class_name}", data: data) do
template.concat(
select_tag(:"#{attribute_name}_taxonomies", nil, class: 'taxonomies')
)
template.concat(
select_tag(:"#{attribute_name}_taxons", nil, class: 'taxons')
)
template.concat super(wrapper_options)
end
end
end
因为数据库设计问题,我这里需要2个不同的下拉
js开发
const Cache = {}
const root = ''
export default class TaxonPicker {
static defaults = {
taxonomiesUrl: '/api/xxx',
taxonsUrl: '/api/xxx',
taxonChildrenUrl: '/api/xxx'
}
/**
* Creates a new instance of a china district picker.
* @class
* @param {jQuery} element - jQuery object to make into a picker.
* @param {Object} options - Overrides to the default plugin settings.
*/
constructor(element, options) {
this.$element = element
this.options = $.extend({}, TaxonPicker.defaults, this.$element.data(), options)
this.taxon_id = `${this.options.taxon_id}`
this.selectedData = {
selectedTaxonomy: null,
selectedTaxon: null,
selectedTaxonChildren: null,
}
this.$taxonomies = this.$element.find('.taxonomies')
this.$taxons = this.$element.find('.taxons')
this.$taxonChildren = this.$element.find('.taxon_children')
}
init() {
this.loadTaxonomies()
this.attachEvents()
this.$taxonChildren.addClass('hide')
// this.test()
}
attachEvents() {
this.$taxonomies.on('change', () => {
this.selectedData.selectedTaxonomy = this.$taxonomies.val()
this.selectedData.selectedTaxon = null
this.selectedData.selectedTaxonChildren = null
this.$taxons.empty()
this.$taxonChildren.empty()
this.loadTaxons(this.selectedData.selectedTaxonomy)
.then(() => {
this.$taxonChildren.empty()
})
})
this.$taxons.on('change', () => {
this.selectedData.selectedTaxon = this.$taxons.val()
this.selectedData.selectedTaxonChildren = null
this.$taxonChildren.empty()
this.loadTaxonChildren(this.$taxons.val())
})
this.$taxonChildren.on('change', () => {
this.selectedData.selectedTaxonChildren = this.$taxonChildren.val()
})
}
loadTaxonomies = () => {
let ret
if (Cache[root]) {
ret = Promise.resolve(Cache[root])
} else {
ret = $.get(this.options.taxonomiesUrl).then((divisions) => {
Cache[root] = divisions
return divisions
})
}
return ret.then((taxonomies) => {
this.resetOptions(
this.$taxonomies,
taxonomies,
this.selectedData.selectedTaxonomy
)
})
}
loadTaxons = (taxonomyId) => {
let ret
if (Cache[taxonomyId]) {
ret = Promise.resolve(Cache[taxonomyId])
} else {
ret = $.get(this.options.taxonsUrl, { id: taxonomyId }).then((divisions) => {
Cache[taxonomyId] = divisions
return divisions
})
}
return ret.then((taxons) => {
this.resetOptions(
this.$taxons,
taxons,
this.selectedData.selectedTaxon
)
})
}
loadTaxonChildren = (parentId) => {
let ret
if (Cache[parentId]) {
ret = Promise.resolve(Cache[parentId])
} else {
ret = $.get(this.options.taxonChildrenUrl, { id: parentId }).then((divisions) => {
Cache[parentId] = divisions
return divisions
})
}
return ret.then((taxonChildren) => {
this.resetOptions(
this.$taxonChildren,
taxonChildren,
this.selectedData.selectedTaxonChildren
)
})
}
resetOptions = ($selector, divisions, selectedId) => {
$selector.empty()
let collection = divisions
const isSubSelector = $selector
if (isSubSelector && divisions.length === 0) {
collection = Cache[root].filter((division) => division.id)
$selector.addClass('hide')
} else {
$selector.removeClass('hide')
}
collection.forEach((division) => {
const optionElement = $(document.createElement('option'))
const attributes = {
value: division.id,
selected: `${selectedId}` === division.id
}
optionElement.attr(attributes).text(division.name)
$selector.append(optionElement)
})
}
}
使用:
<%= f.input :taxon_id,
as: :taxon_select,
input_html: { class: "taxon_children" },
data: { 'taxon_id': f.object.taxon_id, 'level': 3 },
label_html: { for: "taxons" },
label: '产品分类' %>