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

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

Related

How to pass data to child component's #Input from Observable

I have an angular component that I use as a tab in a for loop on the html page:
...
<ng-container *ngFor="let tabData of data$ | async;">
<tab-component
id="{{ tabData.id }}"
name="{{ tabData.name }}"
>
</tab-component>
</ng-container>
<child-component [selectedData]="selectedData"></child-component>
And in the .ts file:
public data$: Observable<Data[]>
public selectedData: Data
ngOnInit() {
this.data$ = this.service.getAllData();
}
ngAfterContentInit() {
this.data$.subscribe(items => this.selectedData = items[0])
}
I would like the first tab to always be the selectedData by default when first loading the page (element 0 in the array).
Then on click or the right/left arrow keys, dynamically update the value of selectedData passed to the child component.
So far, I've tried everything and the value of selectedData in the child component has always been undefined
Please help me, how can I achieve this!
I managed to get it so that the passed value on the child side is no longer undefined with an ngIf, so:
<child-component *ngIf=selectedData [selectedData]="selectedData"></child-component>
Subscribe for allData in the ngOnInIt itself and do check the value of items before assigning it - whether you are getting it or not and if you are not able to find the value there, then there must be the issue with the getAllDataService.
For child component, use double quotes to pass the value like this : <child-component [selectedTab]="selectedTab"></child-component>
Create a dummy variable in the parent ( or a hardcoded value ) and pass it to child. If your child component is working fine, then there's issue with only data and how you are assigning it.
Hope this helps!
Where exactly are you using the selectedData in your template HTML file?
In the snippet you provided there is a selectedTab used, but no selectedData anywhere...
<ng-container *ngFor="let tabData of data$ | async;">
<tab-component
id="{{ tabData.id }}"
name="{{ tabData.name }}"
>
</tab-component>
</ng-container>
<child-component [selectedTab]=selectedTab></child-component>
Also, you can follow #Eugene's advice and do:
ngOnInit() {
this.data$ = this.service.getAllData().pipe(
tap((items) => this.selectedData = items[0])
);
}
without using ngAfterContentInit() and the need to subscribe a second time.
You could use a subject to express the currently selected tab data, then use combineLatest to create an observable of both sources.
private data$: Observable<Data[]> = this.service.getAllData();
private selectedData$ = new BehaviorSubject<Data>(undefined);
vm$ = combineLatest([this.data$, this.selectedData$]).pipe(
map(([tabData, selected]) => ({
tabData,
selectedTab: selected ?? tabData[0]
})
);
setSelected(data: Data) {
this.selectedData$.next(data);
}
Here we create a single observable that the view can use (a view model) using combineLatest. This observable will emit whenever either of its sources emit.
We set the selectedData$ BehaviorSubject to emit an initial value of undefined. Then, inside the map, we set the selectedTab property to use tabData[0] when selected is not yet set. So, initially, it will use tabData[0], but after setSelected() gets called, it will use that value.
<ng-container *ngIf="let vm$ | async as vm">
<tab-component *ngFor="let tabData of vm.tabData"
[id] = "tabData.id"
[name] = "tabData.name"
(click) = "setSelected(tabData)">
</tab-component>
<child-component [selectedTab]="vm.selectedTab"></child-component>
</ng-container>

How to display the contents of a JSON object with multiple arrays in angular html?

I have created a JSON object which contains arrays, corresponding to the fields of a CSV file, which were parsed using the library papa Parse. I'd like to display these in HTML, but I don't know how to go about extracting the arrays from the JSON object and putting them into a variable to that it can be displayed in html.
typescript
func(){
this.fileHasBeenUploaded = true;
this.csvData = reader.result as string;
console.log(this.csvData);
console.log(this.papa.parse(this.csvData));
this.resultObj = this.papa.parse(this.csvData);}
html
<div *ngIf='fileHasBeenUploaded'>
TESTING TESTING:
<div *ngFor="let i of resultObj">
<span *ngFor="let j of i">
{{j}}
</span>
</div>
<div>
the array is: {{resultObj}}
</div>
My nested *ngFor loops give an error, and trying to display the object directly only displays "[object Object]"
The simpliest way would be to transform your object containing arrays into an array containing arrays. *ngFor can only iterate over iterables.
model.ts
export interface ObjectContainingArrays<T = any> {
[key:string]: Array<T>;
}
component.ts
public func():void {
this.fileHasBeenUploaded = true;
this.csvData = reader.result as string;
const resultObj:ObjectContainingArrays = this.papa.parse(this.csvData) as any;
this.resultArr = Object.values(resultObj);
}
component.html
<div *ngFor="let i of resultArr">
<span *ngFor="let j of i">
{{j}}
</span>
</div>
Edit: Updated to use any instead of unknown
Edit2: Removed type annotation in assignment (syntax error)

How to filter on the property of an object in Vuejs

I have two data sets: categories and products. I would like to filter products based on the category they belong to.
I need to filter on the category.name because the name can we equal to product.category. I know the dot nation is not accepted as function parameter but I can not find out how to pass it on.
I have tried: category["name"] and {{category.name}} without success.
<b-tab v-for="category in categories" v-bind:title="category.name" :key="category.id">
<div v-for="product in filteredByCategory(category.name)" :key="product.id" class="slide">
<b-card
v-bind:title="product.name"
:img-src="product.imageUrl"
style="min-width: 15rem; max-width: 15rem;"
>
</b-card>
This is the filter I use.
filteredByCategory(category){
return this.products.filter(product => product.category === category.name)
}
Can someone help please
You pass name already here:
filteredByCategory(category.name)
But then try access name property again in filter function.
product.category === category.name
Change one of those lines
Pass category object to - filteredByCategory(category)
Or check category instead product.category === category
Dot notation actually is accepted with the ES6
function({ propHere })
other than that I see that you already pass the category.name to the function filteredByCategory, but you are still using category.name. So it becomes like 'clothing'.name which is undefined, because string prototype doesn't have such method.

sign dynemic key.value in ngFor

I'm trying to assign a dynamic object value named destination inside ngFor like this:
<div *ngFor="let obj of object.destination"><p [innerHTML]="cont.disc"></p> </div>
This destination is supposed to change dynamically using property binding (it works)
In my component.ts there is a function which assigns the dynamic value I get to the destination value, and connect it to the object key:
public getDestination() {
this.destination = this.to;
return (this.destination = `${this.content}.${this.destination}`); }
But all I get is that {{ object.destination }} equal to
<p>[object Object].india</p>
How can I make the object value dynamic so it will change depending on the property binding?

Filtering Nested Properties in ngRepeat

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

Categories

Resources