how to get first object in ng-repeat - angularjs

I am displaying a contact's information using ng-repeat. Each contact has details. I am trying to grab the first object in the list. Here is my code:
<div ng-repeat="contact in contactList() | filter:{type: 'direct'} | filter:{duration: '1 year'} | orderBy: 'Date'">
<div ng-click="selectedContact(contact)">
<div>{{contact.name}}</div>
<div>{{contact.type}}</div>
</div>
</div>
contactList() is a function calling services:
$scope.contactList = function () {
return ContactService.getContactList();
};
How do I get the first contact object in the ng-repeat? I want to save that object for other windows.

You can set a new scope property to be a result of filtering and ordering. Note, how you group filters with ():
<div ng-repeat="contact in contacts = (contactList() | filter:{type: 'direct'} | filter:{duration:'1 year'} | orderBy: 'Date')">
<div ng-click="selectedContact(contact)">
<div>{{contact.name}}</div>
<div>{{contact.type}}</div>
</div>
</div>
Then to get the first from this list it will be just [0]:
{{ contacts[0] }}

I'm guessing you don't just want to display the one record and you also want the first record from the array after your filters/ordering are applied. If that is the case I would recommend simply adding an alias after your last condition and then you can reference that alias in your controller.
here is a fiddle to help show:
http://jsfiddle.net/nbavesuo/
I would suggest you not call the function in the ng-repeat instead reference an array that has already been called:
<div ng-repeat="contact in contactList|
filter:{type: 'direct'}| filter:{duration:'1 year'}|
orderBy: 'Date' as filteredArray">
....
Then in your controller:
$scope.contactList = ContactService.getContactList();
$scope.selectedContact = function(contact){
console.log(contact);
console.log($scope.filteredArray[0]);
}
You'll see that $scope.filteredArray[0] will have the 1st element in the sorted array.

You could use 'track by $index' and use an 'ng-if' to determine when it's the first object:
<div ng-repeat="contact in contactList()| filter:{type: 'direct'}| filter:{duration:'1 year'| orderBy: 'Date' | track by $index"
ng-if="$index == 0"
ng-init="someMethod()">
<div ng-click="selectedContact(contact)">
<div> {{contact.name}}</div>
<div>{{contact.type}}</div>
</div>
</div>
You could then have a function 'someMethod()' in your controller that saves the object to a window object or to local storage:
function someMethod(key, object) {
window.localStorage.setItem(key, object);
}
I have written an object to use for this exact thing in fact if you want to use it:
var LocalStorageManager = {
setValue: function(key, value) {
window.localStorage.setItem(key, JSON.stringify(value));
},
getValue: function(key) {
try {
return JSON.parse(window.localStorage.getItem(key));
} catch (e) {
}
}
};
So, you would use it with your stuff like this, in your 'someMethod()':
function someMethod(key, object) {
LocalStorageManager.setValue(key, object);
}
Then, to get the object, you would just use the 'getValue' method calling the 'key' that you gave the object.

Related

angucomplete-alt selected object data

in the documentation says that:
selected-object-data -> A second parameter which will be passed to selected-object. I'm trying to use it but the callback function is not receiving it.
What i'm doing wrong?
<div data-angucomplete-alt=""
id="agent"
data-placeholder="Type to search"
data-pause="400"
data-selected-object="callbackFunction"
data-selected-object-data="row"
data-remote-url="getClients?searchString="
data-remote-url-data-field="Clients"
data-title-field="CompanyName"
data-input-class="form-control"
data-match-class="highlight"
data-minlength="2"
data-initial-value="{{row.agentCompany}}"
data-remote-url-response-formatter="formatAutoCompleteJson">
</div>
$scope.callbackFunction = function (selected) {
console.log(selected); //print only the selected object, no the data (second parameter)
//how to get the second parameter?
}
I think if you added a 2nd parameter to your callback function, then you could access the value of "row"
$scope.callbackFunction = function (selected, row) {
console.log(selected);
console.log(row); // should print the row number
}
I created an initialiser function in the controller, which returns the callback function into the scope of the repeat.
<html>
<div ng-repeat="row in rows">
...
<div ng-init="row.callbackFunction = initialiseCallback(row)"></div>
<angucomplete-alt selected-object = "row.callbackFunction" />
...
</div>
</html>
Controller() {
$scope.initialiseCallback = function (row){
return function function (selected) {
console.log(selected);
console.log(row); // should print the row number
}
}
}
I just find out that I was using an older version of the angucomplete, I updated it to the latest version and the parameter start working.
If you are using a ng-repeat
for example
<ul>
<li ng-repeat="customer in customers track by $index">
<angucomplete-alt pause="500"
selected-object="selectedCustomer"
selected-object-data="$index"
remote-url={{apiURL}}/customers/q?search="
remote-url-data-field="customers"
title-field="surname,name"
description-field="address"
minlength="3"/>
</li>
</ul>
If in selected-object-date you bind the $index of ng-repeat
In this case you can have this situation
$scope.selectedCustomer = function(customer, index) {
console.log(customer, index);
};

How to filter based on a property of the current object?

I have a list of file objects like this:
{"name":"A1.java", "analyze":false, "index":0},
{"name":"A2.java", "analyze":true, "index":1},
{"name":"A3.java", "analyze":false, "index":2}
I'm trying to show the file names that have "analyze":true. I think it needs to be something like this:
<div class="row">
{{m.files.name | filter: m.files.analyze == true}}
</div>
But this is not giving me an error, and it's not showing anything.
Edit: I know there are many ways to do this, but I am specifically interested in filtering. If your answer doesn't involve filtering or why it can't be done with filtering, please don't bother, I already know how to do it other ways.
Use ng-repeat with a filter to show all rows that qualify, like this:
<div ng-repeat="file in m.files | filter: {analyze: true}">
{{ file.name }}
</div>
Or, if you want to simply evaluate m.files for a condition like analyze = true, you can create a custom filter, like this
app.filter('fileFilter', function() {
return function(files) {
var result = false;
angular.forEach(files, function(file) {
if (file.analyze) {
result = true;
}
});
return result;
};
});
and use it like this:
<div ng-show="(m.files | filter:fileFilter)">
You can try this
function PersonalFilter(data){
return (data.analyze)? data.name:"";
}
app.filter('myFilter', function() {
return PersonalFilter;
});
<div class="row">
{{m.files | myFilter}}
</div>

How to search on the displayed data and not the backing data using Angular

I am using ng-repeat to create a table of data:
<div class="divTable" ng-repeat="expense in exp.expenses | filter:exp.query">
<div>{{expense.amount | ldCurrency : true}}</div>
...
</div>
A couple of the cells that I am creating are being modified through an Angular filter. In the example above, I am changing the integer to a currency. So the original 4 is changed to $4.00. When I filter the entire list with my exp.query, it does not modify the exp.query search term through the ldCurrency.
The means that if I search on $4, it will not find it, because the backing data is 4, even though $4 is on the page.
I know this is confusing, with the two types of filters that I am talking about here.
How can I search on the data that is being shown on the page and not on the backing data?
You have to create you own filter. What you want to do to is a bad idea, because you are melding the view layer and the model layer.
A example of a filter.
The html:
<input ng-model="query" ng-trim="true">
<span>Finding: </span><span>{{ query }}</span>
<div ng-repeat="product in products | productsFilter: query">
<strong>{{ $index }}</strong>
<span>{{ product.name }}</span>
<span>{{ product.price | currency: '$'}}</span>
</div>
The custom filter:
.filter('productsFilter', [function () {
// Private function: It removes the dollar sign.
var clearQuery = function (dirtyQuery) {
var index = dirtyQuery.indexOf('$');
if (index === -1)
return dirtyQuery;
return dirtyQuery.substr(index+1, dirtyQuery.length-index)
};
// The Custom filter
return function (products, query) {
if (query === '') return products;
var newProducts = [];
angular.forEach(products, function (product) {
var cleanQuery = clearQuery(query);
var strProductPrice = '' + product.price;
var index = strProductPrice.indexOf(cleanQuery);
if (index !== -1) {
newProducts.push(product);
}
});
return newProducts;
};
}]);
The key is in the angular.forEach. There I decide if the product will belong to the new filtered collection. Here you can do the match you want.
You can find the complete example in full plucker example and see a lot of filters in the a8m's angular-filter

OrderBy gets ignored

I have the following ng-repeat:
<div ng-repeat="location in truckDetail.locations track by $index | orderBy:location.startDate" class="locationLoopRow">
<span class="rowEdit"><i ng-click="location.editMode=!location.editMode" class="fa {{location.editMode?'fa-ban':'fa-pencil'}}"></i></span>
<span class="rowDate">{{location.startDate|date:'dd.MM.yyyy'}}</span>
<span class="rowDate">{{location.endDate|date:'dd.MM.yyyy'}}</span>
<span class="rowLocation">{{location.name}}</span>
</div>
The orderBy seems to be ignored completely as seen in the screenshot.
I also tried to solve this by using a sort-function:
| orderBy:dateOrderBy(location.startDate)
$scope.dateOrderBy=function(date) {
return date.getFullYear()+'/'+date.getMonth()+'/'+date.getDate();
},
In debug mode I can see that this message returns values like '2015/4/29'. Still: The list isn't sorted at all
You don't need to call dateOrderBy function in ng-repeat, you only need to specify it's name:
| orderBy:dateOrderBy
Then in your controller your sort function will receive the location object:
$scope.dateOrderBy = function(location) {
return location.startDate;
};
Example in plunkr.
UPD: this one should work as well:
| orderBy:'startDate'
UPD 2: track by $index should always go in the end of expression:
location in truckDetail.locations | orderBy:'startDate' track by $index

AngularJS ng-repeat filter, function over object property

I am looking for a way to check for each movie if the movie has the category which is selected. Movies is an array which contains objects, those objects have some properties, like you can see in the code below. The categories property is a array of categories where the movie is in. Now there is a variable selectedCategories where the current selected category is stored in.
I don't want to use custom filters, because I think it has te be possible with this one, I just can't quite get it. In the javascript function there can't be changed too much either.
If the return of hasSelectedCategory is true, then it has to execute the block, if false not.
Thanks in advance.
//in the javascript file
scope.hasSelectedCategory = function(categories){
var hasCategory = false;
if (categories.indexOf(scope.selectedCategory) !== -1){
hasCategory = true;
}
return hasCategory;
};
//in the html file
<div class="movieListItem {{listItemView}}" ng-repeat="movie in movies | filter:{hasSelectedCategory(categories): true}">
<h4>{{movie.title}}</h4>
<a href="http://www.youtube.com/embed/{{movie.youtubeId}}?rel=0&autoplay=1">
<img ng-src="{{findPosterSource(movie)}}" class="poster"> </a>
<p ng-hide="listItemView === 'grid'">
{{movie.description}}
</p>
<div class="categories" >
<span ng-repeat="category in movie.categories"> <a ng-href="#">{{category}}</a> </span>
</div>
</div>
You have to use the filter like this:
ng-repeat="movie in movies | filter:hasSelectedCategory"
The hasSelectedCategory function will be invoked for each movie in the movies list. In order to filter by selected categories you can use a function like this:
$scope.hasSelectedCategory = function(movie) {
var hasCategory = false;
angular.forEach($scope.selectedCategories, function(selectedCategory) {
if (!hasCategory && movie.categories.indexOf(selectedCategory) !== -1) {
hasCategory = true;
}
});
return hasCategory;
};
Demo (plunker)

Resources