Angular JS for Mutually Exclusive Selections - angularjs

I have two selection tag, each with the same options. The behavior that I am aiming for is to have whatever the selected option of one not be selectable on the options of the other one. Given that I am using an array of objects for the source of the options: [{name:'one'}, {name:'two'}, {name:'three'}]
1. Default.
selection 1
- one
- two
- three
selection 2
- one
- two
- three
2. Selection 1 gets selected.
selection 1
- one
- two
-(three)
selection 2
- one
- two
3. Selection 2 gets selected.
selection 1
- two
-(three)
selection 2
-(one)
- two

FIDDLE
You can do this by using a custom filter function to filter out already selected options.
<select ng-model="picks.select1">
<option ng-repeat="option in options | filter:optionFilter(picks.select1)" ng-value="option.name">
This function takes the model of the select as the parameter to be able to show it as still selectable.
$scope.optionFilter = function(selectedOptionModel){
return function(option){
//actual filtering function starts here, angular passes all items in the array
// to this function and filters out the ones you returned false
if(option.name === selectedOptionModel) return true; // if it's already the selected option it should still be an option in the dropdown
else{
for(var key in $scope.picks){
//otherwise we check to see if they are picked in
//another select dropdown and immediately return false because
// that option is elected should be filtered out.
if(option.name===$scope.picks[key]) return false;
}
//if we successfully got out of the loop it means it's not selected so return true
return true;
}
}
}

Related

Angular select multiple not setting selected items

Scenario is quite simple. I have edit view which comprises of select element with multiple selection. Select element looks as follows
<select class="selectpicker" multiple
ng-model="UserBeingEdited.UberTypes"
ng-options="uberType.Id as uberType.Name for uberType in UberTypes"></select>
</div>
If I press edit for specific user then showEditModal function is called and edit pop up shows up. User has his own UberTypes objects selected so I pick theirs Ids and assign to UserBeingEdited.UberTypes.
$scope.UserBeingEdited = { UberTypes: []};
$scope.showEditModal = function (user) {
for (var i = 0; i < user.UberTypes.length; i++) {
$scope.UserBeingEdited.UberTypes.push(user.UberTypes[i].Id);
}
$("#editUserModal").modal("show");
};
Unfortunately they are not selected, no matter what. Suprisingly, if I set values to property UserBeingEdited by the time of declaring then it works, items are selected.
$scope.UserBeingEdited = { UberTypes: [1,2]}; //this works
It seems like angular does not refresh selected items within UI.
EDIT:
I have two items: Uber1 and Uber2. Both items are selected but view does not reflect it. If I open drop down menu and select Uber2 it shows Uber1 selected, apparently Uber2 was selected and another click was treated as unselection. The same happens when I click Uber1 first, Uber2 shows as selected.
As above picture depicts, Uber2 is highlighted since I have just clicked it but it shows Uber1 as selected. Both were selected in User's UberTypes but view just simply does not mark them as selected.
http://jsfiddle.net/upusq8ah/7/
I use bootstrap-select.js for select element and presumably this library causes such an error since without including it, it works fine.
Solution
After a while of struggle, I accidentally ran into below workaround. You need to call refresh on selectPicker and this has to be delayed otherwise it will bring no effect.
setTimeout(function () {
$('.selectpicker').selectpicker('refresh');
}, 100);
$("#editUserModal").modal("show");

Last selected value in extjs multiselect combobox

How do we get only the last selected value in multiselect combobox and not all the selected values? For example if we select three values 1, 3 and 2, then I want to retrieve 2 as it was selected at last.
When you get the value of combo by using combo.value you will see an array that is in order how you selected the combo data from combo Box. This leads you get the last index of combo.value will be your required result.
In below code I taken a combo values and displaying the last result.
var combo = this.up().down('combo');
var CoboVal = combo.value;
var CoboValLength = CoboVal.length;
if(CoboValLength !== 0){
var CoboValData = CoboVal[CoboValLength-1];
alert(CoboValData);
}
I created a fiddle for you please check.

How to filter the JSON data using AngularJS?

I have three dropdown boxes. I need to filter the data and need to be displayed in the table based on my checkbox selection(either with single checkbox or two checkboxes or three checkboxes).
I have done the following, but if we observe it clearly, I am not able to filter the data properly using AngularJS.
Like:
a. It should work for individual checkbox selection: means if I select any single checkbox either from Name or Description or Field4, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)
b. It should work for multiple(two) checkbox selection: means if I select any multiple checkboxes like either one from Name and one from Description or one from Description and one from Field4 or one from Field4 and one from Name, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)
c. It should work for multiple(three) checkbox selection: means if I select the three checkboxes like one from Name and one from Description and one from Field4, then respective matched filtered data should be displayed in the table, otherwise it shouldn't be displayed any data(i.e if it doesn't match our checkbox selection means it won't display any data)
It is working fine for the first time checkbox selection only, means: after loading the above code/app, if we check either any one of the above selections(like whether single checkbox selection or two checkbox selection or three checkbox selection) then it's working fine, later it is not working(means if we uncheck the above any criteria and then if we select any checkbox again then it's not working, for that again we need to refresh the app/code then only it's working).
Example: if I select one from Name, then respective matched data will be displayed. Then again if I uncheck the same and check the some other checkbox like from Description then it's not working. Similarly for all the above criteria. You can observe it clearly.
Please let me know that what I have done wrong here and let me know how to filter it properly. Created Fiddle. Thanks in advance !
The problem is the convoluted filtering logic. Anytime you find yourself nesting lots of if statements, think about reorganizing the branching logic. By breaking it into smaller components, you can make it easier to manage, and if you can avoid using if altogether, then you only have to test one path, instead of several.
Every time a user checks a box, we need to make sure that we only display items that match however many boxes are checked. So we need to know 1) how many boxes are checked, n, and 2) how many items can be found with n matching fields.
We can take advantage of the fact that Boolean variables can be cast to integers (0 = false, true = 1) and use that to count the number of checked boxes, as well as the number of matches found.
We can also put the field names into an array, so that we don't have a lot of repetition in our functions.
Fiddle example here.
var fields = ["name", "description", "field4"];
//for each field, count how many fields the item matches
function getMatches(item, matchesNeeded) {
var foundMatches = 0;
fields.forEach(field => {
foundMatches += item[field] === $scope.pagedItems[field]
});
//make sure found at least one match and found desired minimum
return foundMatches && foundMatches >= matchesNeeded;
}
//count how many boxes are checked
//this will tell us how many different fields we are matching on
function numChecked() {
var count = 0;
fields.forEach(field => {
//this will auto convert falsy to 0.
//truthy values will be 1
count += Boolean($scope.pagedItems[field]);
});
return count;
}
$scope.filterItems = function(item) {
return getMatches(item, numChecked());
};
As #Larry pointed it was more based on logic. I have modified Apress book 'Pro AngularJS' Source Code from GIT for this.
Basic logic will in filter function as below -
$scope.categoryFilterFn = function (product) {
var canHave = false;//dont load by default
var atLeastOneTrue = false;//Check if previously checked any condition
angular.forEach(filterValues, function(selectedValue, key) {
var selectVals = Object.values(selectedValue);
if(selectVals.indexOf(product[key]) !== -1) {//if values exits in product.
canHave = !atLeastOneTrue ? true : canHave;
}else{
canHave = false;
}
atLeastOneTrue = true;
});
return canHave;
}
For working Fiddle.

Populate dropdown based on another, second one still remembers old selection

I have an unwanted behavior: The second dropdown remembers the old item? Why?
http://jsfiddle.net/Xku9z/ (fiddle borrowed from another thread)
Scenario:
Step 1. Select an item in the first dropdown
Step 2. Select an item in the second dropdown
Step 3. Select an item in the first dropdown (without selecting anything in the second one)
Step 4. Select the same item in the first dropdown as you did in step 1.
I have no clue how to resolve this, I've been using $scope.$watch on the ng-model="option2" just to get a grip on the problem without success.
Also, by setting option2 = null in the data-ng-change="getOptions2()" wont help:
$scope.getOptions2 = function(){
$scope.option2 = null;
};
Any ideas? Thanks
The behaviour you're experiencing is easier to understand if you watch the $scope.option2 value.
When you change the first dropdown you actually don't modify the $scope.option2 value. It stays the same: it's remembered. To make it work like you want just add one line
$scope.option2 = null;
at end of getOptions2 function. That's it. If you want more explanation of the current behaviour, read on.
Why does the second select go blank when I change the first one if the value is remembered?
<select> elements will show a selected value if and only if the value of ng-model can be found in the array bound to this element with ng-options.
Select first items from both dropdowns. Now:
$scope.option2 = "option2 - 1-1";
$scope.options2 = ["option2 - 1-1","option2 - 1-2","option2 - 1-3"];
As you can see the first variable can be found in the array so the value is displayed as currently selected. Now change only the first dropdown to the second item:
$scope.option2 = "option2 - 1-1";
$scope.options2 = ["option2 - 2-1","option2 - 2-2","option2 - 2-3"];
As you can see, $scope.option2 is not changed, but it's no longer in the $scope.options2 array. Therefore its value is not displayer as currently selected.

ng-options creates an empty option at the end when listbox group heading is clicked

I am stuck on this particular issue with ng-options. I am creating a listbox with option grouping:
<select ng-model="selTemplates" size="3" style="width: 150px"
ng-options="template.Name group by template.Type for template in userTemplates">
</select>
When I click on a group heading (Type1 or Type2), Chrome creates an empty option at the end and marks it selected. I believe it has something to do with the selection because it may not find anything 'selected' when a header is clicked, but an empty value at the bottom is not desired.
Please see the fiddle here.How can i fix it?
(The code works fine in IE9, although not sure why the fiddle doesn't)
ng-options adds empty option if case if value currently bound by ng-model doesn't exist in list of options. This prevents from overwriting value due bounding to empty select (this is an often problem in for example knockoutjs).
Clicking option group clears selection and empty option added.
You can see it if add debug <div>{{selTemplates}}</div> below select list.
Also even static select with size or multiple attribute specified clears its selection on clicking option. If size is omitted (for regular dropdown) clicking optgroup doesn't clears selected value.
I'm not sure if this browser inconsistence or expected behavior (if you said it works in IE) but consider replacing select with custom HTML emulates list selection.
Looks like inconsistent browser implementation is the reason. On clicking option header, Chrome clears out the selection whereas IE doesn't, that's why Chrome inserts a new empty row at the bottom.
As a workaround, I am saving last selected value in a variable, and in case user clicks on header (which will make selection null), I am restoring the last selection. See fiddle. Not exactly pretty, but gets the work done.
$scope.checkSelection = function() {
if ($scope.selTemplates == null) {
$scope.selTemplates = last;
}
else {
last = $scope.selTemplates;
}
}
Add ng-init="selTemplates=userTemplates[0]" in your <select>
You can remove "$scope.selTemplates = ***" in your controller

Resources