Skip to main content

About this widget

The RelatedItems component computes search parameters to fetch related items. You can pass a hit as the reference for computing search parameters and retrieving the related items. To add RelatedItems to your search experience, use the following components:
  • Searcher. A new HitsSearcher that handles your searches for related items.
  • HitsView. A data class representing a search result.
  • T. An Indexable data class representing the hit to get related items.
This component acts similarly to the Hits component, but it only modifies the results.

Examples

You can use deserialize to convert raw hits into your own data class using the Serializable annotation.
Kotlin
class MyActivity : AppCompatActivity() {

  val searcher = HitsSearcher(
      applicationID = ApplicationID("YourApplicationID"),
      apiKey = APIKey("YourSearchOnlyAPIKey"),
      indexName = IndexName("YourIndexName")
  )
  val connection = ConnectionHandler()
  val adapter = ProductAdapter()

  val product = Product(
    objectID = ObjectID("objectID123"),
    name = "productName",
    brand = "Amazon",
    categories = listOf("Streaming Media Players", "TV & Home Theater")
  )
  val matchingPatterns = listOf(
      MatchingPattern(Attribute("brand"), 1, Product::brand),
      MatchingPattern(Attribute("categories"), 2, Product::categories)
  )

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)

      connection += searcher.connectRelatedHitsView(adapter, product, matchingPatterns) { response ->
          response.hits.deserialize(Product.serializer())
      }

      searcher.searchAsync()
  }

  override fun onDestroy() {
      super.onDestroy()
      connection.disconnect()
      searcher.cancel()
  }
}

@Serializable
data class Product(
    override val objectID: ObjectID,
    val name: String,
    val brand: String,
    val categories: List<String>
) : Indexable

class ProductAdapter : RecyclerView.Adapter<ProductViewHolder>(), HitsView<Product> {

    private var products: List<Product> = listOf()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
        return ProductViewHolder(parent.inflate(R.layout.list_item_product))
    }

    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
        val item = products[position]
        holder.bind(item)
    }

    override fun setHits(hits: List<Product>) {
        products = hits
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return products.size
    }
}

class ProductViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {

    fun bind(product: Product) {
        view.itemName.text = product.name
    }
}

Compose UI

Kotlin
class MyActivity : AppCompatActivity() {

    private val searcher = HitsSearcher(
        applicationID = ApplicationID("YourApplicationID"),
        apiKey = APIKey("YourSearchOnlyAPIKey"),
        indexName = IndexName("YourIndexName")
    )
    private val relatedItemsSearcher = HitsSearcher(
        applicationID = ApplicationID("YourApplicationID"),
        apiKey = APIKey("YourSearchOnlyAPIKey"),
        indexName = IndexName("YourIndexName")
    )

    private val productsHits = HitsState<Product>()
    private val relatedItems = HitsState<Product>()

    private val matchingPatterns: List<MatchingPattern<Product>> = listOf(
        MatchingPattern(Attribute("brand"), 1, Product::brand),
        MatchingPattern(Attribute("categories"), 2, Product::categories)
    )

    private var relatedItemConnection: Connection? = null
    private val productsSearchConnection = searcher
        .connectHitsView(productsHits) { it.hits.deserialize(Product.serializer()) }
        .also { it.connect() }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyRelatedItemsScreen(
                hits = productsHits.hits,
                relatedItems = relatedItems.hits,
                onProductClick = ::relatedItemsOf
            )
        }
        searcher.query.hitsPerPage = 3 // Limit to 3 results
        configureSearcher(searcher)
        configureSearcher(relatedItemsSearcher)
        searcher.searchAsync()
    }

    private fun relatedItemsOf(product: Product) {
        relatedItemConnection?.disconnect()
        relatedItemConnection = relatedItemsSearcher.connectRelatedHitsView(
            relatedItems, product, matchingPatterns
        ) { response ->
            response.hits.deserialize(Product.serializer())
        }
        relatedItemConnection?.connect()
        relatedItemsSearcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        searcher.cancel()
        relatedItemsSearcher.cancel()
        relatedItemConnection?.disconnect()
        productsSearchConnection.disconnect()
    }
}

Parameters

hit
T : Indexable
required
The reference hit to compute the search parameters to send to Algolia.You can retrieve this hit from any location (app state, your backend, the history, etc.)
Kotlin
val product = Product(
    objectID = ObjectID("objectID123"),
    name = "productName",
    brand = "Amazon",
    categories = listOf("Streaming Media Players", "TV & Home Theater")
)
matchingPatterns
List<MatchingPattern<T>>
required
A schema that creates scored filters based on the hit’s attributes.In the example below, the brand value gets a score of 1 while the category values get a score of 2.
Kotlin
data class Product(
    override val objectID: ObjectID,
    val name: String,
    val brand: String,
    val categories: List<String>
) : Indexable

val matchingPatterns: List<MatchingPattern<Product>> = listOf(
    MatchingPattern(Attribute("brand"), 1, Product::brand),
    MatchingPattern(Attribute("categories"), 2, Product::categories)
)
The hit above would generate the following search parameters:
JSON
{
  "sumOrFiltersScores": true,
  "facetFilters": ["objectID:-1234"],
  "optionalFilters": [
    ["brand:Amazon<score=1>"],
    [
      [
        "categories:TV & Home Theater<score=2>",
        "categories:Streaming Media Players<score=2>"
      ]
    ]
  ]
}
presenter
(ResponseSearch) -> List<T>
required
A function that transforms the search response into a list of results of your T class.
Kotlin
val presenter: (ResponseSearch) -> List<Product> = { response ->
    response.hits.deserialize(Product.serializer())
}
searcher.connectRelatedHitsView(adapter, product, matchingPatterns, presenter)
I