There are several ways to tackle this issue.
Organize the data in the controller
function ExampleCtrl (products) {
this.$onChanges = (changes) => {
if (changes.products) {
this.specialProductPrices = this.products.reduce((map, product) => {
map[product.id] = product.custom_attributes
// @TODO: Consider scenarios where there is no special price.
.find(({attribute_code}) => attribute_code === 'special_price').value;
return map;
}, {})
}
}
}
angular.module('foo').component('example', {
bindings: {
products: '<'
},
controller: [
ExampleCtrl
],
template: `
<div ng-repeat="product in $ctrl.products track by product.id">
Name: <span ng-bind="product.name"></span>
Price: <span ng-bind="product.price"></span>
Special Price: <span ng-bind="$ctrl.specialProductPrices[product.id]"></span>
</div>
`
})
Using the component like so
<example products="products"></example>
follows AngularJS conventions and optimizes performance by preparing data efficiently.
Utilize it within the loop in the template
If necessary, you can include it directly in the template:
<div ng-repeat="product in $ctrl.products track by product.id">
Name: <span ng-bind="product.name"></span>
Price: <span ng-bind="product.price"></span>
Special Price:
<span>
<span ng-repeat="customAttribute in product.custom_attributes track by customAttribute.attribute_code"
ng-show="customAttributeattribute_code === 'special_price'"
ng-bind="customAttribute.value">
</span>
</span>
</div>
However, this approach may not be efficient as it generates unnecessary DOM elements that will remain hidden (ng-if
cannot be used with repeaters here). It could also become highly inefficient with numerous custom attributes.
Alternative approaches
Consider creating components that handle product.custom_attributes
or developing a filter that extracts the attribute. These methods offer more flexibility but require further implementation.