Reputation: 12320
I have a select that looks like this
<select
class="form-control"
ng-model="vm.transaction.location_from"
ng-options="l.name for l in vm.locations">
</select>
with vm.locations
sourcing from the following JSON:
[
{
"id": "c0d916d7-caea-42f9-a87f-a3a1f318f35e",
"name": "Location 1"
},
{
"id": "d8a299a3-7f4b-4d32-884f-efe25af3b4d2",
"name": "Location 2"
}
]
Further, I have another select that looks like:
<select
class="form-control"
ng-model="vm.transaction.item"
ng-options="i.name for i in vm.items">
</select>
with vm.items
sourcing from the following JSON:
[
{
"id": "9f582e58-45dd-4341-97a6-82fe637d769e",
"name": "20oz Soft Drink Cup",
"locations": [
{
"inventory_id": "9d5aa667-4a64-4317-a890-9b9291799b11",
"location_id": "c0d916d7-caea-42f9-a87f-a3a1f318f35e"
},
{
"inventory_id": "9d5aa667-4a64-4317-a890-9b9291799b11",
"location_id": "d8a299a3-7f4b-4d32-884f-efe25af3b4d2"
}
],
}
]
I want to, on change of the ng-mode="vm.transaction.item"
select, have the ng-model="vm.transaction.location_from"
be filtered to only show values that match from the locations
array. I know I can use a | filter: { }
, but I'm not sure what that filter should look like.
Upvotes: 1
Views: 271
Reputation: 11
i think filter:{ id : item.locations[0].location_id }
should do the trick.
here is the jsfiddle
how do you think?
Upvotes: 0
Reputation: 2706
you can do this:
<select
class="form-control"
ng-model="vm.transaction.item"
ng-change="itemCahngedFn()"
ng-options="i.name for i in vm.items">
</select>
var itemChangedFn = function(){
var filtredItems = [];
angular.forEach(vm.locations, function(item){
if(item.name == vm.transaction.item){
filtredItems .push(item.location);
}
});
vm.locations= filtredItems ;
}
Upvotes: 0
Reputation:
I would forego angular filters and use the getterSetter
option of ngModelOptions.
It could look something like this:
var selectedItem, selectedLocation;
var items = [];
var locations = [];
vm._items = items; // Static, always allow all items to be selected.
vm.locations = function () {
// Return differing results based on selectedItem.locations.
};
vm._transaction = {
location: function (v) {
/**
* If v is null, it is not present in the selectedItem.locations array.
* The extra check will ensure that we don't persist a filtered out location when
* selecting another item.
*/
return (v || v === null) ? (selectedLocation = v) : selectedLocation;
},
item: function (v) {
return v ? (selectedItem = v) : selectedItem;
}
};
Here's a plunker demonstrating the behaviour.
Not as simple/straight-forward as a filter, but I would bet (at least in the case of a piped filter) that you'd possibly see a slight performance gain going with this approach.
I do not have numbers to back up the above statement, and it usually boils down to the size of your dataset anyway. Grain of salt.
If you need it to function the other way around, you could write up a secondary filter like such:
function superFilter2 (arr) {
// If no location is selected, we can safely return the entire set.
if (!selectedLocation) {
return arr;
}
// Grab the current location ID.
var id = selectedLocation.id;
// Return the items that are present in the selected location.
return arr.filter(function (item) {
return item.locations.map(function (l) {
return l.location_id;
}).indexOf(id);
});
}
With that and the filter in the supplied plunker, there are some similarities that could be moved into higher order functions. Eventually with some functional sauce you could probably end up with a single god function that would work both ways.
Upvotes: 0
Reputation: 756
Hope this is your expected results. Below are two options I tried ... demo | http://embed.plnkr.co/689OQztgu8F800YjBB2L/
Ref : underscorejs | angular-filter | everything-about-custom-filters-in-angular-js
// 1. filter items collection by location
angular.module('demo').filter('withLocation', function () {
return function (items, selectedLocation) {
function isLocationInLocations (elem) { return selectedLocation && elem.location_id === selectedLocation.id; }
function itemHasLocation (elm){ return (elm.locations && elm.locations.filter(isLocationInLocations).length > 0); }
return items.filter(itemHasLocation);
}});
// 2. filter function to check if option can be rendered ....
vm._filters.selectableItems = function(selectedLocation) {
return function(item) {
var locationsHasLocation = function(elem) { return selectedLocation && elem.location_id === selectedLocation.id; }
return (item.locations && item.locations.filter(locationsHasLocation).length > 0);
}
}
Upvotes: 1
Reputation: 827
One way to do this is to supply a filter function to filter the locations. Something like:
vm.filterFun = function(selectedLocations) {
return function (location) {
var n;
if (!selectedLocations) {
return true;
}
for(n=0;n<selectedLocations.length;n += 1) {
if (selectedLocations[n].location_id === location.id) {
return true;
}
}
return false;
}
}
This is actually a function returning a filter function, based on the item selected.
Then in your select you apply the filter with:
<select
class="form-control"
ng-model="vm.transaction.location_from"
ng-options="l as l.name for l in vm.locations | filter:vm.filterFun(vm.transaction.item.locations)">
</select>
See plunker here.
Upvotes: 0
Reputation: 2687
var app = angular.module("Test", []);
app.controller("Ctrl1", function($scope) {
$scope.location_fromArr =
[{
"id": "9f582e58-45dd-4341-97a6-82fe637d769e",
"name": "20oz Soft Drink Cup",
"locations": [{
"inventory_id": "9d5aa667-4a64-4317-a890-9b9291799b11",
"location_id": "c0d916d7-caea-42f9-a87f-a3a1f318f35e"
},{
"inventory_id": "9d5aa667-4a64-4317-a890-9b9291799b11",
"location_id": "d8a299a3-7f4b-4d32-884f-efe25af3b4d2"
}],
}];
$scope.itemArr =
[{
"id": "c0d916d7-caea-42f9-a87f-a3a1f318f35e",
"name": "Location 1"
},{
"id": "d8a299a3-7f4b-4d32-884f-efe25af3b4d2",
"name": "Location 2"
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="Test" ng-controller="Ctrl1">
Item
<select
class="form-control"
ng-model="item"
ng-options="i.name for i in itemArr">
</select>
Location
<select
class="form-control"
ng-model="location_from"
ng-options="l.name for l in location_fromArr | filter:{l.id: location_from.location_id}">
</select>
</div>
Upvotes: 0