algolia / autocomplete

🔮 Fast and full-featured autocomplete library
https://alg.li/autocomplete
MIT License
5.04k stars 329 forks source link

Introduce defaults #99

Closed legshooter closed 6 years ago

legshooter commented 8 years ago

Hey guys,

Have you considered introducing defaults?

Having to write all the boilerplate on the same (or very similar) implementations across an app is kinda daunting and not very DRY.

What do you think?

vvo commented 8 years ago

HI @legshooter, to better understand your issue, can you be more explicit by giving a bit of code sample that is concerned by your issue?

legshooter commented 8 years ago

Hi @vvo,

Sure, I mean a defaults object like many other plugins have, that gets merged with the object's options, e.g.

$.extend(true, {}, $.fn[pluginName].defaults, options);

If I want to implement the same behaviour for 100 autocompletes in my app, why should I retype:

$('.selector').autocomplete({
    minLength: 2,
    autoselect: true,
    openOnFocus: true,
},

And even further, with the datasource:

[
    {
        source: debounce(function (query, callback) {
            $.ajax(route + '/' + query,
                {
                    beforeSend: function () {
                        processingIcon.removeClass('hidden');
                    },
                    complete: function () {
                        processingIcon.addClass('hidden');
                    }
                })
                .done(function (suggestions) {
                    callback(suggestions);
                });
        }, 300),
        displayKey: displayKey,
        templates: {
            suggestion: function (suggestion) {
                var regExp = new RegExp('(' + search.autocomplete('val') + ')', 'giu');
                return e(suggestion.name).replace(regExp, '<span class="aa-highlight">$1<\/span>');
            },
        }
    }
]);

This is just an example of course, but why should I write this 100 times, when possibly all I need to change between implementations the is route var? Or route, processingIcon, displayKey and suggestion function?

And even further, with events:

// highlight first suggestion
.on('autocomplete:shown', function (event) {
    $(event.target).closest('.algolia-autocomplete').find('.aa-suggestion').first().addClass('aa-cursor');
})
// turn suggestions to links
.on('autocomplete:selected', function (event, suggestion, datasetName) {
    $.pjax({url: suggestion.url, container: '#pjax'});
})

If I have a way to set defaults for this kind of stuff, I can have a sort of a "template" for my settings, and when one of my implementations diverges from the default, I only need to override those specific details that are different, instead of copy-pasting everything all over again.

vvo commented 8 years ago

Hi @legshooter we already have defaults internally for example if you only specify hint: false you will still get the default settings.

We could expose those default settings of autocomplete.js but I am failing at seeing what would be the use case since we already do merging of parameters internally.

The examples you gave me seems to be defaults of your application not defaults for the whole community.

I feel I am missing some context/use case to better understand what you mean.

legshooter commented 8 years ago

This is exactly what I am talking about, most serious jQuery plugins out there expose defaults for the user to change (I did it myself with addel).

The examples are my own, but it's the principle, it has nothing to do with any specific option I choose to use.

The advantage is, again just for example, that the user can set 10 options as the defaults, and then instantiate aa 50 different times across his app, and only tweak one or two options here and there when that specific instantiation differs from what he set earlier as default.

In the current situation, sticking to the same example, the user would have to copy-paste all 10 options to each and every one of the 50 instantiations. It's writing 50 * 10 duplicated lines, instead of 1 * 10 + 49 * 1.

You can always use a shared selector, e.g. $('.input').autocomplete(...), for all 50 instantiations, to force them to share options, but then what happens when you want only some of the 50 to have a different option X? You're 'locked' in, any change you make will effect all instantionations because of the shared selector, and that's exactly the benefit that exposing defaults to the user bring to the table.

Again, numbers are just an example, they don't really matter, and what specific options each one chooses for himself matter even less.

Hope I made things a bit clearer :)

vvo commented 8 years ago

Hi @legshooter do you have a good example of a plugin proposing defaults and how it can be used to be enhanced and applied everywhere?

If I understand well it's like providing an object containing defaults options and if you mutate (modify) it, it will be applied to any call to .autocomplete?

legshooter commented 8 years ago

Exactly.

Select2 and DataTables are a couple of popular jQuery plugins with an exposed defaults object/API, and provide some explanations of their own.

vvo commented 8 years ago

Ok now I fully understand what you meant. One challenge thought is that autocomplete.js is currently a jQuery, vanilla JS and angular JS plugin. So we would also have to find API proposals that would fit for vanilla JS or angular JS.

This default object behavior seems to be very popular with jQuery plugins indeed.

I would say you should keep doing what you are doing today: manually handling yourself your own defaults instead of willing to include this in the library.

You could do this:

var myDefaults = {
    minLength: 2,
    autoselect: true,
    openOnFocus: true,
};

autocomplete('....', myDefaults);
autocomplete('......', myDefaults);

If you want to change some defaults per instantiation:

var myDefaults = {
    minLength: 2,
    autoselect: true,
    openOnFocus: true,
};

autocomplete('....', myDefaults);
autocomplete(
  '......',
  Object.assign(
    {},
    myDefaults,
    {minLength: 3}
  )
); // compatible with all modern browsers

I do not believe there's a very important user base that would benefit from having those default parameters. Unlike Select2 or DataTables, usecases where you would want to instantiate 20 or 30 different autocomplete.js are rare today.

And even if you have the use case, you can still use the solutions I gave you.

Thanks for explaining clearly to me your issue and I hope your understand the choice.

I will let other maintainters chime in for some time if they want and then we will close this more probably.

Haroenv commented 6 years ago

We didn't see this as a necessary feature, because of the reasons @vvo mentioned in his previous comment and there being a fairly simple workaround which doesn't really have downsides and prevents us from having to make this work in all three of the flavours.

Feel free to open a new issue or pull request if you think this is an essential feature to have.

Have a nice new year 🎆