id | title | sidebar_label |
---|---|---|
integral-lists |
Lists |
Lists |
Lists are used within Integral to organise data such as links, images, posts etc. Lists are most useful when they represent data that users will frequently want to change, for instance a menu (list of links) or a gallery (list of images).
Lists are managed at /admin/lists
, all users can view, create, edit and delete lists. Other features include;
- Cloning a list
- Linking objects to a list item
- Linking an image to a list item
- Setting whether or not list items can have children
- Setting a maximum amount of list items
- Organising the order of list items
Lists are visualised using a ListRenderer
. Pass a list to a ListRenderer and call .render
to output HTML.
The default output of the ListRenderer is an unordered list. Take for example the 3 highest grossing movies of all time;
list = Integral::List.create(title: '3 highest grossing movies of all time',
list_items: [
Integral::ListItem.create(title: 'Avatar'),
Integral::ListItem.create(title: 'Titanic'),
Integral::ListItem.create(title: 'Star Wars: The Force Awakens')
])
Integral::ListRenderer.render(list)
=> "<ul><li><a>Avatar</a></li><li><a>Titanic</a></li><li><a>Star Wars: The Force Awakens</a></li></ul>"
You can pass options to the ListRenderer, for example to change this to an ordered list;
Integral::ListRenderer.render(list, wrapper_element: 'ol')
=> "<ol><li><a>Avatar</a></li><li><a>Titanic</a></li><li><a>Star Wars: The Force Awakens</a></li></ol>")
Rather than just generic ListItems we can also add Links to lists and render them out;
list = Integral::List.create(title: '3 highest grossing movies of all time',
list_items: [
Integral::Link.create(title: 'Avatar', url: 'https://en.wikipedia.org/wiki/Avatar_(2009_film)'),
Integral::Link.create(title: 'Titanic', url: 'https://en.wikipedia.org/wiki/Titanic_(1997_film)'),
Integral::Link.create(title: 'Star Wars: The Force Awakens', url: 'https://en.wikipedia.org/wiki/Star_Wars:_The_Force_Awakens')
])
Integral::ListRenderer.render(list)
=> ""<ul><li><a href=\"https://en.wikipedia.org/wiki/Avatar_(2009_film)\">Avatar</a></li><li><a href=\"https://en.wikipedia.org/wiki/Titanic_(1997_film)\">Titanic</a></li><li><a href=\"https://en.wikipedia.org/wiki/Star_Wars:_The_Force_Awakens\">Star Wars: The Force Awakens</a></li></ul>""
That's all well and good but what if we want to create a more complicated layout for each of the items? That's where PartialListItemRenderer
comes into play. Pass this Renderer a partial view path and the output will be generated by running each item through the partial view.
Integral::ListRenderer.render(list, { wrapper_element: 'div', item_renderer: Integral::PartialListItemRenderer, item_renderer_opts: { partial_path: 'shared/movie_card' }})
=> ""<div><span>Avatar - Complex Card Partial</span><span>Titanic - Complex Card Partial</span><span>Star Wars: The Force Awakens - Complex Card Partial</span></div>
Lists start to become really powerful when you use the PartialListItemRenderer to render list items linked to an object.
For example a user can create a list of their favourite blog posts, you can then pass that list into a ListRenderer along with a partial view path which would represent each list item.
list = Integral::List.create(title: 'Johns Top Picks',
list_items: [
Integral::Object.create( object: FactoryBot.create(:integral_post)),
Integral::Object.create( object: FactoryBot.create(:integral_post)),
Integral::Object.create( object: FactoryBot.create(:integral_post))
])
Integral::ListRenderer.render(list, { wrapper_element: 'div', html_classes: 'grid-x grid-padding-x align-center show-for-medium', item_renderer: Integral::PartialListItemRenderer, item_renderer_opts: { partial_path: 'shared/top_pick_post' }})
=> ""<div class='grid-x grid-padding-x align-center show-for-medium'><div>Avatar ...</div><div>Titanic ...</div><div>Star Wars ...</div></div>""
If a listRenderer cannot find the list or they're no list items the Renderer will output a HTML comment.
There is a helper method render_list which can be used to easily render lists in views
render_list(Integral::List.find_by_id(12), opts)
Remember to use find_by_id
which if a record isn't found will return nil, and be handled by the renderer, rather than error out with RecordNotFound
.
If you have created a custom object and would like Users to be able to select it as a ListItem through the UI you need to do the following;
- Enable listable through
acts_as_integral
options
acts_as_integral({
listable: { enabled: true }
})
- Set list item values to represent object instances
# @return [Hash] the instance as a list item
def to_list_item
subtitle = published_at.present? ? I18n.t('integral.blog.posted_ago', time: time_ago_in_words(published_at)) : I18n.t('integral.users.status.draft')
{
id: id,
title: title,
subtitle: subtitle,
description: description,
image: attachment, # Expects Integral::Storage::File or ActiveStorage::Attachment as #representation will be called
url: Integral::Engine.routes.url_helpers.post_url(self)
}
end
Lists can only have items 2 levels deep.
Valid List
- List Item 1
- Child 1
- Child 2
- List Item 2
- Child 1
Invalid List
- List Item 1
- Child 1
Invalid Item
- Child 1
- List Item 2
- Child 1
Fill an issue on [GitHub]((https://github.com/yamasolutions/integral)