Getting dynamically rendered Vue.js dropdown to work with Select2 library - javascript

I am new to Vue so pardon me if this is an easy question. I have a page where I dynamically render a select dropdown and dynamically populate its options based on a computed property called filteredWidgets that depends on selections the user made in other dropdowns. The markup is as follows:
<div v-if="filteredWidgets.length > 0">
<select id="widgetSelect" name="widgets">
<option value="">Select up to two Widgets</option>
<option v-for="widget in filteredWidgets" v-bind:value='widget.id'>
#{{widget.name}}
</option>
</select>
</div>
From the Select2 documentation, it states that this is how you convert the select/option elements to become Select2 multiselect elements:
$(document).ready(function() {
$('#widgetSelect').select2();
});
I can get this to work for a page with a non-dynamically rendered select dropdown. Obviously this doesn't work with Vue because the dropdown is rendered dynamically, and it is based on the computed property selectedWidgets. I need to find a way to get select2 to work at the time this dropdown appears/changes. Here is the computed property method filteredWidgets():
filteredWidgets() {
var filteredWidgets = this.availableWidgets.filter(widget => {
return widget.color == selectedColor && widget.size == selectedSize;
});
return filteredWidgets;
}
While the default select dropdown renders as I want it to and contains the filtered widgets I want, I need to figure out how to apply select2() to the widgetSelect dropdown immediately after it is rendered by Vue. What is the correct way to do this?

watch for changes to filteredWidgets, and call .select2().
watch: {
async filteredWidgets() {
await this.$nextTick() // wait for DOM to update
$(this.$refs.widgetSelect).select2()
}
}
You'll need to add a ref to the <select> so you can access the element directly with this.$refs.widgetSelect, instead of doing something like this.$el.querySelector('#widgetSelect'). The id attr is no longer needed, unless you're using it for something else.
<select ref="widgetSelect" name="widgets">

Related

select2: is there a way to propagate a class from an option to the item presented in the list?

In my scenario, I'm preloading a select with several options and I was wondering if there's any way to add a class to the li that get generated by the control so that I can change its styles. Here's the code I'm using on the server side to generate the select (ASP.NET MVC):
<select id="areas" name="areas" class="form-control" multiple="multiple">
#foreach (var area in Model.AreasAssociadas) {
<option value="#area.IdArea" selected="selected" #Html.Raw(area.Active ? "" : "class='disabled'")>#area.Nome</option>
}
</select>
Now, I'd like to change the default UI, but only for those items that are disabled (ie, for all the items where the Active property returns false). Btw, I want to add a style so that I can get something like this:
Can this be done?
Since it seems like there's not a property or event to handle this, I've ended up adding codes for changing the dom on the fly. not the best option, but gets the work done...

Angular Select NgOptions double selecting when directive compiles

I am working on a dynamic form that populates a dropdown conditionally based on another input. I have written a directive because the data that comes back will also carry validation rules that need to be applied. However when i apply the validation rules to the dropdown and recompile the select options are borked. The final HTML looks like this:
The questions on the form can depend on another to be answered in a very specific way before they appear. This dropdown for example depends on the country selected but can be required or optional depending on what country is selected. The data coming back from my server gives me a validation object that contains validation information for the input field such as:
var question = scope.question;
var input = element.find('select');
if (question.validation.required) {
if (!input.attr('required')) {
input.attr('required', question.validation.required);
}
}
$compile(input)(scope);
The standard <option value="?" selected="selected"></option> is put in but when the question the dropdown depends on triggers the watch and a request happens for the dropdown the server returns and the backing select values are changed but the HTML output results as seen above all the items that are set to selected are unselectable and the form validation fails.
function answerMatch(countryCode) {
sectionService.getDivisionsByCountryCode(countryCode).then(function (response) {
scope.question.selectValues = response.data;
element.show();
});
}
and an HTML snippet for good measure
<select id="question{{question.questionId}}" name="answer" ng-model="question.value" ng-options="value.text for value in question.selectValues" class="form-control">
</select>

Select2 with Backbone.Marionette: Pre-selected values not hidden

I am trying to integrate Select2 within a Marionette ItemView.
The problem: I want to initialize the Select2 with already-selected values, but the selected elements are still available in the dropdown. If I clear the box then manually reselect the items from the dropdown, the items are then properly removed from the dropdown.
Javascript:
View.Profile = Marionette.ItemView.extend({
template: profileTpl,
onShow: function(){
var $select = this.$("#categories"); // grabs the element for Select2
$select.select2(); // build the Select2 element
$select.select2("val", ["american", "french", "italian"]); // select values
}
HTML:
<select id="categories" data-placeholder="Add a category..." multiple class="form-control" tabindex="8">
<option></option>
<option value="american">American</option>
<option value="french">French</option>
<option value="italian">Italian</option>
<option value="indian">Indian</option>
</select>
I can do this on a single html example page with no trouble.
Using Marionette's onShow, the "tag" elements correctly displayed in the Select2 box, but when I click the box to select different options, all options are still available.
I suspect there is some event not properly attached to the Select2 element because of the way I'm attaching the Select2 element in the onShow event.
Here is working example of your issue.
Just one note related to your code. It's a good practice, when accessing an element of view, use this.$el.find('selector') reference instead of querying it via jquery $('selector').
You can do it even shorter like this.$('selector').

AngularStrap Select and ng-options don't work well using dynamic array

I'm using AngularJS with AngularStrap (directive Select, based on Bootstrap-Select made by Silvio Moreto). I have the next problem:
I have an array of car brands. Using ng-options, I put them like options in a select.
By other way, when I select an option (car brand), I get the different models of this car brand, and show them like options in another select.
The problem is when I'm using the AngularStrap directive select, it doesn't work well. The first time i select a car brand, it works fine, but the next selected option (car brand), it shows the models of the car brand selected and the first model of the previous car brand selected.
When I don't use AngularStrap select it works well, therefore i think the problem is in AngularStrap select.
Thanks for your help.
My code is the next:
HTML:
<select ng-model="selectBrand" ng-options="carBrand.id as boatBrand.name for boatBrand in boatBrands" bs-select >
<optionvalue="">CarBrand</option>
</select>
<select ng-model="selectModel" ng-options="carModel.id as carModel.name for boatModel in carModels" bs-select>
<option value="">CarModel</option>
</select>
Controller (JS):
$scope.carBrands = carBrand.query();
$scope.$watch('selectBrand', function() {
$scope.carModels = carModel.query({type_id: $scope.selectBrand});
};
I realize this is old, but I had a similar problem with the Chosen Select plugin and a dynamic list of ng-options. I finally resolved the problem by wrapping my options query inside of a $timeout.
$timeout(function () {
$scope.carModels = carModel.query({type_id: $scope.selectBrand});
});
The only way I was able to use the AngularStrap select support with a select element was to use ng-options and have no option elements as children of the <select>.

AngularJS selecting multiple options

So, What I'm trying to do is fairly simple with vanilla JS, but I'm using AngularJS and I would like to know how to do it the best way within the framework. I want to update the selected options in a multiple select box. I do not want to add or remove any of the options. Here is what my HTML looks like:
<select multiple>
<option value="1">Blue</option>
<option value="2">Green</option>
<option value="3">Yellow</option>
<option value="4">Red</option>
</select>
Using the following array, I'd like to programmatically select/deselect options from this list:
[{id:1, name:"Blue"},{id:4, name:"Red"}]
When I set this array in the scope, I want the select box to deselect anything that is not Blue or Red and select Blue and Red. The standard response that I've seen on the Google Groups is to use ng-repeat. However, I can't recreate the list every time because the list of selected values is incomplete. As far as I can tell, AngularJS has no mechanism for this, and I'm at a loss as to how I would do this without resorting to using jQuery.
ngModel is pretty awesome! If you specify the indexes as a model selectedValues
<select multiple ng-model="selectedValues">
built from your list (selected) in a $watch
$scope.$watch('selected', function(nowSelected){
// reset to nothing, could use `splice` to preserve non-angular references
$scope.selectedValues = [];
if( ! nowSelected ){
// sometimes selected is null or undefined
return;
}
// here's the magic
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString() );
});
});
ngModel will automatically select them for you.
Note that this data binding is one-way (selected to UI). If you're wanting to use the <select> UI to build your list, I'd suggest refactoring the data (or using another $watch but those can be expensive).
Yes, selectedValues needs to contain strings, not numbers. (At least it did for me :)
Full example at http://jsfiddle.net/JB3Un/

Categories

Resources