Filtering Nested Properties in ngRepeat - javascript

In my controller I have:
$scope.currentDiscount = new DiscountPrototype;
Where:
var DiscountPrototype = function(){
this.Id = 0;
this.PromoCode = null;
this.DiscountValue = null;
this.DiscountProducts = []
}
var DiscountProductPrototype = function(discountId,id,catId,catType,name) {
this.DiscountId = discountId;
this.ProductCategoryType = catType;
this.Name = name
}
And then I push a bunch of new DiscountProductPrototypes into the DiscountProducts array of $scope.currentDiscount. If the DiscountProduct has a ProductCategoryType = "C" it is a category, and if it is "P" it is a product. My filter is intending on only displaying the objects in the DiscountProduct array that are categories.
<div ng-repeat="category in currentDiscount.DiscountProducts | filter:{category.ProductCategoryType: 'C' : true}"
class="productTile">
<p>{{category.Name}}</p>
</div>
With the above filter I get the following error:
Syntax Error: Token '.' is at column {2} of the expression [{3}] starting at [{4}].
Which seems to say there's something wrong with:
category.ProductCategoryType
If I do the following, I get no error, but the filter does nothing. Both categories and products are displayed.
<div ng-repeat="category in currentDiscount.DiscountProducts | filter: category.ProductCategoryType='C'"
class="productTile">
Do I need to create a custom filter to achieve this kind of filtering?

This should work:
<div ng-repeat="category in currentDiscount.DiscountProducts | filter:{ProductCategoryType: 'C'}"
class="productTile">
<p>{{category.Name}}</p>
</div>

The problem is with placement of true word.
true must be placed after second colon. After first colon, it should be just Expression.
Try following...
<div ng-repeat="category in currentDiscount.DiscountProducts | filter:{ProductCategoryType: 'C'}: true"
class="productTile">
<p>{{category.Name}}</p>
</div>
For more information on Filters, refer: https://docs.angularjs.org/api/ng/filter/filter

Related

Angular 6 calling method and asigning value to variable inside *ngFor

I want to call a method inside ngFor and want to assign the return value to a local variable. I tried this approach:
<div *ngFor="let card of partNumberPlanningCards; let i = index" class="partnumber-basic-card">
<div
*ngFor="let scope of containerScopeLineItems; let lineItem = getOperatingWeightBy(scope.containerScopeId, card.typeId)">
</div>
</div>
But it's showing this error:
Parser Error: Unexpected token (, expected identifier, keyword, or string at column 74 in [let scope of containerScopeLineItems; let lineItem = getOperatingWeightBy(scope.containerScopeId, card.typeId)] in ng
You can store function returned value in any of the attribute of element and use the element reference to get value.
<div *ngFor="let card of partNumberPlanningCards; let i = index" class="partnumber-basic-card">
<div *ngFor="let scope of containerScopeLineItems" #lineItem [title]="getOperatingWeightBy(scope.containerScopeId, card.typeId)">
{{lineItem.title}}
</div>
</div>
Here title has been used but you can use any of valid attribute of element.
What are you trying to do here? Calling a function within ngFor to update DOM is certainly a bad practice to do.
As it looks, you want to filter based on the containerScopeId and typeId, you could simply do this and assign to a variable in the component.ts level rather than calling a function in the template.
Just declare a variable lineItem and use array.find() with your conditions to get the matching item.
Not sure if it helps you. But just tried something.. You can create a ng-template and use ng-container to display the template.
HTML:
<div *ngFor="let card of partNumberPlanningCards;" class="partnumber-basic-card">
{{card?.typeId}}
<div *ngFor="let scope of containerScopeLineItems;">
<ng-container *ngTemplateOutlet="eng; context: getOperatingWeightBy(card.typeId, scope.containerScopeId)"></ng-container>
{{scope?.containerScopeId}}
</div>
<ng-template #eng let-obj='value'>
{{obj}}
</ng-template>
TS:
export class AppComponent {
partNumberPlanningCards = [
{typeId : 'xx'}
]
containerScopeLineItems = [
{containerScopeId : 2}
];
getOperatingWeightBy(a,b){
return {value:a+b};
}
}
https://stackblitz.com/edit/angular-ngfor-loop

Display AngularJS array to a 'human' readable string

I have outputted a variable that is an array within my view and while it is displaying the values as following :-
Inbound bound posts will contain ["phone", "car"]
How do I change this to display this in a human format eg. (as below)
Inbound bound posts will contain phone, car
if you simply want to list the array you can use join:
arr = ["phone", "car"];
arr.join(", ");
would output: "phone, car".
To make array displayed as series of texts
Inbound bound posts will contain {{ ["phone", "car"].join(', ') }}
Create a method on your controller to handle the array->string:
let arrayToWrite = ['phone', 'car'];
aToS() {
return arrayToWrite.join(' ');
}
Then your view:
Inbound bound posts will contain {{ vm.aToS() }}
(assuming 'vm' is your controller, as per standard convention)
You could input the array to the method too, if you need, rather than defining the array outside the method.
There are many alternatives. You could also do this:
<div>
Inbound bound posts will contain
<span ng-repeat="obj in objects">{{obj}} </span>
</div>
and in your controller hold the list on scope:
$scope.objects = ["car", "phone"];
You could use a filter:
myApp.filter('join', function () {
return function join(array, separator, prop) {
if (!Array.isArray(array)) {
return array; // if not array return original - can also throw error
}
return (!!prop ? array.map(function (item) {
return item[prop];
}) : array).join(separator);
};
});
And in your HTML, simply write this:
<div ng-controller="MyCtrl">
Inbound bound posts will contain {{things | join: ', ' }}
</div>
A working JSFiddle: http://jsfiddle.net/Lvc0u55v/12345/

How do you exclude items from AngularJS ng-repeat

Is it possible to exclude items in an ng-repeat?
For example, I have something similar to the following (simplified to keep things shorter):
<div class="row" data-ng-repeat="entry in data.feed.entry | orderBy:'gsx$timestamp.$t':true">
{{entry.gsx$jobID.$t}}
</div>
I have another scope object called exclusionData that is structured in a similar fashion. I want to exclude any items in my first ng-repeat that appear in an exclusionData.feed.entry.gsx$jobID.$t
Or is there an easier way to do this back in my controller (i.e. do the exclusion in data right away)? Both the data and the exclusionData is sourced from two different JSON feeds.
This will exclude the matching data simply adding an ng-if, and adding a bang to make it falsy.
<div
class="row"
data-ng-repeat="(key, entry) in data.feed.entry | orderBy:'gsx$timestamp.$t':true"
ng-if="!exclusionData.feed[key]gsx$jobID.$t">
{{entry.gsx$jobID.$t}}
</div>
You can either use a filter shown below, or just an ng-if/ng-show
<div class="row" data-ng-repeat="entry in data.feed.entry | orderBy:'gsx$timestamp.$t':true | filter: {gsx$exlucde.$t: true}">
{{entry.gsx$jobID.$t}}
</div>
data.feed.entry = [{
gsx$jobID.$t: 'something',
gsx$exlucde.$t: true,
gsx$timestamp.$t: '1/1/1990'
}]
the easiest way to do this is with a filter directive in your repeat, but you could also do this in your controller.
It depends on how your application looks like from a OO design perspective.
You can create a filter like this:
angular.module('appFilters', []).filter('yourFilterName', function() {
return function(input, key) {
var myList = [];
for(var i = 0; i < input.length; i++){
var found = _.find($scope.exclusionData, function() { // You can replace this with your own function.
// Your own logic here
});
if(found){
myList.push(input[i]);
}
}
return myList;
};
});
I am assuming you have underscore included in you project, but you can implement your own search function instead.
The in your template you pass the filter like this:
<div class="row" data-ng-repeat="entry in data.feed.entry | yourFilterName | orderBy:'gsx$timestamp.$t':true">
{{entry.gsx$jobID.$t}}
</div>

Filter ng-repeat json result against array

At the moment I have a json result which is displayed in an ng-repeat that I would like to have filtered based on a separate object or array of data:
Controller.js
$scope.jsonResult = [
{
"id": "a123"
},
{
"id": "b456"
}
]
HTML
<span ng-repeat="r in jsonResult">{{r.id}}</span>
What I am attempting to achieve is to create a separate array of info and then use this data to filter the ng-repeat results that display in my HTML.
$scope.itemsToFilter = ["b456","foo"]
Since an item within my itemsToFilter array matches an object within my jsonResult scope, I would like that not to display within my ng-repeat within the HTML. Is this something I should write a custom filter for? Sorry I am very new to Angular.
You can create an Angular filter which returns the array filtered by items' ids which match your blacklist:
angular.module("yourAppName")
.filter("filterArrayByBlacklist", function() {
blackList = ["b456","foo"];
return function(array) {
return array.filter(function(item) {
return blackList.indexOf(item.id) === -1; // item id not found in blacklist
});
};
});
You can then filter the ng-repeat by your filter function:
<span ng-repeat="r in jsonResult | filterArrayByBlacklist">{{r.id}}</span>
See this plnkr for a demo: http://plnkr.co/edit/VK3jiVBpL0e1G06WmPZq
The easiest way is by using a custom filter. A quick filter can be written like this:
$scope.filterByStrings = function (item) {
return ($scope.itemsToFilter.indexOf(item.id) === -1);
};
And called like this:
<div ng-repeat="item in data | filter:filterByStrings ">
<p>{{item.id}}</p>
</div>
Here is the fiddle.

AngularJS filter on multiple values of one field

I need to be able to filter on two different values of one field of an object. Take the following example.
$scope.products = [
{name:"Apple",type:"fruit"},
{name:"Grape",type:"fruit"},
{name:"Orage",type:"fruit"},
{name:"Carrot",type:"vegetable"},
{name:"Milk",type:"dairy"}
]
With the filter ng-repeat="item in products | filter:{type:'fruit'}". I can get all of the fruits. But what if I want to get all of the fruits and vegetables. I tried
ng-repeat="item in products | filter:{type:['fruit','vegetable']}"
But that didn't work. I figure there should be a simple solution to this, but I couldn't find it.
JSFiddle Example
Use a filter function instead:
$scope.fruitOrVeg = function(product){
return product.type == 'fruit' || product.type == 'vegetable';
};
<li ng-repeat="item in products | filter:fruitOrVeg">{{item.name}}</li>
Fiddle

Categories

Resources