Selectize.js: Preserve custom HTML5 data attributes

Created on 3 Jan 2014  ·  60Comments  ·  Source: selectize/selectize.js

Feature request

Preserve custom HTML5 data attributes, so that in this case data-fruit won't disappear when going from <select> to Selectize:

http://jsfiddle.net/k44p2by6/

consensus on need enhancement pull request welcome

Most helpful comment

I think that it's already possibile to do that without extending the plugin (certainly, a full support will be appreciated) simply using the onInitialize method in combination with the revertSettings attribute (jsfiddle):

$('select').selectize({
    onInitialize: function () {
        var s = this;
        this.revertSettings.$children.each(function () {
            $.extend(s.options[this.value], $(this).data());
        });
    }
});

The possibilities are infinite with this feature, like a FULL HTML SELECT.

All 60 comments

+1

I've created a plugin to override -not extend- the function which changes the original select options.

Selectize.define('preserve_original_select', function(options) {
  var self = this;

  this.updateOriginalInput = (function() {
    var original = self.updateOriginalInput;
    return function() {
      var i, n, options, self = this;

      if (self.$input[0].tagName.toLowerCase() === 'select') {
        for (i = 0, n = self.items.length; i < n; i++) {
          self.$input.find('[value="'+self.items[i]+'"]').prop('selected', true);
        }
      } else {
        self.$input.val(self.getValue());
      }

      if (self.isSetup) {
        self.trigger('change', self.$input.val());
      }

      // original.apply(this, arguments);
    };
  })();

});

Don't forget to load the plugin.

Plugin is good but data-attributes in OPTIONs shouldn't disappear by default.
It is hurt for transparent selectizing of existing SELECT elements.

Yes! Selectize should be updated to allow for the preservation of custom attributes in each option.

+1

Would really appreciate a fix to this. Can't get plugin working.

+1

Agreed, selectize should retain data attributes

+1

I have no idea how I got CC'd on all the posts to this list, but I'd appreciate it if it stopped. Thanks!

On Sep 1, 2014, at 8:05 AM, Stephan Helbig [email protected] wrote:

+1


Reply to this email directly or view it on GitHub.

+1

+1

+1

+1

This is working.

$(ele).selectize({
.....
dataAttr: 'data-extra', //default is data-data
.....
}
});

Add data-extra in every option as json encoded, Ex
option value="one" data-extra="{'test':'123'}"
option value="two" data-extra="{'test':'456'}"

Get the selectize instance using this, var selectize = $(ele)[0].selectize

Users selected options can be found here: selectize.items

Data attributes of all options can be found here: selectize.options

In our case it will be,
selectize.options['one'].test
selectize.options['two'].test

Let me know if this is working.

I think that it's already possibile to do that without extending the plugin (certainly, a full support will be appreciated) simply using the onInitialize method in combination with the revertSettings attribute (jsfiddle):

$('select').selectize({
    onInitialize: function () {
        var s = this;
        this.revertSettings.$children.each(function () {
            $.extend(s.options[this.value], $(this).data());
        });
    }
});

The possibilities are infinite with this feature, like a FULL HTML SELECT.

@indrimuska You are a hero sir. That works like charm!

@JamesWilsonVSolvit :smile: thank you man!

works like charm, but not for option groups as their are undefined :(. any idea how to get to next level.. ( get each from option group and keep custom-data ? )

Hi @kimek, as you can see, revertSettings has a $children attribute that contains all the previous children of the original select you define.
If your select has got many <optgroup>s, the $children attribute contains these jquery elements, not the <option>s you want. That's why you get undefined as value of those datas.

schermata 2015-04-20 alle 15 28 10

The simplest way to overcome this problem is to look for the <option>s inside the <optgroup>s as you normally do in jQuery (.find()).
Here it is an example.

Thanks for fast replay and for help
The magic for me is how You looping children more than 'real optgroup' children.
children = this.revertSettings.$children; // its loop only for option group in my ex. is 6 optgroups

if (children.first().is('optgroup')) { // why this is not a loop ?
children = children.find('option');
}

Maybe this will help how i'm thinking, probably it's bad way..
var s = this;
x = s.options; // all items
$.each(x, function(i, val) {
$.extend(s.options[i.value], //here go data by jQ);
})
I really don't get it how you guys changing all '' here.
Thanks in advance

Hi @kimek.
In the fiddle I posted, the variable children initially assumes the value of the $children attribute offered by the plugin:

var s = this, children = this.revertSettings.$children;

Now, I don't know if children contains a collection of <option>s or a collection of <optgroup>s, so I have to catch the second situation in that way:

// if the first element of the collection is an `<optgroup>`
// I have to look through this list looking for the the `<options>`s.
if (children.first().is('optgroup')) {
    children = children.find('option');
}
// Now `children` is definitely a collection of `<option>`s.

In your case, you can remove the if-statement and use the corresponding block directly:

var s = this, children = this.revertSettings.$children.find('option');

@indrimuska your example is awesome I was looking for creating something like this and boom I found the perfect 1 to 1 example :) https://jsfiddle.net/8y9xkb0o/ I wanted to ask you if you know a way around the delay of the images loading? Any way to load them before opening the select? I'm trying to see the images instantly. Thanks a lot.

Hi @voidale, your problem is about to preload the image before the select has been opened. If you google it you can find many way to preload an image by using javascript or css. I think that the better solution for you is to parse the data-attributes as jquery element looking for src-attributes of the images, then to preload them like this:

var image =  new Image();
image.src = $(this).attr('src');

Here it is an example.

EDIT:
I just notice that the images are loaded every time the $(data.html) is called, so you don't even have to load the image manually. I tested this fiddle on Chrome and Firefox, I'm not sure about the behavior on the other browsers.

@indrimuska Hey, That's awesome I did google it and founds some solutions but didn't really like them all. This seems much more light weight. I wasn't aware of the Image api. It's really awesome thanks a lot for the information I also noticed that Image instance has onload function that can be really useful. Thanks again now this seems so easy I thought it will be really hard to fix :)

I think this feature would be delightful.

+1

+1

+1

+1

Please take note that '+1' comments have no effect on issue priority but to summon my attention away from the other things that need to be done. If you want to add priority to this issue, add a +1 emoji on the original post, these are taken into account.

Sorry @joallard, that was not my intent. Really grateful for Selectize and all of the work that goes into it.

No worries. It's a big repo with lots of requests and I get kinda cranky. Meanwhile the only viable solution is to work towards a pull request for this as there's no-one working full time on fixing issues for free.

👍

Coming back to this, 2.5 years have passed, but reading this, it's not clear where OP is asking the data attributes should remain. On the dropdown items? On the input items? On the original select children?

Would someone describe to me what a vanilla use case of needing that feature would look like? That'd help.

Hi,

I believe custom attributes should be transferred to both the Selectize dropdown and its input items.

In our case, we wanted multiple attributes like data-category, data-subcategory, data-article-type etc. Right now, only the original children's value are transferred as data-value, so we had to come up with a workaround where we placed multiple attributes inside each value like value="foo|bar|baz".

Hope that helps!

OP

The comments and workarounds in this thread so far are great, but what still isn't happening is the <option> element is not having the data attributes applied to it. The full HTML example above works well for displaying content from attributes, but the original option loses them.

In my use case, I'm using the data to populate subsequent things, and losing the attributes means this doesn't work.

Something like $("#my_select_box").find(':selected').data("color") no longer works because the <option> is stripped of the attributes.

My use case was absolutely the same. When you already have existing select on the page and it has some JS logic on it, this logic stops work when you "selectize" this select. If the attributes were not cut, then selectizing operation would be completely transparent to underlying JS code, which works with vanilla select element.

Why I want my JS code to work with vanilla select instead of produced selectized component? Because it is convinient. I can unselectize my select element any moment later and nothing stops to work. Also it cound be backward compatability: in legacy project I don't want to change any JS code just for selectizing my select elements.

@joallard OP has an example at http://jsfiddle.net/k44p2by6/. I'm thinking the same as OP here. Have data-attributes in the select option elements copied over to the Selectize items.

This raises a few questions regarding for example entering input values from JavaScript instead of HTML. And also how Selectize store this data internally. Now it has to store attributes in addition to key/value. And should it be possible to define data-attributes using JS or just limit it to HTML input creation?

I successfully managed to modify the code locally to work when you load in
the options via AJAX, however it doesn't translate when the options are
loaded from HTML.

I gotta work on it some more but hopefully will have some idea of changes
that could be included in a PR soon.

On Tue, Jul 26, 2016 at 11:00 AM, Espen Antonsen [email protected]
wrote:

@joallard https://github.com/joallard OP has an example at
http://jsfiddle.net/k44p2by6/. I'm thinking the same as OP here. Have
data-attributes in the select option elements copied over to the Selectize
items.

This results in some questions regarding for example entering input values
from JavaScript instead of HTML. And also how Selectize store this data
internally. Now it has to store attributes in addition to key/value. And
should it be possible to define data-attributes using JS or just limit it
to HTML input creation?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/selectize/selectize.js/issues/239#issuecomment-235295552,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAuFpiaYOLXMI_1DBFJp4kDun_nQc18Xks5qZiETgaJpZM4BXMdG
.

+1

Here's my use case.

I would like to be able to pass data attributes from the original options, onto the selectize options, so that I can later check them in a change event.

For example, my selectize list might be a list of countries, some of which required a postcode if selected. Each option has data-postcode=true or data-postcode=false. The event handler would be able to see the data-postcode value for the selected option and then show or hide the postcode field.

+1

For me, the solution provided by @indrimuska preserve the data-attributes on select, but not for options.

This is how I added a data-type="list" to my select options. The answer is based on stackoverflow post at: https://stackoverflow.com/questions/36512536/add-data-attribute-to-selectize-js-options

Markup:
<option data-data='{"type": "list"}' value="lorem">Lorem</option>

JavaScript:

$(#mySelect).selectize({
    render: {
        option: function (data, escape) {
            return '<div data-type="' + data.type + '">' + data.text + '</div>';
        }
    }
})

$(#mySelect).on('change', function(event) {
    var selectedValue = $(this).val();
    var $selectedOption = $(this)[0].selectize.getOption(selectedValue);
    if ($selectedOption.data('type') === 'list') {
        // do something
    }
});

The solution presented by @smohadjer works for me:

<select class='form-control' id="productSelection">
    <option disabled="disabled" value="" selected>Please select a Product.</option>
    <option value="1234" data-data='{"name":"Product 1234"}'>Product 1234</option>
    ....
</select>
$("#productSelection").selectize({
    render: {
        option: function (data, escape) {
            return '<div data-name="' + data.name + '">' + data.name + '</div>';
        }
    }
});

// To retrieve value
var selectedValue = $("#productSelection").val();
var name = $("#productSelection")[0].selectize.getOption(selectedValue).data('name');

But I'm not using markup, but loading in options from JS.

@WadeTheFade In the case of data from JS this issue does not apply.

You can use the render function to add data attributes to the returned options and then query them when selected. This issue exists only if going from markup to selectize and wishing to retain data- attributes which existed on the original

I still can't get it to work. I've tried everything said here but my option field never receives any data values.

@KazutoDE Here is a working example using solution I suggested earlier. Note that the data attribute (in this case data-continent) would be gone from original option element after selectize is initialized, but it will be preserved on markup generated by selectize, so you can still access it.

http://sandbox.saeidmohadjer.com/selectize/

1058 by @dakuzen highlights an important issue when using the $.extend workaround by @indrimuska.

@KazutoDE @WadeTheFade

Sample code which worked for me.

HTML markup

<select>
<option data="{value:1, name: 'data 1'}" value="3"> First option</option>
<option data="{value:2, name: 'data 2'}" value="3"> Second option</option>
</select>

Init the selectize:

    $("select").selectize({dataAttr: 'data'})

Then you can fetch the data attributes using:

$("select").data().selectize.options['1'].name  => data 1
$("select").data().selectize.options['2'].name  => data 2

No need to overrider the selectize's renderer or anything.

Hi @naveed-ahmad !
I tried your code, but it does not work at all for me...

When I write
$("select").data().selectize.options['1'].name
The result is "undefined"

To hope to have an exit, I have to write
$("select").data().selectize.options["3"]
and the result is
{text: "First", value: "3", $order: 1}

I have only this option in my options array...
I tested many things but nothing that works to recover the data...

Thanks for your help !

@Younnah please see data attribute in my html, data="{value:1, name: 'data 1'}" i've name and value keys.

In your case keys are text, value, $order
so $("select").data().selectize.options['1'].name SHOULD be undefined.

Try $("select").data().selectize.options['1'].text and value should be First

Yes, I see, but I can not access the attribute "name" in the "data" ...

The way that worked for me

My only goal was to get the "selected" data-attr from the select

Get all data-attr
thanks to @indrimuska

$('.js-select').selectize({
        onInitialize: function () {
            var s = this;
            s.revertSettings.$children.each(function () {
                $.extend(s.options[this.value], $(this).data());
            });
        }
    });

then inside the eventListener:
```
$('.js-select').change((e) => {
const value = $(e.currentTarget).val();
const options = $(e.currentTarget).data().selectize.options;
// There you have it
return options[value];
})

```

closing stale issues older than one year.
If this issue was closed in error please message the maintainers.
All issues must include a proper title, description, and examples.

@risadams I would have liked to see this shortcoming of Selectize to be fixed properly.

It's a fair request. We're currently focused on getting the project actively maintained with security patches, dependency updates, processing the 120 opened PRs, etc.

This is a very valid enhancement and PRs are welcomed.

If anyone has bandwidth to work on this, open up a new PR against this issue and we can re-open it.

Looks like maybe #1194 addresses this too. We need to process all the PRs including their functionality, test coverage and all the usual suspects including performance. If you want to pull that PR down and check it too, the more the merrier!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vilimco picture vilimco  ·  5Comments

fadhilanugrah picture fadhilanugrah  ·  4Comments

jaideepYes picture jaideepYes  ·  5Comments

adrianmihalko picture adrianmihalko  ·  4Comments

AndrejVM picture AndrejVM  ·  3Comments