Okay so i have the following object:
$scope.search = {};
this allows me to search through the following elements:
<div class="col-md-12" ng-repeat="question in questions | filter:search:strict">
Now one of the things i can do is to set a variable called category_id which then filters the category_id of each item:
$scope.search.category_id = selected.id;
However there is a problem. once i try to reset it AKA call $scope.search.category_id = null
All result disapear.
So it seem it is searching for categories where id = null which is false in every case.
So my question is how do i reset it then?
You should delete the property from the object rather than setting it to null. That will remove it from being listed in the search criteria.
delete $scope.search.category_id
You can see how this is different from setting it to null below
var a = { hello: 5 }
console.log(a, Object.keys(a)) // Object {hello: 5} ['hello']
a.hello = null
console.log(a, Object.keys(a)) // Object {hello: null} ['hello']
delete a.hello
console.log(a, Object.keys(a)) // Object {} []
Related
In one component I can filter my array using the following:
// Array of product objects
const result = products.filter(p => p.name.includes('val'));
and value of products remains same as the first value but filtered value stores in result.
But in the following code, filter() filters array of strings itself:
// Array of strings
const result = strs.filter(s => s.includes('val'));
The question is how can I filter strings and return result without modifying the strs itself?
Note: I tried with array.filter(function() { return res; }); but didn't make any change.
It returns the filtered ones and don't change the actual array. You are doing something wrong
const strs = ['valval', 'bal', 'gal', 'dalval'];
const result = strs.filter(s => s.includes('val'));
console.log(strs);
console.log(result);
First thing we need to know is, if we filter our list we loose our original data
products: any[] = [
{
"productId": 1,
"productName": "foo-bar",
"price": 32.99
}
]
and can't get it back without re-getting the data from it's source so we have to make another list to store the filtered list.
filteredProduce: any[];
Next if you are working to show a list of filtered product on a grid or something like this we need a way to know when the user changes the filter criteria. we could use event binding and watch for key presses or value changes, but an easier way is to change our _listFilter property into a getter and setter, like this
get listFilter: string {
return this._listFilter;
}
set listFilter(value:string) {
this._listFilter= value;
}
next we want to set our filteredProducts array to the filtered list of products like this
set listFilter(value:string) {
this._listFilter= value;
this.filteredProducts = this._listFilter? this.performFilter(this._listFilter) : this.products;
}
in preceding code we are using js conditional operator to handle the posibility that _listFilterstring is empty, null or undefined.
Next we use this.performFilter(this._listFilter) to filter our list.
performFilter(filterBy: string): any[] {
filterBy = filterBy.toLocaleLowerCase();
return this.products.filter((product: any) =>
product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
Finally we should assign the main list of products to the filteredProducts and _listFilter to what we want.
constructor() {
this.filteredProducts = this.products;
this._listFilter= 'foo-bar';
}
last step is to change our template to bind to our filteredProducts property.
On my backend, I have a nested categories structure like this:
Category
--------
id
parent_id
name
That I load completely into $scope.categories as a single dimension array.
On screen, I want to show one dropdown per level, showing the correspondent path. For example, if the path is cars/sedan/ford/taurus, I want to show four dropdowns:
Cars v Sedans v Ford v Taurus v
Whenever a dropdown is changed, the ones to the right should be deleted, and the immediate one populated with all child categories whose parent is the one I just selected. Regular stuff.
I also created a category_path array that contains each category_id in the path to the product category: [null, category_id, category_id, category_id].
And then I did this:
<select
ng-repeat="item in category_path"
ng-model="selected_category[$index]"
ng-options="category.name for category in (categories | filter : { parent_id: item } : true ) track by category.id "
ng-change="select_category(selected_category[$index], $index)"
></select>
On my controller:
$scope.select_category = function ( selected_category, index ) {
if ( $filter('filter') ($scope.categories, { parent_id: selected_category.id }, true).length ) {
if ( $scope.category_path[index+1] != undefined ) {
$scope.category_path = $scope.category_path.slice(0, index+1);
$scope.category_path[index+1] = selected_category.id;
} else {
$scope.category_path.push( selected_category.id );
}
} else {
$scope.product.category_id = selected_category.id;
}
}
This works like charm, except for the fact that I can't populate the default values for each dropdown, based on the current product category_path array.
I tried:
ng-init="select_category[$index] = category_path[$index]"
without success. Ideas?
Your category_path array holds different values than the model, i.e. the selected_category array. The latter seems to hold JSON strings while the former holds a single value (for the id key).
To make the default values work, insert the full JSON objects into the model array.
I'm pretty new to AngularJS.
I'm using it with firebase.
I have a set of data like this one:
"userId1" : {
"name" : "Bobby",
"comments" : {
"-J_v90hh5sbJ2acmX4nq" : true
}
}
and a comment list
"-J_v90hh5sbJ2acmX4nq" : {
"creation_date" : 1415110466568,
"creator_id" : "userId1",
"desc" : "dsqdsq",
"type" : "suggest"
}
So what I want to do is to display all the comments of our friend Bobby.
.controller('CommentsCtrl', function($scope, $firebase){
var creator_id = 'userId1'; // Test purpose
var userCommentsRef = new Firebase("https://awesome.firebaseio.com/users/"+creator_id+'/comments');
var commentsRef = new Firebase("https://awesome.firebaseio.com/comments");
var userCommentsSync = $firebase(userCommentsRef);
var commentsSync = $firebase(commentsRef);
var userComments = userCommentsSync.$asObject();
var comments = commentsSync.$asObject();
$scope.userComments = userComments;
$scope.comments = comments;
})
Do you know how I should proceed with this display, but to be sure that if the comments has been deleted (and the key is still there), the description will not be displayed?
<ion-list ng-controller="CommentsCtrl">
<ul class="list">
<li class="item item-checkbox item-checkbox-right" ng-repeat="(key,item) in userComments">
{{comments[key].desc}} // Working, but don't want deleted comments
</li>
</ul>
</ion-list>
Is this the correct way to handle this situation?
How can I say to my controller to display only existing comments ?
You can use filter in ng-repeat block in a such way:
<li ng-repeat="(key,item) in userComments | filter:{deleted:false}">
{{comments[key].desc}} // Working, but don't want deleted comments
</li>
or, if information stored in comments object use ng-if:
<li ng-repeat="(key,item) in userComments | filter:{deleted:false}" ng-if="!comments[key].deleted">
{{comments[key].desc}} // Working, but don't want deleted comments
</li>
No, this is not the correct way. When working with collections, utilize $asArray instead of $asObject. From the guide:
Synchronized arrays should be used for any list of objects that will be sorted, iterated, and which have unique ids.
Objects are useful for storing key/value pairs, and singular records that are not used as a collection.
Also, there is no need to have a deleted parameter. You could simply removed the deleted comments from the user's index. Then if it exists in that list, it is not deleted. There is no need for extra filtering fanciness.
That said, you may also want to check out the new query parameters. With those, and a slight data structure change, you could match on items with a property of deleted equal to false, rather than sorting client-side in Angular.
So all together:
var fbRef = new Firebase("https://awesome.firebaseio.com/");
var userCommentsRef =
fbRef.child("users" + creator_id + "/comments")
.orderBy('deleted')
.startAt(false)
.endAt(false);
$scope.userComments = $firebase(userCommentsRef).$asArray();
Problem 1:
I came across this issue where in I need to create objects on the fly based on a loop.
Example:
angular.forEach([0,1,2], function (index) {
$scope.cc + index = buildMeProto();
});
Am I approaching this the wrong way? Can I create $scope.element based on an index?
Problem 2:
I also notice that in the HTML if you do something like:
<div ng-repeat="black in blacks">
<lightbox name="black+$index" />
</div>
you can't append an index to an object, in this case 'black' is an object and index is 0, 1,2 etc.
Is there a each way to piggy ride the index to create or invoke elements?
Thanks
Problem 1
If you want to create a $scope property on the fly you need to use the [] notation.
angular.forEach([0,1,2], function (index) {
$scope["cc" + index] = buildMeProto();
});
Problem 2
You could call a function on the scope that would augment the object by adding a property.
$scope.addIndex = function(person, index){
person.id = index;
};
Example jsfiddle.
I have this code in my router:
category: (id) ->
alert id
filteredProducts = new App.Collections.Products(#productsCollection.where({category_id: id}))
#productsView.renderResults(filteredProducts)
The alert id call works properly (e.g. app.com/categories/6 > alerts "6") and when I change the id in the where function to an actual number the products collection filters properly like so:
filteredProducts = new App.Collections.Products(#productsCollection.where({designer_id: 6}))
But when I set the designer_id: id the where loop return an empty collection.
My foreign key category_id was a number not a string. The answer is:
filteredProducts = new App.Collections.Products(#productsCollection.where({category_id: parseInt(id)}))