Formatting data before render it - javascript

I am displaying some data in the view, but I need to formatted first, I was doing something like
val.toFixed(2) and that is OK, it works but the problem is that val sometimes comes with letters, and toFixed(2) is not taking that into account so is not displaying the letters.
So I need something that takes into account letters and numbers, the letters don't have to change, only the numbers which comes like 234235.345345435, and obviously I need it like this 234235.34.
Here is some of the code I am using
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val.toFixed(2)}}</span>
</div>
</td>
</tr>
</table>
and in the controller
$scope.LoadMyJson = function() {
for (var s in myJson){
$scope.data.push(s);
if ($scope.headers.length < 1)
for (var prop in myJson[s]){
prop.data = [];
$scope.headers.push({th:prop, td: []});
}
}
for (var s in $scope.data){
for (var prop in $scope.headers){
var header = $scope.headers[prop].th;
var data = myJson[$scope.data[s]][header];
$scope.headers[prop].td.push(data);
console.log($scope.headers[prop].td);
}
}
};
and I prepared this Fiddle
the way it is right now, is displaying the table properly, but as you see, the table is missing the name, it is because of the toFixed method.
So, what can I do ?

Create a custom filter to use on your template.
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val|formatValue}}</span>
</div>
</td>
</tr>
</table>
angular.module('whatever').filter('formatValue', function () {
return function (value) {
if (isNaN(parseFloat(value))) {
return value;
}
return parseFloat(value).toFixed(2);
}
});

You can try this :
That is a clean way to render formated data in view using angularjs as MVC
frontend framework :
Create a filter in your angular application.
Include your filter in your index.html.
use your filter like this : {{somedata | filterName}}
That is a simple angular filter to solve your problem, hope it will help you :
angular.module('app')
.filter('formatHeader', function() {
return function(data) {
if(angular.isNumber(data)) {
return data.toFixed(2);
}
return data;
}
});
And us it like this :
<table>
<tr>
<th ng-repeat='header in headers'>{{header.th}}</th>
</tr>
<tr>
<td ng-repeat='data in headers'>
<div ng-repeat='inner in data.td'>
<span ng-repeat='(prop, val) in inner'>{{val | formatHeader}}</span>
</div>
</td>
</tr>
You can take a look about these references :
angular functions
filter doc.
angular tutorials

Related

Highlight cell with highest value in ng-repeat with AngularJS 1.4.14

I am working on a dashboard and I'd like some help '_'.
I get a JSON from an API and I get an array of 5 element and each contain this structure (I simplified it but it is close to that).
{
"app_id": "id",
"app_name": "name",
"users_percentiles": {
"users_percentile_1": "3408",
"users_percentile_2": "2356",
"users_percentile_3": "988",
"users_percentile_4": "1099",
}
}
Then, I use a table to organize those elements in my dashboard.
<tbody ng-repeat="dash in dashboard">
<tr>
<td>{{dash.app_id}}</td>
<td>{{dash.app_name}}</td>
<td ng-repeat="percentile in dash.users_percentiles">
{{(percentile}}%
</td>
</tr>
</tbody>
I'd like for each ng-repeat highlight the highest value of percentile (if two are equals, then both should be highlighted).
I think i should add something like :
ng-class="{max : percentile == maxPercentile}"
and a function :
$scope.maxPercentile = -1;
angular.forEach(percentiles, function (percentile) {
if (percentile > $scope.maxPercentile) {
$scope.maxPercentile = percentile;
}
});
But I don't know really where to use this method.
I tried with a $watch but no matter how I tried I didn't get it to work...
<tbody ng-repeat="dash in dashboard">
<tr>
<td>{{dash.app_id}}</td>
<td ng-init = "maxpercentile = getMaxPercentile(dash.users_percentiles)">{{dash.app_name}}</td>
<td ng-class="{max : percentile === maxpercentile}"
ng-repeat="percentile in dash.users_percentiles">
{{percentile}}%
</td>
</tr>
</tbody>
$scope.getMaxPercentile = function(percentiles){
var maxPercentile = -1;
angular.forEach(percentiles, function (percentile) {
if (percentile > $scope.maxPercentile) {
maxPercentile = percentile;
}
});
return maxPercentile;
}

orderBy not working with pagination and filters

<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in foods | filter:foodFilter | itemsPerPage:pageSize | orderBy:'created_at_date'">
<td class="col-md-"> {{food.created_at_date}} </td>
</tbody>
</table>
<dir-pagination-controls
max-size= 7
boundary-links="true">
</dir-pagination-controls>
This is only a snippet of my code but its too large to put up. Everything is working except only some of the created_at_date is in order. When I click on a different filter to add in or remove data depending on that filter, only some of it is entered into the correct place. My main question is: is there someway to sort all of the dates properly while still allowing the everything else function as well? All help is welcome, Thanks
(function () {
"use strict";
App.controller('foodsController', ['$scope'],
function($scope) {
$scope.sortDirection = true;
In your controller you can add the method to order the array before you loop over them.
Assuming your foods array has an array of objects, each with a key of created_at_date and a value:
App.controller('foodsController', function($scope) {
$scope.foods = [{
created_at_date: 6791234
}, {
created_at_date: 9837245
}, {
created_at_date: 1234755
}];
// create a method exposed to the scope for your template.
$scope.orderBy = function(key, array) {
// now you've received the array, you can sort it on the key in question.
var sorted = array.sort(function(a, b) {
return a[key] - b[key];
});
return sorted;
}
});
Now on your template, you have a method available to sort your values for you:
<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in orderBy('created_at_date', foods) | filter:foodFilter | itemsPerPage:pageSize">
<td class="col-md-"> {{food.created_at_date}} </td>
</tr>
</tbody>
</table>
The orderBy method which we've created on your controller returns an array, but it's just sorted by the key that's sent in as the first argument of the function. The second argument is the original array you're trying to sort.
At least this way you can check if you remove all your other filters to see if it's ordered correctly, if then after you add them back in it changes it's because those filters are also changing the order.

How do I do an if with value in mustache.js?

I have the following code:
<script id="tplPLDSemanal" type="text/template">
{{#.}}
<tr>
<td width="20%">{{Peso}}</td>
<td width="20%">{{SECO}}</td>
<td width="20%">{{Sul}}</td>
<td width="20%">{{Nordeste}}</td>
<td width="20%">{{Norte}}</td>
</tr>
{{/.}}
</script>
and I would like to do something like the following, but it does not work
if ({{Peso}} == 2)
<td width="20%">Leve</td>
else if({{Peso}} == 4)
<td width="20%">Media</td>
else
<td width="20%">Pesado</td>
anyone could help me?
Mustache allows you to use functions inside the template, you can add a function to your data and add the logic you want inside the template.
Consider the following template:
<script id="template" type="text/template">
{{#.}}
<tr>
<td width="20%">{{checkPeso}}</td>
<td width="20%">{{SECO}}</td>
<td width="20%">{{Sul}}</td>
<td width="20%">{{Nordeste}}</td>
<td width="20%">{{Norte}}</td>
</tr>
{{/.}}
</script>
<table id="target"></table>
The first variable is checkPeso which is the name of the function we will add to our data.
Consider the following data:
var data = [];
data.push({'SECO': 'val1a', 'Sul': 'val1b', 'Nordeste': 'val1c', 'Norte': 'val1d', 'peso': 0});
data.push({'SECO': 'val2a', 'Sul': 'val2b', 'Nordeste': 'val2c', 'Norte': 'val2d', 'peso': 2});
data.push({'SECO': 'val3a', 'Sul': 'val3b', 'Nordeste': 'val3c', 'Norte': 'val3d', 'peso': 4});
You simply add the function to the data object with the name checkPeso. Inside the function you have access to the data that is being rendered and you can access the data via this.
data.checkPeso = function () {
if (this.peso === 2) return 'Leve';
if (this.peso === 4) return 'Media';
return 'Pesado';
};
Then, you render as usual your Mustache template:
var template = $('#template').html();
Mustache.parse(template); // optional, speeds up future uses
var rendered = Mustache.render(template, data);
$('#target').html(rendered);
See full demo here
Note: As it is correctly stated, Mustache is logic-less but it allows you to use functions and so you can add logic in your template.

Sort table columns with angularjs in non-angular application

Ok, suppose I have a table
<table>
<tr>
<td>Name</td><td>Phone</td>
</tr>
<tr>
<td>John</td><td>2222222</td>
</tr>
<tr>
<td>Mark</td><td>3333333</td>
</tr>
<tr>
<td>Alice</td><td>1999999</td>
</tr>
</table>
That was rendered by non-angularjs app.
All the examples I see on the web suggest that I have a controller and a scope and all the angularjs stuff, but what if I want to deal with existing data?
One time I have this headache I've surrendered and re-wrote everything to be an angularjs app.
There is a major issue with: it's not indexed by the search engines. Or at least not by all of them (I know google is super-smart, but that's only google).
What if I want to use angularjs power and have this existing data? How do I bind those values of the table and make it sortable?
This is interesting and I think it is useful when we want to give old web application power of angularjs.
The following code is nothing more than my idea without careful consideration.
In Html
<div ng-app="myapp" ng-controller="myctrl">
<table>
<tr>
<td><a href ng-click="mgrtable.sort('name')">Name</href></td><td><a href ng-click="mgrtable.sort('phone')">Phone</a></td>
</tr>
<tr ng-init="mgrtable.add_row('John', '2222222')">
<td>{{mgrtable.rows[0].name}}</td><td>{{mgrtable.rows[0].phone}}</td>
</tr>
<tr ng-init="mgrtable.add_row('Mark', '3333333')">
<td>{{mgrtable.rows[1].name}}</td><td>{{mgrtable.rows[1].phone}}</td>
</tr>
<tr ng-init="mgrtable.add_row('Alice', '1999999')">
<td>{{mgrtable.rows[2].name}}</td><td>{{mgrtable.rows[2].phone}}</td>
</tr>
</table>
</div>
In javascript
angular.module('myapp', [])
.factory('ManagerTable', function(){
return function(){
this.rows = [];
var desc = {
name: true, phone: true
}
this.add_row = function(name, phone){
this.rows.push({name: name, phone: phone});
}
this.sort = function(key){
var _desc = desc[key];
desc[key] = !_desc;
this.rows.sort(function(a, b){
var vala = a[key],
valb = b[key];
if (_desc){
return vala > valb ? 1: -1;
}else{
return vala > valb ? -1: 1;
}
});
}
};
})
;
function myctrl($scope, ManagerTable){
$scope.mgrtable = new ManagerTable();
}
Demo jsfiddle is here.
When you want to add some feature about the table data, all you have to do is adding the function of ManagerTable. Although I know html is not clean, I think this way could keep the MVC principle and angular-way.
Please let me know what you think.

knockout observable array is not updating view on removing elements from array

Here is my view model code
var TopicsViewModel = function() {
var self = this;
var fakeTopicData =
[
];
self.createProfile = function () {
alert("came to create profile");
};
self.editProfile = function () {
alert("came to edit profile");
};
self.removeProfile = function (profile) {
alert("came to remove profile");
fakeTopicData.pop();
self.topicsArr(fakeTopicData);
};
var refresh = function() {
self.topicsArr = fakeTopicData;
};
self.topicsArr = ko.observableArray([]);
refresh();
};
ko.applyBindings(new TopicsViewModel());
Here is my html for the view:
<hr />
<hr />
<table class="table table-striped table-bordered table-condensed">
<tr >
<th>Area</th>
<th>Name</th>
<th>Link</th>
<th>Description</th>
<th>Why</th>
</tr>
<tbody data-bind="foreach : topicsArr">
<tr>
<td data-bind="text :area"> </td>
<td class=""><a data-bind="text:name, click:$parent.editProfile"></a></td>
<td data-bind="text:link"> </td>
<td data-bind="text:desc"> </td>
<td data-bind="text:why" ></td>
<td><button class="btn btn-mini btn-danger" data-bind="click:$parent.removeProfile">remove</button></td>
</tr>
</tbody>
</table>
<script src="~/Scripts/Topic.js"></script>
The view initially display all the Topics in my fakeData Array.
On clicking the remove Button, I am trying to remove an element from the array, and expected the view to refresh and not show the removed item any more. However the view still shows all the 3 topics.
Could someone please point to what I might be doing wrong.
I spend a long time researching the other similar queries on stackoverflow, but am still stuck. Thanks so much for any insight into this issue.
You are replacing your observable array called topicsarr with one which isn't observable in your refresh method...
Change
var refresh = function() {
self.topicsArr = fakeTopicData;
};
to
var refresh = function() {
self.topicsArr(fakeTopicData);
};
you have 2 issues in your code.
First, you are setting your observableArray topicsArr with non observableArray or normal array in refresh function. Instead use self.topicsArr(fakeTopicData)
Second, in function removeProfile you are using pop() to remove profile element. From KnockoutJS documentation:
myObservableArray.pop() removes the last value from the array and
returns it
So, it's better to use remove(item) and pass to it your profile element or loop through your array and remove that specific item
myObservableArray.remove(someItem) removes all values that equal
someItem and returns them as an array

Categories

Resources