Open blackWins opened 1 year ago
And we can also create a js bound function to help user bound select2 to dynamic form property.
select2Bound.js:
function select2Bound(option) {
var _option = {
dom: '',
url: '',
text: 'name',
value: 'id',
data: 'items',
filter: 'filter',
allowClear: false
}
_option = Object.assign(_option, option)
var element = document.getElementById(_option.dom.replace('#', ''));
if (element && element.tagName !== 'SELECT') {
let autoCompleteSelect = $('<select></select>', {
id: element.attributes['id'].value,
name: element.attributes['name'].value,
class: 'auto-complete-select',
"data-autocomplete-api-url": _option.url,
"data-autocomplete-display-property": _option.text,
"data-autocomplete-value-property": _option.value,
"data-autocomplete-items-property": _option.data,
"data-autocomplete-filter-param-name": _option.filter,
"data-autocomplete-allow-clear": _option.allowClear,
});
autoCompleteSelect.insertAfter(element);
element.remove();
} else if (element) {
element.setAttribute("class", "auto-complete-select");
element.setAttribute("data-autocomplete-api-url", _option.url);
element.setAttribute("data-autocomplete-display-property", _option.text);
element.setAttribute("data-autocomplete-value-property", _option.value);
element.setAttribute("data-autocomplete-items-property", _option.data);
element.setAttribute("data-autocomplete-filter-param-name", _option.filter);
element.setAttribute("data-autocomplete-allow-clear", _option.allowClear);
} else {
abp.log.error('autoCompleteSelect not found element: ' + _option.dom)
}
}
used in page
//ViewModel:
public class CreateEditViewModel
{
[Display(Name = "AddressId")]
public Guid AddressId { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "Disable")]
public bool Disable { get; set; }
}
// CreateModal.cshtml
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="CreateModal">
<abp-modal>
<abp-modal-header title="@L["Create"].Value"></abp-modal-header>
<abp-modal-body>
<abp-form-content />
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
</abp-modal>
</abp-dynamic-form>
<script>
select2Bound({
dom: '#ViewModel_AddressId',
url: "/api/app/address-book",
text: "displayName",
value: "id",
data: "items",
filter: "displayName",
allowClear: true
});
</script>
My solution
[AttributeUsage(AttributeTargets.Property)]
public class AutoCompleteSelectAttribute : Attribute
{
public required string ApiUrl { get; set; }
public required string ItemsPropertyName { get; set; }
public required string DisplayPropertyName { get; set; }
public required string ValuePropertyName { get; set; }
public required string FilterParamName { get; set; }
public string? SelectedItemName { get; set; }
public string? SelectedItemValue { get; set; }
public string? ParentSelector { get; set; }
public string? AllowClear { get; set; }
public string? Placeholder { get; set; }
}
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AbpSelectTagHelperService), IncludeSelf = true)]
public class MyAbpSelectTagHelperService : AbpSelectTagHelperService
{
public MyAbpSelectTagHelperService(
IHtmlGenerator generator,
HtmlEncoder encoder,
IAbpTagHelperLocalizer tagHelperLocalizer,
IStringLocalizerFactory stringLocalizerFactory,
IAbpEnumLocalizer abpEnumLocalizer)
: base(generator, encoder, tagHelperLocalizer, stringLocalizerFactory, abpEnumLocalizer)
{
}
protected override Task<TagHelperOutput> GetSelectTagAsync(TagHelperContext context, TagHelperOutput output, TagHelperContent childContent)
{
var autoCompleteSelectAttributeAttribute = TagHelper.AspFor.ModelExplorer.GetAttribute<AutoCompleteSelectAttribute>();
if (autoCompleteSelectAttributeAttribute != null)
{
TagHelper.AutocompleteApiUrl ??= autoCompleteSelectAttributeAttribute.ApiUrl;
TagHelper.AutocompleteItemsPropertyName ??= autoCompleteSelectAttributeAttribute.ItemsPropertyName;
TagHelper.AutocompleteDisplayPropertyName ??= autoCompleteSelectAttributeAttribute.DisplayPropertyName;
TagHelper.AutocompleteValuePropertyName ??= autoCompleteSelectAttributeAttribute.ValuePropertyName;
TagHelper.AutocompleteFilterParamName ??= autoCompleteSelectAttributeAttribute.FilterParamName;
TagHelper.AutocompleteSelectedItemName ??= autoCompleteSelectAttributeAttribute.SelectedItemName;
TagHelper.AutocompleteSelectedItemValue ??= autoCompleteSelectAttributeAttribute.SelectedItemValue;
TagHelper.AllowClear ??= autoCompleteSelectAttributeAttribute.AllowClear;
TagHelper.Placeholder ??= autoCompleteSelectAttributeAttribute.Placeholder;
TagHelper.AutocompleteParentSelector ??= autoCompleteSelectAttributeAttribute.ParentSelector;
}
return base.GetSelectTagAsync(context, output, childContent);
}
}
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(AbpDynamicFormTagHelperService), IncludeSelf = true)]
public class MyAbpDynamicFormTagHelperService : AbpDynamicFormTagHelperService
{
public MyAbpDynamicFormTagHelperService(
HtmlEncoder htmlEncoder,
IHtmlGenerator htmlGenerator,
IServiceProvider serviceProvider,
IStringLocalizer<AbpUiResource> localizer)
: base(htmlEncoder, htmlGenerator, serviceProvider, localizer)
{
}
protected override bool IsSelectGroup(TagHelperContext context, ModelExpression model)
{
return model.ModelExplorer.GetAttribute<AutoCompleteSelectAttribute>() != null || base.IsSelectGroup(context, model);
}
}
Usage
[AutoCompleteSelect(
ApiUrl = "/api/app/identity-user",
DisplayPropertyName = "name",
ItemsPropertyName = "items",
ValuePropertyName = "id",
FilterParamName = "name",
AllowClear = "true")]
public Guid? IdentityUserId { get; set; }
we can also add a new attribute InputAction
.We can coding javascript filter function in it. Now we need to modify the
dom-event-handlers.js
// line:78
abp.dom.initializers.initializeAutocompleteSelects = function ($autocompleteSelects) {
...
let allowClear = $(this).data("autocompleteAllowClear");
let placeholder = $(this).data("autocompletePlaceholder");
let inputAction = eval("(" + $(this).data("autocompleteInputAction") + ")"); //added this line
...
delay: 250,
dataType: "json",
data: function (params) {
let query = typeof (inputAction) === 'function' ? inputAction() : {}; //modified this line
query[filterParamName] = params.term;
return query;
},
processResults: function (data) {
now we can customize more query parameters.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Is there an existing issue for this?
Is your feature request related to a problem? Please describe the problem.
No response
Describe the solution you'd like
Additional context
No response