AngularJS filter already selected option from dynamic field - angularjs

I have a form where you can add x number of fields. Each field contains option select. I want to filter out the already chosen option when this option is already chosen in one or multiples field before. Each field has a remove button and the form has 1 add button.
How can I filter out the dynamic fields?
Any help,guidance is most welcome.Thanks in advance. :)
This is how my HTML looks like:
<div data-ng-repeat="choice in choices">
<select data-ng-model="choice.option"
data-ng-options="item as item.Value for item in options">
</select>
<button data-ng-click="removeChoice(choice)">Remove choice</button>
<div>
<button data-ng-show="choices.length <= 4" data-ng-click="addNewChoice()">Add Choice</button>
</div>
</div>
And my controller:
$scope.options = [
{
"Key": "0",
"Value": "Select an option"
},
{
"Key": "Option1",
"Value": "Option1"
},
{
"Key": "Option2",
"Value": "Option2"
},
{
"Key": "Option3",
"Value": "Option3"
},
{
"Key": "Option4",
"Value": "Option4"
},
{
"Key": "Option5",
"Value": "Option5"
}
];
$scope.choices = [{ id: '1' }];
$scope.addNewChoice = function () {
var newItemNo = $scope.choices.length + 1;
$scope.choices.push({ id: newItemNo, option: $scope.option, value: $scope.value });
};
$scope.removeChoice = function () {
var index = $scope.choices.indexOf(choice);
$scope.choices.splice(index, 1);
};

ok
i can give simple recommendation which will be this.
1: add variable $scope.selectedOptions = [];
this will contain list of already selected options from all select elements .
2: create function $scope.AddSelectedOption(item);
this will add the selected object when we change option from any select element because we are going to use for all selects ng-change= "AddSelectedOption(item);"
3: add checkIfSelected(item); this will check if given object value is already selected or not ..
will user in
hope you understand what it will do just check like this
$scope.checkIfSelected = function (item) {
$scope.selectedFound = $scope.selectedOptions.filter(function
(option) {
if(option.value == item.value)
{
return day;
}
});
if($scope.selectedFound.length == 0 ) { return false; } else {
return true; }
}
This will return true if give item found in the options.
if not out.. you can invite me to help again .

This is possible. I'm explaining a basic version of this requirement. See the working example here http://plnkr.co/edit/S9yZpjhY55lXsuifnUAc?p=preview
What wer are doing is maintaining another options which is the copy of the original options. Copying the options will make it to not reference existing options since objects are pass by reference in Javascript.
The main logic is in this function, which modify the options on selection:
$scope.optionSelected = function(choice) {
$scope.availableOptions = $scope.availableOptions || angular.copy($scope.options);
if (choice.option) {
var index = -1;
// See if available options has that key
angular.forEach($scope.availableOptions, function(item, i) {
if (item.Key === choice.option.Key) {
index = i;
}
});
if (index > -1) {
// And then remove it
$scope.availableOptions.splice(index, 1);
}
}
};

Related

Angular Materials md-select and trackBy allowing options to be selected

I'm trying to customise this Angular Material example code (https://material.angularjs.org/latest/api/directive/mdSelect) to my needs.
I have three groups of select options. If an option is selected in a group, it should unselect all options in other groups (but leave other options in own group as they are).
In my code I have managed to get the logic working right (as you will see from the console.log outputs at the bottom), but the actual select options do not interact with user input.
My JSFiddle: https://jsfiddle.net/e2LLLxnb/8/
My JS code:
var myModule = angular.module('BlankApp', ['ngMaterial']);
myModule.controller("FilterCtrl", function($scope, $element) {
$scope.categories = ["Any", "Target Category", "Option 1", "Option 2", "Option 3", "Option 4"];
$scope.mustCatSelected;
$scope.categoryObj = {};
// build the list of options with values and groups - create equivalent of $scope.data for <md-option ng-repeat="item in categoryObj.data.items">
var finGroup = [];
$scope.categories.forEach(function(value,key){
if(key>1){
finGroup.push(key);
};
});
$scope.categoryObj.data = {items: [], groups: [{
group: [0]
}, {
group: [1]
}, {
group: finGroup
}]};
$scope.categories.forEach(function(value,key){
$scope.categoryObj.data.items.push({name: value,
value: false,
id: (key + 1)});
});
$scope.clickOn = function(item, index) {
if(item.value == false){item.value = item.name;}
else {item.value = false;}
if (item.value === false) {
} else {
var thisGroup = [];
angular.forEach($scope.categoryObj.data.groups, function(value, key) {
if (value.group.indexOf(index) !== -1) {
thisGroup = value.group;
}
});
angular.forEach($scope.categoryObj.data.items, function(value, key) {
if (thisGroup.indexOf(key) !== -1) {
return;
} else {
value.value = false;
}
});
$scope.mustCatSelected = $scope.categoryObj.data.items.filter(function(e){
return e.value != false;
});
console.log($scope.mustCatSelected);
console.log($scope.categoryObj.data.items);
}
}
//search-term header
$scope.searchTerm;
$scope.clearSearchTerm = function() {
$scope.searchTerm = '';
};
// The md-select directive eats keydown events for some quick select
// logic. Since we have a search input here, we don't need that logic.
$element.find('input').on('keydown', function(ev) {
ev.stopPropagation();
});
});
Solved (finally!): https://jsfiddle.net/hqck87t1/4/
var myModule = angular.module('BlankApp', ['ngMaterial']);
myModule.controller("FilterCtrl", function($scope, $element) {
$scope.categories = ["Any", "None", "Option 1", "Option 2", "Option 3", "Option 4"];
$scope.mustCatSelected = [];
$scope.categoryObj = {};
$scope.categoryObj.items = [];
$scope.categories.forEach(function(value,key){
var grp;
if (key < 2){grp = key;}
if (key >= 2){grp = 2;}
$scope.categoryObj.items.push({
name: value,
id: (key + 1),
group: grp});
});
//set default
$scope.mustCatSelected.push($scope.categoryObj.items[0]);
$scope.clickOn = clickOn;
function clickOn(newValue, oldValue, type) {
//console.log($scope.categoryObj.items);
//console.log(oldValue);
if(oldValue.length == 0) {
return false;
}
//create arrays of new and old option ids
oldValue = JSON.parse(oldValue);
var newIds = [];
var oldIds = [];
newValue.forEach(function(value,key){
newIds.push(value.id);
});
oldValue.forEach(function(value,key){
oldIds.push(value.id);
});
//define and set the clicked value
var clickedValue;
newIds.forEach(function(value, key){
if(oldIds.indexOf(value) == -1) {
clickedValue = value;
}
});
var clickedGroup;
newValue.forEach(function(value,key){
if(value.id == clickedValue){
clickedGroup = value.group;
}
});
//console.log([clickedValue, clickedGroup]);
//console.log([newIds, oldIds, clickedValue]);
if(type == 'mustCat'){
$scope.mustCatSelected = $scope.mustCatSelected.filter(function(e){
return e.group == clickedGroup;
});
}
}
//search term above select
$scope.searchTerm;
$scope.clearSearchTerm = function() {
$scope.searchTerm = '';
};
// The md-select directive eats keydown events for some quick select
// logic. Since we have a search input here, we don't need that logic.
$element.find('input').on('keydown', function(ev) {
ev.stopPropagation();
});
});
There key to the solution lies in two things:
Using ng-change instead of ng-click. The former is used to distinguish the state of ng-model inline vs the specified state of ng-model after the change event. Whereas ng-click is not reliable for this.
Write the ng-change function in the html like this:
ng-change="clickOn(mustCatSelected, '{{mustCatSelected}}')"
where mustCatSelected is the ng-model and '{{mustCatSelected}}' the inline state of ng-model before the change event.
Now we have an multiple md-select with logic handling the selection of options / groups of options.

Comparing objects from two scopes to provide a value

I'll try to simplify the problem as much as I can.
Let's say I have 2 scopes
$scope.section1 = [
{label: 'label1'},
{label: 'label2'}
];
$scope.section2 = [
{value: 'one'},
{value: 'two}
];
Those scopes are used to generate buttons with ng-repeat
<button ng-repeat="item in section1 type="button">{{item.label}}</button>
and
<button ng-repeat="item in section2 type="button">{{item.value}}</button>
Now what I would like to do it to create a third scope that would attach values to the combinations of objects from the two previous ones, say:
$scope.combo = [
{ section1.label:label1 + section2.value: one = 'result1' },
{ section1.label:label2 + section2.value: one = 'result2' },
{ section1.label:label1 + section2.value: two = 'result3' },
{ section1.label:label2 + section2.value: two = 'result4' }
];
Now here comes the tricky part. What I would need to do, is to add a function that would take the values of clicked ng-repeat buttons from each section and then display the results based on the third scope in an input field or something.
So, if you click the button with label:label1 and the one with value:two the input field would show result3.
I'm very green when it comes to Angular and I have no idea how to approach it, especially that all values are strings.
If I understand correctly you could setup your combo something like ...
$scope.combo = {
"label1": {
"one": "result1",
"two": "result2"
},
"label2": {
"one": "result3",
"two": "result4"
}
}
You can then reference the correct value as combo[valueFromButton1][valueFromButton2] where valueFromButton1 and valueFromButton2 point at a model that contains the result of the clicked buttons. Your controller function then just needs to tie everything together by updating the model when the buttons are clicked.
See this plunkr ... https://embed.plnkr.co/GgorcM/
Without changing much you can also try like below provided code snippet.Run it to check the demo.
var app = angular.module('app', []);
app.controller('Ctrl',['$scope' ,function($scope) {
var key1, key2;
$scope.click = function(type, item) {
if (type == 'label') {
key1 = item;
} else if (type == 'val') {
key2 = item;
}
$scope.key = key1 + '+' + key2;
angular.forEach($scope.combo, function(val, key) {
if(val[$scope.key]){
$scope.finalVal = val[$scope.key];
}
});
};
$scope.section1 = [{
label: 'label1'
}, {
label: 'label2'
}];
$scope.section2 = [{
value: 'one'
}, {
value: 'two'
}];
$scope.combo = [{
'label1+one': 'result1'
}, {
'label2+one': 'result2'
}, {
'label1+two': 'result3'
}, {
'label2+two': 'result4'
}];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='Ctrl'>
<button ng-repeat="item in section1" ng-click="click('label',item.label)" type="button">{{item.label}}</button>
<button ng-repeat="item in section2" ng-click="click('val',item.value)"type="button">{{item.value}}</button>
<input type="text" ng-model="finalVal"/>{{key}} {{finalVal}}
</div>

Filtering out objects with certain property value in an array (Angular)

Trying to filter through an array in Angular, and filter out all objects of a certain property
I have an array like this:
[
{
"group":"Group A",
},
{
"group":"Group A",
},
{
"group":"Group B",
},
{
"group":"Group B",
}
{
"group":"Group C",
},
{
"group":"Group C",
}
]
...and I want to write a function to return an array with only Group A and B (not Group C).
So far this is what I have:
function filterStandings() {
for (var i = 0, len = $scope.originalArray.length; i < len; i++) {
$scope.filteredArr = [];
if (originalArray[i].group !== "Group C") {
$scope.filteredStandingsArr.push($scope.originalArray[i]);
}
}
return $scope.filteredArr;
};
Then I when I try to display this array in my view by calling the filterStandings() function, nothing shows up.
Can anyone help?
Array.prototype.filter()
For your use case:
$scope.filteredArr = $scope.originalArray.filter(function(item){
return item.group !== 'Group C'
});
Try this :
$scope.test = function () {
$scope.filteredArr = [];
for (var i = 0; i < $scope.items.length; i++) {
if ($scope.items[i].group != "Group C") {
$scope.filteredArr.push($scope.items[i]);
}
}
return $scope.filteredArr;
};
You have just miss to use the $scope services and initialize your new array (filteredArr) in the for-loop.
You can also use the filter keyword :
JS
$scope.filteredArr = function (item) {
return item.group != "Group C";
};
HTML
<div ng:repeat="item in originalArray| filter: filteredArr ">
{{item}}
</div>

React Js select list to have own value

I have rows of selects lists, when I change a list on one row, the lists for the whole table column change, is there a way each select list can have its own selected option?
I an rendering each row component use the following schema:
tableRowScheme: [
{"column":"levelId",
"title":"Level",
"type": "select",
"optionData": this.state.gradeOptions,
"afterChange": this.onLevelSelect,
"className": "col-md-1"},
{"column":"subjectId",
"title":"Subject",
"type": "select",
"optionData": this.state.subjects,
"afterChange": this.onSubjectSelect,
"className": "col-md-1"},
Then Im rendering each select list
case 'select': {
var optionsData = cellData.optionData ? cellData.optionData : [];
if(cellData.isRowInEditMode && !cellData.isNonEditable) {
return (
<div>
<TableDropdown columnName={cellData.column}
staticElements={this.props.staticElements}
optionsData={optionsData}
staticElementId={cellData.selectTypeId}
defaultValue={parseInt(this.state.rowDataStack[cellData.column])}
className="input-sm"
handleSelect={this.onDropdownChange}/>
<Input type="hidden" ref={cellData.column} standalone={true}
defaultValue={parseInt(this.state.rowDataStack[cellData.column])} />
</div>
);
Then each dropdown has this.onDropdownChange :
onDropdownChange: function(data){
var localRowDataStack = _.cloneDeep(this.state.rowDataStack);
localRowDataStack[data.filterName] = data.filterVal;
this.setState({
rowDataStack: localRowDataStack,
isOmitReRender: false
});
for (var i=0; i<this.props.rowScheme.length;i++) {
if(this.props.rowScheme[i].afterChange != undefined && this.props.rowScheme[i].column == data.filterName) {
this.props.rowScheme[i].afterChange(data.filterVal);
break;
}
}
},

Angular.js count item iterations when filtering objects with ng-options

working on a list filtering with Angular, where listing the items based on region and creating an option select to list these regionsm where I have to remove duplications, and will need a count number next to the region name, which represents how many items from the same region.
I found this thread : How to count unique results based on a particular properties within ng-options but its not working when removing the duplications.
Heres is my select
<select ng-options="item.region as item.region for item in items | unique: 'region'" ng-model="catFilter">
Here is my app.js
var regionSort = angular.module('regionSort', [
'regionSort.controllers'
]);
regionSort.filter('unique', function() {
return function(items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {},
newItems = [];
var extractValueToCompare = function(item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function(item) {
var valueToCheck, isDuplicate = false;
var count = 0;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
Does anybody have any idea how should I solve this? Thanks in advance!!
Item structure is pretty simple like :
[
{
"name": "Name",
"desc": "Description",
"price": 700,
"priceold": 1080,
"persons": 10,
"discount": 35,
"vote": "9,3",
"image": "https://someige.jpg",
"url": "http://someurl.com",
"region": "XXX"
}, ...
]

Resources