Background: There's a table from which I can choose employees. I want to filter these employees by name.(I know name is not a good way to filter, this is just an example)
Basically I have a drop down from which I choose one of the filters.
My declaration: $scope.filters = null;.
I also have this deceleration to choose my filter $scope.chosenFilter= null;.
I use the following to retrieve the different filters I have $scope.filters = retrieveFilters(info.Names);
retrieveFilters looks like the following:
var retrieveFilters = function(rows) {
var filterWrapper = document.querySelector(".filterWrapper");
var datasetOptions = [];
$scope.predicate = 'Name';
if (rows) {
//Add Default option
datasetOptions.push({
name: $scope.data.Fnames.defaultFilterOptionLabel,
value: ''
});
$scope.chosenFilter = datasetOptions[0];
_.forEach(rows, function(ele) {
datasetOptions.push({
name: ele,
value: ele
});
});
} else {
filterWrapper.style.display = "none";
}
return datasetOptions;
};
I use the following to choose my filter:
$scope.$watch('chosenFilter', function() {
var filterSearchInput = document.querySelector(".filterWrapper input");
ng.element(filterSearchInput).triggerHandler('input');
});
Everything is fine and the display works on first load as I have set the default with
//Add Default option
datasetOptions.push({
name: $scope.data.Fnames.defaultFilterOptionLabel,
value: ''
});
From the default table whenever I click on an employees name hes details are displayed. However whenever I filter and click on the employees name, nothing is displayed. Whenever I click on a specific employees name at the default table and then filter in the same name the information also shows up, as I cache it each time.
I assume that you're displaying this data somewhere in your GUI using ng-repeat. Angular has a lot of great built-in features for this. Check out the answer here: AngularJS custom search data by writing custom filter for a way to approach this more from an Angular direction. You also might want to check out this question and answer: "Thinking in AngularJS" if I have a jQuery background?.
Related
I'm successfully using the Loqate Address Verfication control, and filter its address results down to a single country, chosen in a select control.
However, when the country code in the select is changed, I've not been able to change the country filter in the Loqate address service to use the updated value.
var addressControl;
var avOptions = { suppressAutocomplete: false, setCountryByIP: false };
$(function () {
addressControl = initialiseAddressValidation();
});
$("#CountryCode").change(function () {
if (addressControl) {
addressControl.destroy();
addressControl = null;
}
addressControl = initialiseAddressValidation();
});
function initialiseAddressValidation() {
avOptions.key = $("#avKey").val();
avOptions.countries = { codesList: $("#CountryCode").val() };
//other config truncated
}
Loqate's docs suggest that the .destroy() method I'm calling on change of the select should remove the control, and I tried setting it to null, before recreating it with the new country code value, but the address results it returns are still for the original country is was initialised with on load.
Does anyone know how to set a new country filter to the Loqate address verifier without completely reloading the page?
My working solution, based on #SlapdashFox 's invaluable assistance. Done this way to avoid having to completely re-create the control on every change of country
$("#CountryCode").change(function () {
if (addressControl) {
addressControl.options.search.countries = $("#CountryCode").val();
} else {
addressControl = initialiseAddressValidation();
}
});
Looks like you're changing the wrong value here, you want to be changing the search.countries attribute within your options object.
In your above example you could do this as follows:
function initialiseAddressValidation() {
avOptions.key = $("#avKey").val();
avOptions.search = { countries: $("#CountryCode").val() };
}
I'm writing a directive wrapper around a typeahead input. This directive listens for changes on a link and get's new data + options for the typeahead.
I can simply simulate this behaviour with a $timeout and demonstrated it in this plnkr.co.
JS
app.controller('sample', function($scope, $timeout) {
$scope.options = ['1800', '1900', '2100'];
// Simulate some latency
$timeout(function () {
$scope.options.push('1850');
}, 4000);
});
HTML
<div>
<input type="text" ng-model="optionValue" typeahead="opt for opt in options | filter:$viewValue">
</div>
If you start typing '18' in the input field it shows 1800 as expected. But when 1850 get's added after an amount of time, the selectable options from typeahead are not being updated.
-- FYI my real live directive looks like this --
$scope.$watch($interpolate(url), function (newUrl) {
$http.get(newUrl).then(function (response) {
$scope.options = response;
});
});
I tried to use typeahead="opt for opt in getData()" but this doesn't work because the interpolated value is not yet up to date. It's always one value behind.
Seems like an issue to post on AngularUI Bootstrap website. Matches are getting selected on every keystroke but they don't get updated if you change the underlying data between keystrokes. I don't see any work-around for this, except maybe triggering the appropriate key event handler on the input manually (when you change the collection).
If someone interested in the solution, here is how I solved it at the moment. I'm not happy with the end result, please provide me some feedback :-).
Plunkr
Check out updated-bootstrap.js, I had to add the following in order to make it work:
A custom attribute that'll be use for the $watchCollection
var customOptions = attrs.typeaheadCustomOptions || '';
In the function where it gets the matches I've added a watch if customOptions is provided:
if (customOptions) {
originalScope.$watchCollection(customOptions, function (matches) {
resetMatches();
updateMatches(matches);
});
}
And that was basically it :-), the updateMatches is just an abstraction of existing code. It's not being used by me and the manual update.
var updateMatches = function(matches) {
for (var i = 0; i < matches.length; i++) {
locals[parserResult.itemName] = matches[i];
scope.matches.push({
id: getMatchId(i),
label: parserResult.viewMapper(scope, locals),
model: matches[i]
});
}
scope.query = modelCtrl.$viewValue;
};
Opened issue on github
I'm currently facing a problem with the Kendo UI MultiSelect widget for selecting an option more than once. For example, in the image below I want to select Schindler's List again after selecting The Dark Knight, but unfortunately the MultiSelect widget behaves more like a set than an ordered list, i.e. repetitive selection is not allowed. Is there actually a proper way to achieve this? Any workarounds?
That's the intended behavior of the multi-select control and there is no simple way to make it do what you want using the available configuration options. Possible workarounds are ...
Creating a custom multi-select widget
Something like this should work (note that I haven't tested this much - it lets you add multiples and keeps the filter intact though):
(function ($) {
var ui = kendo.ui,
MultiSelect = ui.MultiSelect;
var originalRender = MultiSelect.fn._render;
var originalSelected = MultiSelect.fn._selected;
var CustomMultiSelect = MultiSelect.extend({
init: function (element, options) {
var that = this;
MultiSelect.fn.init.call(that, element, options);
},
options: {
name: 'CustomMultiSelect'
},
_select: function (li) {
var that = this,
values = that._values,
dataItem,
idx;
if (!that._allowSelection()) {
return;
}
if (!isNaN(li)) {
idx = li;
} else {
idx = li.data("idx");
}
that.element[0].children[idx].selected = true;
dataItem = that.dataSource.view()[idx];
that.tagList.append(that.tagTemplate(dataItem));
that._dataItems.push(dataItem);
values.push(that._dataValue(dataItem));
that.currentTag(null);
that._placeholder();
if (that._state === "filter") {
that._state = "accept";
}
console.log(this.dataSource.view());
},
_render: function (data) {
// swapping out this._selected keeps filtering functional
this._selected = dummy;
return originalRender.call(this, data);
this._selected = originalSelected;
}
});
function dummy() { return null; }
ui.plugin(CustomMultiSelect);
})(jQuery);
Demo here.
Using a dropdown list
Use a simple dropdown list (or ComboBox) and bind the select event to append to your list (which you have to create manually).
For example:
var mySelectedList = [];
$("#dropdownlist").kendoDropDownList({
select: function (e) {
var item = e.item;
var text = item.text();
// store your selected item in the list
mySelectedList.push({
text: text
});
// update the displayed list
$("#myOrderedList").append("<li>" + text + "</li>");
}
});
Then you could bind clicks on those list elements to remove elements from the list. The disadvantage of that is that it requires more work to make it look "pretty" (you have to create and combine your own HTML, css, images etc.).
I'm using the chosen plugin to build multiple select input fields. See an example here: http://harvesthq.github.io/chosen/#multiple-select
The default behavior disables an option if it has already been selected. In the example above, if you were to select "Afghanistan", it would be greyed out in the drop-down menu, thus disallowing you from selecting it a second time.
I need to be able to select the same option more than once. Is there any setting in the plugin or manual override I can add that will allow for this?
I created a version of chosen that allows you to select the same item multiple times, and even sends those multiple entries to the server as POST variables. Here's how you can do it (fairly easily, I think):
(Tip: Use a search function in chosen.jquery.js to find these lines)
Change:
this.is_multiple = this.form_field.multiple;
To:
this.is_multiple = this.form_field.multiple;
this.allows_duplicates = this.options.allow_duplicates;
Change:
classes.push("result-selected");
To:
if (this.allows_duplicates) {
classes.push("active-result");
} else {
classes.push("result-selected");
}
Change:
this.form_field.options[item.options_index].selected = true;
To:
if (this.allows_duplicates && this.form_field.options[item.options_index].selected == true) {
$('<input>').attr({type:'hidden',name:this.form_field.name,value:this.form_field.options[item.options_index].value}).appendTo($(this.form_field).parent());
} else {
this.form_field.options[item.options_index].selected = true;
}
Then, when calling chosen(), make sure to include the allows_duplicates option:
$("mySelect").chosen({allow_duplicates: true})
For a workaround, use the below code on each selection (in select event) or while popup opened:
$(".chosen-results .result-selected").addClass("active-result").removeClass("result-selected");
The above code removes the result-selected class and added the active-result class on the li items. So each selected item is considered as the active result, now you can select that item again.
#adam's Answer is working very well but doesn't cover the situation that someone wants to delete some options.
So to have this functionality, alongside with Adam's tweaks you need to add this code too at:
Chosen.prototype.result_deselect = function (pos) {
var result_data;
result_data = this.results_data[pos];
// If config duplicates is enabled
if (this.allows_duplicates) {
//find fields name
var $nameField = $(this.form_field).attr('name');
// search for hidden input with same name and value of the one we are trying to delete
var $duplicateVals = $('input[type="hidden"][name="' + $nameField + '"][value="' + this.form_field.options[result_data.options_index].value + '"]');
//if we find one. we delete it and stop the rest of the function
if ($duplicateVals.length > 0) {
$duplicateVals[0].remove();
return true;
}
}
....
I`m trying to add options to my select menu in my custom plugin. I want to get these options from array that I have and with forearch or for to create these options.How can I do that?
Could you show us your code that generates the select box? If I'm guessing right, you might be able to do something like
var things = [];
var your = ["Derpy","Fluttershy","Applejack"];
for(var i = 0; i < your.length; i++) {
// The two values used to separate actual and display values if needed
things[i] = [your[i],your[i]];
}
// snip snip
tab.add({
type: 'select',
label: 'myAwesomePonySelector',
id: 'myAwesomePonySelector',
items : things
// your other definitions, like onShow and commit
});
I hope this helps.