Instantsearch.js: InstantSearch dynamic remove/add widgets

Created on 27 Sep 2017  路  5Comments  路  Source: algolia/instantsearch.js

InstantSearch::removeWidget

The goal is to be able to mount and unmount widgets from the instantSearch instance dynamically. With such a feature we would be able to build "dynamic" search experiences.

First API proposal

Every widgets are implementing a getConfiguration() method which is indicating what SearchParameters do we need to set before querying Algolia API.

We use this method to guess which SearchParameters we need to remove from the SearchParameters when we unmount this widget.

Removing a widget also implies some DOM operations in order to remove the widget from the page. In this solution we are attaching to the widget instance a reference to the DOM node where the widget is mounted and we "automatically" remove all the content of the node.

PROS

  • Non-breaking changes API
  • Will work with most of the widgets already written, not a lot of code changes

CONS

  • It's not 100% safe since we are "guessing" which parameters to change after removing the widget
  • If we run into issue, the code will have a lot of if/else branches and will become spaghetti
  • Can't remove the refined value of the NumericRefinementList and SortBySelector

Second API proposal

In the first proposal, almost everything is done into the InstantSearch class itself. Which is great for non-breaking changes update and it should work with the widgets already implemented. But it's also "risky" because we cannot implement a custom method for a widget behaving really differently than the others.

To avoid these potential issues, we are enhancing the connectors API. Connectors accepts a first parameters which will be the renderFn and now they do accept a function unmountFn which will be responsible to remove the widget from the DOM if it is requested to.

And widgets have now a new method dispose() which takes as parameters the helper instance and the current SearchParameters / helper.state. The dispose() method will call the unmountFn and return the next SearchParameters after the widget is removed (if needed).

PROS

  • Each widget is responsible for his unmount logic
  • We can test each dispose() and unmountFn separately

CONS

  • More boilerplate code
  • Semi-breaking changes in the connectors & widgets API

Conclusion

The first proposal is a sexy way to do it, because it's "automatically" and will work most of the time and it does not require updates from the clients.

But in the end, when we will have complex cases it will become more tricky to maintain. Sometime it's better to well separate concerns and I think here it's the case. For instance with the first proposal there's no easy solution to know when to remove the refined value for the NumericRefinementList and the SortBySelector

Every own widgets should be aware of how to mount and unmount themselves: it will be easier to test and to maintain.

You can find the two PRs and the code here:

Connectors Core Widgets Refactor

Most helpful comment

What would you think about swapping one widget for another?

Yes this is a potential usecase, but I don't really have something in mind for it now.

I was also thinking of a InstantSearch::dispose method that will remove everything from the page, when for instance the user change page on a SPA.

All 5 comments

I like the decentralized aspect of the second proposal. And even though it's gonna be another method to implement, it's not mandatory if you don't plan to remove the widget so we can still hack / prototype widget. Also it makes for a more explicit API.

I have some questions:

  • do you have something planned to lower the number of search calls in case of multiple remove?
  • do you have an idea for the dynamic addWidget?

Do you have something planned to lower the number of search calls in case of multiple remove?

This would be easily implemented, we can enhance the API of removeWidget() to accept an Array of widgets instances and compute the SearchParameters for the next search before triggering it.

Do you have an idea for the dynamic addWidget?

I need to do the PoC, but from the code of InstantSearch.js we can track if the search is already started and here call this same function to update the SearchParameters before triggering a new search 馃憤

This would be easily implemented, we can enhance the API of removeWidget() to accept an Array of widgets instances and compute the SearchParameters for the next search before triggering it.

Yes indeed that's a good improvement of the API.

What would you think about swapping one widget for another?

What would you think about swapping one widget for another?

Yes this is a potential usecase, but I don't really have something in mind for it now.

I was also thinking of a InstantSearch::dispose method that will remove everything from the page, when for instance the user change page on a SPA.

Merged in feat/2.3 馃帀

Was this page helpful?
0 / 5 - 0 ratings