Skip to content

Commit bf6b3a2

Browse files
authored
Merge pull request #469 from platanus/fix-tags
feat(tags-input): rework to return array
2 parents 6ca6e17 + 033dceb commit bf6b3a2

File tree

5 files changed

+26
-91
lines changed

5 files changed

+26
-91
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
77
#### Breaking changes
88
* Defines required ruby version to >=2.7.0 [#460](https://github.com/platanus/activeadmin_addons/pull/460)
99
* Nested and search select now use the name of the association instead of the name of id [#462](https://github.com/platanus/activeadmin_addons/pull/462)
10+
* Tags input now returns an array of strings instead of a string [#469](https://github.com/platanus/activeadmin_addons/pull/469)
1011

1112
#### Fixes
1213
* Include only items that belong to parent when using collection option in a nested input level [#463](https://github.com/platanus/activeadmin_addons/pull/463)

app/inputs/tags_input.rb

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
1-
class TagsInput < ActiveAdminAddons::InputBase
1+
class TagsInput < ActiveAdminAddons::SelectInputBase
22
include ActiveAdminAddons::SelectHelpers
33

44
def render_custom_input
5-
if active_record_select?
6-
return render_collection_tags
7-
end
8-
9-
render_array_tags
5+
render_collection_tags
106
end
117

128
def load_control_attributes
13-
load_data_attr(:model, value: model_name)
14-
load_data_attr(:method, value: method)
9+
@options[:multiple] = true
1510
load_data_attr(:width)
1611

1712
if active_record_select?
@@ -24,32 +19,8 @@ def load_control_attributes
2419

2520
private
2621

27-
def render_array_tags
28-
render_tags_control { build_hidden_control(prefixed_method, method_to_input_name, input_value) }
29-
end
30-
3122
def render_collection_tags
32-
render_tags_control { render_selected_hidden_items }
33-
end
34-
35-
def render_tags_control(&block)
3623
concat(label_html)
37-
concat(block.call)
38-
concat(builder.select(build_virtual_attr, [], {}, input_html_options))
39-
end
40-
41-
def render_selected_hidden_items
42-
template.content_tag(:div, id: selected_values_id) do
43-
template.concat(build_hidden_control(empty_input_id, method_to_input_array_name, ""))
44-
input_value.each do |item_id|
45-
template.concat(
46-
build_hidden_control(
47-
method_to_input_id(item_id),
48-
method_to_input_array_name,
49-
item_id.to_s
50-
)
51-
)
52-
end
53-
end
24+
concat(builder.select(method, [], input_options, input_html_options))
5425
end
5526
end

app/javascript/activeadmin_addons/inputs/slim-select-tags.js

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ const classes = ['tags-input'];
22

33
// eslint-disable-next-line max-statements
44
function settings(el) {
5-
const model = el.dataset.model;
6-
const method = el.dataset.method;
7-
const prefix = `${model}_${method}`;
85
const isRelation = el.dataset.relation === 'true';
96
const collection = el.dataset.collection ? JSON.parse(el.dataset.collection) : null;
107

@@ -14,38 +11,7 @@ function settings(el) {
1411
return { ...rest, value: id, selected: !!item.selected };
1512
});
1613

17-
function fillHiddenInput(values) {
18-
const hiddenInput = document.querySelector(`#${prefix}`);
19-
hiddenInput.value = values.map(val => val.value).join();
20-
}
21-
22-
const events = {
23-
afterChange: (newVal) => {
24-
if (isRelation) {
25-
const selectedItemsContainer = document.querySelector(`#${prefix}_selected_values`);
26-
const itemName = `${model}[${method}][]`;
27-
selectedItemsContainer.innerHTML = '';
28-
29-
newVal.forEach((data) => {
30-
const itemId = `${prefix}_${data.value}`;
31-
if (document.querySelectorAll(`#${itemId}`).length > 0) {
32-
return;
33-
}
34-
35-
const hiddenInput = document.createElement('input');
36-
hiddenInput.id = itemId;
37-
hiddenInput.name = itemName;
38-
hiddenInput.value = data.value;
39-
hiddenInput.type = 'hidden';
40-
41-
selectedItemsContainer.appendChild(hiddenInput);
42-
});
43-
} else {
44-
fillHiddenInput(newVal);
45-
}
46-
},
47-
};
48-
14+
const events = {};
4915
if (!isRelation) {
5016
events.addable = (value) => value;
5117
}
@@ -56,12 +22,7 @@ function settings(el) {
5622
};
5723
}
5824

59-
function init(el) {
60-
el.multiple = true;
61-
}
62-
6325
export {
6426
settings,
6527
classes,
66-
init,
6728
};

docs/slim-select_tags.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
## Tagging
44

5-
To enable Slim Select with tags functionality you need to do the following:
5+
To allow selecting multiple values, you can use the `:tags` input type:
66

77
```ruby
88
f.input :names, as: :tags
99
```
1010

11-
You can load previous created tags using `collection` option passing an array of strings like this:
11+
You can load previously created tags using `collection` option passing an array of strings like this:
1212

1313
```ruby
1414
f.input :names, as: :tags, collection: ['Diego', 'Leandro', 'Guillermo']
@@ -36,9 +36,15 @@ So, in the ActiveAdmin's Event form, you can add:
3636
f.input :performer_ids, as: :tags, collection: Performer.all, display_name: :full_name
3737
```
3838

39-
> Remember: the input name must be: `performer_ids` not `performers` and you need to add to `permit_params` the `performer_ids: []` key.
39+
> Remember: the input name must be: `performer_ids` not `performers`.
4040
41-
### Options
41+
## :warning: Gotchas
42+
43+
Note that this input type uses a regular select with `multiple: true` under the hood. As such, it also returns an array of string, so **remember to add your attribute as an array to the permitted_params**, such as `performer_ids: []`.
44+
45+
Moreover, this input is subject to [this same limitation](https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#:~:text=Gotcha-,The%20HTML%20specification,-says%20when%20multiple) that multiple select inputs have: the returned array will always contain an empty string. When using with AR relations or something like [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on) this shouldn't be an issue, as an empty string won't trigger the creation of a new record. However, in other cases, like when using **postgres array column**, this might be a problem. Be sure to sanitize this value before saving in those cases.
46+
47+
## Options
4248

4349
* `display_name`: **(optional)** You can pass an optional `display_name` to set the attribute (or method) to show results on the select. It **defaults to**: `name`
4450
* `value`: **(optional)** You can pass an optional `value` to set the attribute (or method) to use when an item is selected. It **defaults to**: `id`

spec/features/inputs/tags_input_spec.rb

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
end
3535
end
3636

37-
context "working with active record relations" do
37+
context "when working with active record relations" do
3838
before do
3939
register_form(Invoice) do |f|
4040
f.input :item_ids, as: :tags, collection: Item.all
@@ -51,14 +51,12 @@
5151
context "with added item" do
5252
before { pick_slimselect_entered_option(@item1.name) }
5353

54-
it "adds/removes hidden item", js: true do
55-
item_id = "#invoice_item_ids_#{@item1.id}"
56-
input = find(item_id, visible: false)
57-
expect(input.value).to eq(@item1.id.to_s)
58-
expect(input[:name]).to eq("invoice[item_ids][]")
54+
it "includes and then removes item from select value", js: true do
55+
select_selector = "select[name='invoice[item_ids][]']"
56+
expect(find(select_selector, visible: false).value).to include(@item1.id.to_s)
5957
find(".ss-value-delete").click
6058
sleep 0.5
61-
expect { find(item_id, visible: false) }.to raise_error(Capybara::ElementNotFound)
59+
expect(find(select_selector, visible: false).value).not_to include(@item1.id.to_s)
6260
end
6361

6462
it "does not allow new items", js: true do
@@ -72,7 +70,7 @@
7270
end
7371
end
7472

75-
context "working with active record relations but alias" do
73+
context "when working with active record relations but alias" do
7674
before do
7775
register_form(Invoice) do |f|
7876
f.input :other_item_ids, as: :tags, collection: Item.all
@@ -89,14 +87,12 @@
8987
context "with added item" do
9088
before { pick_slimselect_entered_option(@item1.name) }
9189

92-
it "adds/removes hidden item", js: true do
93-
item_id = "#invoice_other_item_ids_#{@item1.id}"
94-
input = find(item_id, visible: false)
95-
expect(input.value).to eq(@item1.id.to_s)
96-
expect(input[:name]).to eq("invoice[other_item_ids][]")
90+
it "includes and then removes item from select value", js: true do
91+
select_selector = "select[name='invoice[other_item_ids][]']"
92+
expect(find(select_selector, visible: false).value).to include(@item1.id.to_s)
9793
find(".ss-value-delete").click
9894
sleep 0.5
99-
expect { find(item_id, visible: false) }.to raise_error(Capybara::ElementNotFound)
95+
expect(find(select_selector, visible: false).value).not_to include(@item1.id.to_s)
10096
end
10197
end
10298
end

0 commit comments

Comments
 (0)