Skip to content

Latest commit

 

History

History
136 lines (106 loc) · 5.64 KB

integral_lists.md

File metadata and controls

136 lines (106 loc) · 5.64 KB
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

How to use lists

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>

Linking objects to lists

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.

Helpers

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.

Making a custom object listable

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;

  1. Enable listable through acts_as_integral options
acts_as_integral({
  listable: { enabled: true }
})
  1. 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

Limitations

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
  • List Item 2
    • Child 1

Further Questions?

Fill an issue on [GitHub]((https://github.com/yamasolutions/integral)