conditional currency sign with angular filter - javascript

$scope.countries = [{name: 'UNITED KINGDOM', id: 1, sign:"£", 'val':2300987 },{name: 'AUSTRIA', id: 2, sign:"€", 'val':6703482 }
// In HTML
<tr ng-repeat="country in countries">
<td class="td-border">{{country.val| currency}}</td>
</tr>
I need angular filter which will take care of currency conditionally as per above object..

From Angular Docs
Filter definition {{ currency_expression | currency : symbol :
fractionSize}}
Simply you could add parameter to filter which would be sign of your currency.
Markup
<tr ng-repeat="country in countries">
<td class="td-border">{{country.val| currency: country.sign}}</td>
</tr>

I believe you need to filter the rows based on currency. You can achieve that by simply updating the code to following
// In HTML
<tr ng-repeat="country in countries | filter : {sign : currency}">
<td class="td-border">{{country.val}}</td>
</tr>

First, if you want the filter to format your currency you will have to pass the country object or the sign and the val to it, otherwise you can't add the sign with the filter.
.filter('currency', [function() {
return function(countryObj) {
return countryObj.val + countryObj.sign;
}
};
}])

The filtering of angular could be bind on the repeater.
Using a separate model to store the current currency is super easy:
$scope.currency = "£";
Filtering on the repeater will be quite easy then:
<tr ng-repeat="country in countries | filter : { sign : currency || ''}">
<td class="td-border">{{country.val}}</td>
</tr>
Working demo: http://jsfiddle.net/CBgcP/692/

Related

How can I populate the dropdown values for each row within a data table?

The following is my HTML.
<tr>
<th>
Test Data
</th>
<th>
Test Data Options
</th>
</tr>
<tr>
<td>
<ng-container>
{{data.testData}}
</ng-container>
</td>
<td class="text-base font-normal">
<ng-container>
<p-dropdown [options]="dropdownOptions" placeholder="Select Test Data"></p-dropdown>
</ng-container>
</td>
</tr>
This is my JSON file.
“data”: [
{
“testData”: “Test Data A”,
“testDataOptions”: [
{
“testDataOptionValue”: “Test Data A1 Option”,
“testDataOptionLabel”: “Test Data A1”
},
{
“testDataOptionValue”: “Test Data A2 Option”,
“testDataOptionLabel”: “Test Data A2”
}
],
},
{
“testData”: “Test Data B”,
“testDataOptions”: [
{
“testDataOptionValue”: “Test Data B1 Option”,
“testDataOptionLabel”: “Test Data B1”
},
{
“testDataOptionValue”: “Test Data B2 Option”,
“testDataOptionLabel”: “Test Data B2”
}
],
}
How could I populate the dropdown values in each row in the data table according to their indexes?
For example
The Test Data A row dropdown values should be:
Test Data A1, Test Data A2
The Test Data B row dropdown values should be:
Test Data B1, Test Data B2
I guess you're missing a *ngFor in the code snippet you sent:
<tr *ngFor="let data of json.data">
<td>{{ data.testData }}</td>
<td>
<p-dropdown [options]="data.testDataOptions" optionLabel="testDataOptionLabel" optionValue="testDataOptionValue"></p-dropdown>
</td>
</tr>
Edit: binding the selected value
A first option, although it might feel hacky depending on context, is to bind to the data object you already have. For instance:
<p-dropdown [options]="data.testDataOptions" optionLabel="testDataOptionLabel" optionValue="testDataOptionValue" [(ngModel)]="data.selectedValue"></p-dropdown>
If that feels weird or you just don't want to mess with that data, then you'll need to store it in a separate variable, which can be an array or a key/value structure. Then you just bind each item to the corresponding entry in the the data structure.
Allan gave you the correct answer, I'm just going to expand it a bit. Since your dropdown options list might be a large one, please consider using trackBy as well. It is not mandatory and it does not always prove much more performant, but overall it should help with performance. You can do it like so:
<tr *ngFor="let data of json.data; trackBy: trackByMethod">
<td>{{ data.testData }}</td>
<td>
<p-dropdown [options]="data.testDataOptions" optionLabel="testDataOptionLabel" optionValue="testDataOptionValue"></p-dropdown>
</td>
</tr>
While in your .ts file (make sure you add some IDs to your items as well - or use other unique identifiers):
trackByMethod = (index: number, item: any): string => item.id;
You can read more about trackBy here: https://dev.to/rfornal/angular-is-trackby-necessary-with-ngfor-594e

Compare value in a key value list in AngularJS and print that value in my view

I have this key, value list in my controller:
$scope.events = [
{eventID: 3200, eventName: "HO BASE PRICE CHG"},
{eventID: 1600, eventName: "DAMAGED M/D TO 0"}
];
and I want to compare my eventID with one value coming
from a web service in a field called EVENT_ID and if there's a match then print the eventName in my html table where it says "{{EVENT NAME ACCORDING TO EVENT ID}}".
The EVENT_ID field is in my ng-repeat.
<tr ng-repeat="d in (exportDataEventDesc.result.slice(0, exportDataEventDesc.result.length-7))">
<td style="text-align: left">{{EVENT NAME ACCORDING TO EVENT ID}}</td>
<td ng-bind = "+ '$' +(d.merchMetrics.SALES_AMOUNT_LW | number : 2)"></td>
<td ng-bind="d.merchMetrics.SALES_LW_CHG_LY + '%'"></td>
<td ng-bind="d.merchMetrics.SALES_L4W_CHG_LY + '%'" ></td>
<td ng-bind="d.merchMetrics.SALES_L13W_CHG_LY + '%'"></td>
<td ng-bind="d.merchMetrics.SALES_L52W_CHG_LY + '%'"></td>
</tr>
Also one more questions, is there something like a "map" in JavaScript?
or which is the best way to achieve what I want, the way I'm doing it is OK? or there's a better one?
WS Response:
Controller:

AngularJS Directive with Filter and Color

I have a list of the simple objects (containing only names) in my model:
var list = [{name: "Jane"}, {name: "Mary"}];
Here I display them:
<table>
<tr data-ng-repeat="pers in list | filter: filter.label >
<td >
{{pers.name }}
</td>
</tr>
</table>
And that's fine.
I also have a filter:
Name: <input type="text" data-ng-model="filter.name" />
What I need to do is to mark the filtered match with some color: for example if you type "A" symbol it should display the search result: Mary, Jane where substring "A" will be red.
I guess I need to use the directives but I don't have much experience with them and I was wondering if somebody could advise how can I achieve this result?
Thanks.
you need to use a filter to extract the matched search terms and replace them with tag with your highlighting style.
<table>
<tr data-ng-repeat="pers in list | filter: filter.label" ng-bind-html="pers.name | highlight:filter.label">
<td >
{{pers.name }}
</td>
</tr>
</table>
your filter would look something like this:
.filter('highlight', function($sce) {
return function(text, phrase) {
if (phrase) text = text.replace(new RegExp('('+phrase+')', 'gi'),
'<span class="highlighted">$1</span>')
return $sce.trustAsHtml(text)
}
checkout this demoand the code

Unbinding ng-repeat scope

I have two <tr>s and an ng-repeat on each, but both perform the same operation on their child elements, like so:
<tr ng-repeat="item in data : filterFunc" ng-if="mode === 'something'">
<td>{{item.name}}</td>
</tr>
<tr ng-repeat="item in data : filterFunc" ng-if="mode === 'somethingelse'">
<td>{{item.name}}</td>
</tr>
Imagine, there are two types of data sets and which one is to be rendered is decided by the mode property at run time. So, either the first <tr> is rendered in the DOM or the other one.
Initially the first <tr> will be rendered and the associated filterFunc function will work properly. There's a simple drop down which has two options, one each for the two modes. If you select the other mode, the second <tr> will be rendered and first one will be removed from the DOM.
The problem is, the filterFunc now is bound to both the <tr>s and operates on both of them.
How do I unbind the scope or watchers for the first one let it be bound only to the second one? or any one of them at any point of time? Here's the fiddle http://jsfiddle.net/6kx4ojL4/
Note: For the sake of simplicity, I have simply returned the passed-in data object as-is in filterFunc. Check the output in browser console. It gets called twice, i.e. for both data sets.
It is not clear what you want to do exactly from your description. My first thought is that you could separate your modes in ng-if, say, use mode1 and mode2, so you can control two <tr>s separately..
Use ng-show instead of ng-if
<tr ng-repeat="item in data : orderBy: 'name'" ng-show="mode === 'something'">
<td>{{item.name}}</td>
</tr>
<tr ng-repeat="item in data : orderBy: 'name'" ng-show="mode === 'somethingelse'">
<td>{{item.name}}</td>
</tr>
How about this. Check this JSFiddle: http://jsfiddle.net/vxcjw45d/1/
If it's not what are you looking for tell me - I will delete it :)
HTML:
<body ng-app="myApp">
<table ng-controller="myController">
<tr ng-repeat="item in data | orderBy: 'name'"
ng-if="mode === 'something'">
<td>{{ item.name }}</td>
</tr>
<tr ng-repeat="item in data | orderBy: 'name'"
ng-if="mode === 'somethingelse'">
<td>{{ item.age }}</td>
</tr>
<tr>
<td>
<button ng-click="changeMode()">
Change Mode
</button>
</td>
</tr>
</table>
</body>
JS:
var myApp = angular.module('myApp', []);
myApp.controller('myController', function($scope) {
$scope.data = [
{ name: 'John', age: 21 },
{ name: 'Doe', age: 33 }
];
$scope.mode = 'something';
$scope.changeMode = function() {
if ($scope.mode === 'something') {
$scope.mode = 'somethingelse';
} else if ($scope.mode === 'somethingelse') {
$scope.mode = 'something'
}
};
});

Conditionally apply filters with ng-repeat

I have an object that contains a mixture of numbers and text for values. I'd like to apply the numbers filter to the object's value when it's a number (obviously). But when it isn't a number, I'd be okay with it just spitting out the string. As is, applying | number to the value formats the numbers, but leaves the string values empty (afterall, they aren't numbers).
I'm guessing it'll have to be a custom filter (which I have yet had a need to make). Is there a way to do it solely within the HTML when doing the ng-repeat?
<table>
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td>{{metricData | number}}</td>
</tr>
</table>
$scope.data = { name:"this is the name",
score:48
outcome:"as expected",
attendance:820,
total:212.34
};
Here is the requested alternate version of the answer from #callmekatootie using ng-if (v1.1.5):
<table>
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td ng-if="isNumber(metricData)">{{metricData | number}}</td>
<td ng-if="!isNumber(metricData)">{{metricData}}</td>
</tr>
</table>
This has the advantage of only running the filter on the elements which are numeric. This is probably of little benefit in this case but may be useful in other more complex filter situations. To answer your other question about the built-in angular.isNumber, #callmekatootie does use that in the scope function isNumber, which is only a wrapper for using the built-in in the view.
Here is a fiddle
You could try it this way - In your controller, you can have a function which identifies if the provided value is a string or a number:
$scope.isNumber = function (value) {
return angular.isNumber(value);
};
Next, in your view you could have the following:
<table>
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td ng-show="isNumber(metricData)">{{metricData | number}}</td>
<td ng-hide="isNumber(metricData)">{{metricData}}</td>
</tr>
</table>
Thus, when the metricData is a number, it is filtered and when it is a string, it is output as it is.
I know this is old, but I think the best solution is to move the logic to a filter.
app.filter("metricDataFilter", function($filter) {
return function(value) {
if(angular.isNumber(value)) {
return $filter("number", value);
}
return value;
}
}
That way the HTML is more concise, and angular won't have to redraw dom elements
<table>
<tr ng-repeat="(metric, metricData) in data">
<td>{{metric}}</td>
<td>{{metricData | metricDataFilter}}</td>
</tr>
</table>

Categories