CRUD
CRUD copied to clipboard
[Pro] HTML in Select2 fields
Discussed in https://github.com/Laravel-Backpack/community-forum/discussions/1109
Originally posted by giovdi August 7, 2024 Hi everyone! Today, I was wondering if it's possible to write HTML into a Select2 dropdown with Backpack. Well, the short answer (I think) is no... but...
I tried looking at the code that generates the Select2 Javascript for my specific case, and it is probably pretty easy to do.
In this example, I added the following code blocks to backpack/pro/resources/views/fields/relationship/select.blade.php.
// make sure the $field['value'] takes the proper value
$current_value = old_empty_or_null($field['name'], []) ?? $field['value'] ?? $field['default'] ?? [];
+ if(isset($field['html']) && !is_array($field['html'])) {
+ $field['html'] = [true];
+ }
+ $activeHtml = !empty($field['html']) ? true : false;
+
+ if ($activeHtml) {
+ $field['html']['base_element'] = $field['html']['base_element'] ?? 'span';
+ }
if (!empty($current_value) || is_int($current_value)) {
switch (gettype($current_value)) {
@if($field['multiple'])
multiple
@endif
+ data-html="{{ var_export($field['allows_null']) }}"
+ @if($activeHtml)
+ data-html-element="{{ $field['html']['base_element'] }}"
+ @endif
>
function bpFieldInitRelationshipSelectElement(element) {
const $placeholder = element.attr('data-placeholder');
const $multiple = element.attr('data-field-multiple') == 'false' ? false : true;
+ const $html = element.attr('data-html') == 'true' ? true : false;
+ const $htmlElement = element.attr('data-html-element');
const $allows_null = (element.attr('data-column-nullable') == 'true') ? true : false;
var $select2Settings = {
theme: 'bootstrap',
multiple: $multiple,
placeholder: $placeholder,
allowClear: $allowClear,
dropdownParent: $isFieldInline ? $('#inline-create-dialog .modal-content') : $(document.body)
};
+ if ($html) {
+ $select2Settings.templateSelection = function(elem) {
+ if (!elem.id) {
+ return elem.text;
+ }
+
+ return $('<'+$htmlElement+'>'+elem.text+'</'+$htmlElement+'>');
+ }
+ $select2Settings.templateResult = function(elem) {
+ if (!elem.id) {
+ return elem.text;
+ }
+
+ return $('<'+$htmlElement+'>'+elem.text+'</'+$htmlElement+'>');
+ }
+ }
if (!$(element).hasClass("select2-hidden-accessible"))
At this point, I can add the following option to the CRUD:
CRUD::field([
'name' => 'variants',
'type' => "relationship",
'inline_create' => true,
'init_rows' => 1,
'min_rows' => 1,
'subfields' => [
[
'name' => 'price',
'label' => 'Price',
'type' => 'number',
'prefix' => "€",
'attributes' => ["step" => "any"],
'wrapper' => [
'class' => 'form-group col-md-3'
],
],
[
'name' => 'weight_initial',
'label' => 'Weight',
'type' => 'number',
'suffix' => "grams",
'wrapper' => [
'class' => 'form-group col-md-3'
],
],
],
'pivotSelect' => [
+ 'html' => true,
'wrapper' => [
'class' => 'form-group col-md-6'
],
'options' => (function ($query) {
return $query->orderBy('variant_name', 'ASC')->get();
})
],
]);
...and with the following accessor:
public function identifiableAttribute()
{
return 'variant_name_full';
}
protected function variantNameFull(): Attribute
{
return Attribute::make(
get: function () {
$ret = '';
if (!empty($this->product->filament_material)) {
$ret .= '<span class="badge badge-primary">'.$this->product->filament_material->filament_material.'</span> ';
}
if (!empty($this->attributes['color'])) {
$ret .= '<span class="badge" style="border:1px solid black; background-color:'.$this->attributes['color'].'"> </span>';
}
$ret .= " ".$this->product->manufacturer->manufacturer_name . ' - ' . $this->product->product_name . ' - ' . $this->attributes['variant_name'];
if (!empty($this->code)) {
$ret .= ' ('.$this->code.')';
}
return $ret;
},
);
}
...here is the result!
Not so bad, isn't it?
As you can see from the code blocks, a <span> tag surrounds the HTML option, but you can customize it with the base_element property, as follows: 'html' => ['base_element' => 'div'].
You can't avoid this because if you mix plain text options and HTML ones, the $(elem.text); fails with a JS error, so at least one HTML tag is required.
Please let me know your suggestions... or if I just lost 2 hours of my life for some option that I don't know 😄 Unfortunately, I don't have enough time to create a full PR in a reasonable time, so please, if it's a good idea, take care of it :)
Thanks a lot!
I was 1 minute into reading it and was ready to say "NO" but, holy shit... can this be useful! Like for example... when you have a selector for people - to show the avatar too. Or show both the name and their email, but in a nice way, not in the standard John Doe - [email protected].
I like this, I think it's a nice COULD-DO. Buuuut.... I would mean having to do this in all our select2s right 🤦♂️ So it would take quite some time to actually implement it in Backpack PRO 😔