I need to get the current object out of an ng-repeat on ng-click, I can't use $index because I'm using orderBy and therefore it gives me the wrong index relative to the scope object. Idealy I want to be able to click on the object (thumbnail) and have $scope.activePerson gain all that objects values.
My data is structured as follows:
[
{
'name': 'john'
},
{
'name': 'toby'
},
{
'name': 'sarah'
}
]
This is very much simplified, my real objects have 30+ KV pairs and subobjects. There are 10 objects that I'm repeating from (in batches of 4).
My current HTML is:
.item.fourth(ng-repeat="person in people | orderBy:'-name' " ng-show="$index <= 3" nid="{{person.guid}}"
Thanks
It's just person in ng-repeat="person in people";
I'm not sure what kind of markdown you're using, you definitely don't have html there, but you want something like:
<div
ng-repeat="person in people | orderBy:'-name' "
ng-show="$index <= 3"
nid="{{person.guid}}"
ng-click="activePerson = person">
</div>
Note that ng-repeat creates a child scope, so you'll want to have activePerson already set in the parent scope.
You can just use orderBy and copy the current object from ng-repeat, see this plunkr. Relevant code:
Controller
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.stuff = [
{
'name': 'john'
},
{
'name': 'toby'
},
{
'name': 'sarah'
}
];
$scope.setActivePerson = function (obj) {
$scope.activePerson = obj;
};
});
View
<body ng-controller="MainCtrl">
<div ng-repeat="thing in stuff | orderBy: 'name'">
<input type="radio" ng-click="setActivePerson(thing)" />
{{ thing.name }}
</div>
<br />
<div ng-model="activePerson">Active: {{ activePerson.name }}</div>
</body>
Related
I'm trying to ignore a property called title in my angular filter. I have a dataset like the below example:
const data = [
{
title: 'Title 1'
groups: [
{...},
{...},
{...}
]
},
{
title: 'Title 2'
groups: [
{...},
{...},
{...}
]
},
{
title: 'Title 3'
groups: [
{...},
{...},
{...}
]
}
];
And i'm using the ng-repeat with filter to iterate over the objects, and other loop to iterate over the groups:
<input ng-model="search">
<div ng-repeat="item in data | filter:search">
<h1>{{item.title}}</h1>
<ul>
<li ng-repeat="group in item.group | filter:search">
<span>{{group.something}}</span>
</li>
</ul>
</div>
Is working fine, but now i would like to ignore the title in the search. I did try several things, like: filter:search:item.title (in the first ng-repeat), or remove the first filter:search, but all tries failed. What i'm missing? Do i need a custom search or something like that?
Thank you.
You can specifically enter properties you want to filter and leave out title:
<li ng-repeat="group in item.groups | filter: { something: search }">
The above code will only filter based on the something property.
More answers and explanations here: AngularJS filter only on certain objects
If you type and no filtering the title property, just remove the first filter. This way when you type the li's isnt match will hide, but their h1's will stay the same place.
You should create custom filter, where you can specify which property should be excluded(ignore parameter) from consideration:
angular.module('app', []).controller('MyController', ['$scope', function($scope) {
$scope.data = [
{name:"Tom", title:'London'},
{name:"Max", title:'Moscow'},
{name:"Henry", title:'NY'},
{name:"Paul", title:'NY'},
{name:"Sam", title:'Paris'}
];
}]).filter('myfilter',function(){
return function(input, search, ignore){
if(!search)
return input;
var result = [];
for(var item of input)
for(var prop in item)
if(prop != ignore && item[prop].indexOf(search) != -1)
{
result.push(item) ;
break;
}
return result;
}
});
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="MyController">
search: <input type='text' ng-model='search' ng-init='search="a"'/>
ignore: <input type='text' ng-model='ignore' ng-init='ignore="title"'/>
<ul>
<li ng-repeat='item in data | myfilter: search: ignore'>
{{item.name}} {{item.title}}
</li>
</ul>
</div>
</body>
I'm trying to concatenate an ng-repeat item to ng-model object. I was wondering if this possible.
so for example:
//array
$scope.array = [
{
param: 'color',
....
},
{
param: 'weight',
.....
}
]
html
<div ng-repeat="item in array">
{{ item.param }}
<input type="text" ng-model="form.name.{{ item.param }}" >
</div>
so lets say {{ item.param }} is color, the ng-model will be form.name.color.
form object will be something like this:
{
name: {
color: 'value of input',
weight: 'value of input'
}
}
How can I concatenate the item.param to the object form.name? I've been trying so many ways but no results. I trying to use $index, but don't know where to begin.
Your help will be appreciated!
Check out this fiddle.
Your ng-model should look like this:
ng-model="form.name[item.param]"
When iterating a list with ng-repeat, how can I add a condition/filter by a property of those items.
Example (of course there are several items in real world):
{"items":[{"type":"xxx"}]}
I only want to show the item where type!='test'.
The following just prints nothing:
<ul ng-repeat="item in items | filter: (item.type != 'test')">
Whereas if I remove the filter, all items are printed, of course.
Also, if possible, how could I create a condition that checks for multiple type values not being permitted?
Simple, use a function in the filter expression.
angular.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.items = [{
"type": "xxx"
}, {
"type": "test"
}];
$scope.filterFn = function(value) {
return value.type !== 'test';
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="AppCtrl">
<ul>
<li ng-repeat="item in items | filter: filterFn">{{item.type}}</li>
</ul>
</div>
If your data schema changes just update the filter function.
You could also use object notation
angular.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.items = [{
"type": "xxx"
}, {
"type": "test"
}];
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="AppCtrl">
<ul>
<li ng-repeat="item in items | filter: {type: '!test'}">{{item.type}}</li>
</ul>
</div>
but this has some limitations like not suporting primitive value filters(it expects an object with properties as the item) and the same filter cannot be specified multiple times(something like {type:"!test!xxx"})
You could change your ng-repeat to read like this:
<ul ng-repeat="item in items | filter: {type: '!test'}">
In order to provide multiple type values you can create your own filter for reusability like so:
app.filter('typeFilter', function(){
return function(arr,criteria){
if(!angular.isDefined(criteria) || criteria == ''){
return arr;
}
return arr.filter(function(curr){
return criteria.indexOf(curr.type) == -1;
});
}
});
and then change your ng-repeat statement to read:
//List array of criteria...
<ul ng-repeat="item in items | typeFilter:['test'] ">
I have an array of objects which I want to display as a table with filter. My filter with model name is filtering the deep object family. This works fine but not the way I want it to work...
What I want: Insert string to input, e.g. 'Ma'. Now, I want it to display all items containing a string in family matching 'Ma' - that means I want to keep all the family members displayed as long as one string matches. In my example this would be the filtered result:
Homer Marge, Bart, Lisa, Maggie
Ned Maude, Rod, Todd
Example Code with snippet below:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.tableData = [
{id: 1, name: 'Homer', family: ['Marge', 'Bart', 'Lisa', 'Maggie']},
{id: 2, name: 'Carl', family: []},
{id: 3, name: 'Lenny', family: []},
{id: 4, name: 'Clancy', family: ['Sarah', 'Ralph']},
{id: 5, name: 'Ned', family: ['Maude', 'Rod', 'Todd']},
{id: 6, name: 'Moe', family: []}
];
});
table td {
padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tr>
Filter family members: <input type="text" ng-model="name">
</tr>
<tr ng-repeat="item in tableData">
<td>{{item.name}}</td>
<td>
<span ng-repeat="member in item.family | filter: name">
{{member}}{{$last ? '' : ', '}}
</span>
</td>
</tr>
</table>
</div>
You need to filter the first ng-repeat:
<tr ng-repeat="item in tableData | filter: name && {family: name}">
The key is to provide the name of the property you want to filter on. Here it is the property family.
See fiddle (Type ma in the search box)
Edit: And remove the filter you placed on the inner ng-repeat
You can solve this without a custom filter, by providing a conditional filter on the first ng-repeat. For example:
<tr ng-repeat="item in tableData | filter: (name.length > 0 || '') && {family: name}">
You need the conditional because if you add a filter and remove it, the blank arrays wont be considered (angular quirk).
I have created a working fiddle here
You want to use a custom filter on the top ng-repeat. You can specify a function as the filter: custom filter answer. In this custom filter return all items in tableData that contain a match in the sub array.
Note: You could use lodash to help with this calculation.
Example: plunkr example
<tr ng-repeat="item in tableData | filter:criteriaMatch(name)">
...
$scope.criteriaMatch = function( criteria ) {
return function( item ) {
if(!angular.isDefined(criteria) || criteria === "")
return true;
var results = _.filter(item.family, function(n) {
if(_.contains(n.toUpperCase(), criteria.toUpperCase()))
{
return true;
}
});
if(results.length !== 0)
return true;
else return false;
};
};
Do you try to use the filter in tableData?? Something like this:
<input type="text" ng-model="family">
And
<tr ng-repeat="item in tableData | filter: family">
I am following this question to filter ng-repeat by a field
ng-repeat :filter by single field
However my case is different, it's actually a field in the object value of the main object. Basically I want to show only data.a == 1
The following code works on the first list. The second list gives me error:
angular.module('myapp', [])
.controller('mainCtrl', function ($scope) {
$scope.items = [{
name: "John",
data: {
a: 1
}
}, {
name: "Lee",
data: {
a: 2
}
}, {
name: "Rue",
data: {
a: 3
}
}, {
name: "Peter",
data: {
a: 1
}
}];
});
HTML
<div ng-controller="mainCtrl">
<h1>List 1</h1>
<p ng-repeat="item in items">{{ item.name }}</p>
<h1>List 2</h1>
<p ng-repeat="item in items | filter: {data.a :1}">{{ item.name }}</p>
</div>
http://plnkr.co/edit/nh4GryqZJbEiXSzMzTKk
Any help on how to do this or is there a nicer way?
UPDATE 1
I tried angular.filter filterBy and it didn't work either. Giving me blank array.
http://plnkr.co/edit/nh4GryqZJbEiXSzMzTKk?p=preview
<p ng-repeat="item in items | filterBy: ['item.data.a'] :1">{{ item.name }}</p>
UPDATE 2
I tried this below
<p ng-repeat="item in items | filter: {data :{a:1}}">{{ item.name }}</p>
It seems to work but I need exact match, not substring match. I read this but not seem to find a way to add true AngularJS Filter Exact Match
Any clue?
UPDATE 3 (CORRECT ANSWER):
This works http://plnkr.co/edit/qJl6MtY6fOlVtD9Rv999?p=preview
Basically I added this to the controller
$scope.filteredItems = $filter('filter')($scope.items, {data :{a:1}}, true);
and do ng-repeat on filteredItems instead. I don't see a way to pass true param in the view directly.
If you want to access the inner property you need to access it with object notation:
<p ng-repeat="item in items | filter: {data :{a:1}}">{{ item.name }}</p>
Check this plunker.
If you are using \ can upgrade to angular 1.3, then you can use this: 1.3 filters These are faster. In particular, you can use filterBy
See: plunkr example
<p ng-repeat="item in items | filterBy: ['data.a'] :1">{{ item.name }}</p>
Otherwise, use a custom function. See my answer here: custom function