I have a codepen of some code I am playing with. I want to load the json data through a service and then use ng-repeat to load the arrays.
The problem is that it loads the first array just fine. However, the nested array "data.cities" doesn't show up. In the console, it states that its too much recursion. Here is the link and code below.
Codepen Link
html
<div ng-app="myApp" ng-controller="nameController">
<div class="container">
<div class="row">
<div class="col-md-12">
<div ng-repeat="r in data">
<div>{{ r.region }} - x: {{ r.x}}, y: {{r.y}} ---- {{ r.desc}}</div>
<div ng-repeat="city in data.cities">{{city.name}}</div>
<div>
</div>
</div>
</div>
</div>
</div>
JS
var app = angular.module("myApp", []);
app.controller("nameController", function($scope, mapService) {
$scope.data = mapService.mapData();
});
app.service("mapService", function() {
var mapInfo = [{
region: "America",
desc: "Some info about America",
x: 50,
y: 200,
cities: [{
name: "Chicago",
x: 20,
y: 232
}, {
name: "Los Angeles",
x: 52,
y: 124
}]
}, {
region: "Europe",
desc: "Some info about Europe",
x: 10,
y: 24,
cities: [{
name: "Chicago2",
x: 20,
y: 232
}, {
name: "Los Angeles2",
x: 52,
y: 124
}]
}, {
region: "China",
desc: "Some info about China",
x: 88,
y: 126,
cities: [{
name: "Chicago3",
x: 20,
y: 232
}, {
name: "Los Angeles3",
x: 52,
y: 124
}]
}];
this.mapData = function() {
/*angular.forEach(pics, function(value, key) {
//console.log("key", value.name);
return value.name;
});*/
return mapInfo;
};
});
update only this line
<div ng-repeat="city in r.cities">{{city.name}}</div>
http://jsfiddle.net/L01rjepb/
that's becuse citis is in r not in data
try like this
ng-repeat="city in r.cities"
CODEPEN
<div ng-repeat="city in r.cities">{{city.name}}</div> is what you need.
<div ng-app="myApp" ng-controller="nameController">
<div class="container">
<div class="row">
<div class="col-md-12">
<div ng-repeat="r in data">
<div>{{ r.region }} - x: {{ r.x}}, y: {{r.y}} ---- {{ r.desc}}</div>
<div ng-repeat="city in r.cities">{{city.name}}</div>
<div>
</div>
</div>
</div>
</div>
</div>
Change data.cities (original object)
<div ng-repeat="city in data.cities">{{city.name}}</div>
to r.cities (iterator item)
<div ng-repeat="city in r.cities">{{city.name}}</div>
http://codepen.io/anon/pen/dYWgXd
below sample might help you,
<table>
<tbody ng-repeat="row in rows">
<tr>
<th>{{row.name}}</th>
</tr>
<tr ng-repeat="sub in row.subrows">
<td>{{sub.name}}</td>
</tr>
</tbody>
</table>
Related
This question already has answers here:
Calculating sum of repeated elements in AngularJS ng-repeat
(20 answers)
Closed 5 years ago.
I am trying to do some calculations inside ng-repeat where i want to get the total price out from each nested ng-repeat from the list.
<div class="Container" ng-repeat="items in list">
<div class="top">i am in the top {{items.date}}</div>
<div class="item" ng-repeat="item in items">
<a>{{item.count}}</a>
<a ng-init="setTotals(total = (item.count * item.price))">{{item.price}}</a>
</div>
<div class=bottom">total price: {{totalPrice}}</div>
</div>
this is the angular scope i try to get:
$scope.setTotals = function (total) {
$scope.totalPrice = total * total;
}
but this just doubles the output of a single item, how would i be able to get the total amount of all the items in the nested ng-repeat?
Assuming the list of items is like:
$scope.list = [
{date: '2017-12-14', items: [
{count: 3, price: 9},
{count: 1, price: 20}
]},
{date: '2017-12-15', items: [
{count: 2, price: 10},
{count: 5, price: 20}
]}
];
And that you want to calculate sum of prices per day with function:
$scope.calculateTotal = function (dayItems) {
let total = 0;
for (item of dayItems.items) {
total += (item.count * item.price);
};
return total;
}
The html becomes like:
<div class="Container" ng-repeat="items in list">
<div class="top">i am in the top {{items.date}}</div>
<div class="item" ng-repeat="item in items.items">
<a>{{item.count}}</a>
<a>{{item.price}}</a>
</div>
<div class=bottom">total price: {{calculateTotal(items)}}</div>
</div>
See working demo plunker. Of course you can modify code to fit your needs, it is only a sample implementation.
Add function to controller:
$scope.getTotalPrice = function(items)
{
return items.reduce(function(sum, item)
{
return (sum + (item.count * item.price));
}, 0);
};
call it in html:
<div class="Container" ng-repeat="items in list">
<div class="top">i am in the top {{items.date}}</div>
<div class="item" ng-repeat="item in items">
<a>{{item.count}}</a>
<a>{{item.price}}</a>
</div>
<div class=bottom">total price: {{ getTotalPrice(items) }}</div>
</div>
What you can do here is to do the calculation logic in your controller and just display its result in your view:
JavaScript:
$scope.totalPrice = $scope.items..reduce((sum, item) => {
return (sum + item.count * item.price);
}, 0);
HTML:
<div class="Container" ng-repeat="items in list">
<div class="top">i am in the top {{items.date}}</div>
<div class="item" ng-repeat="item in items">
<a>{{item.count}}</a>
<a>{{item.price}}</a>
</div>
<div class=bottom ">total price: {{totalPrice}}</div>
</div>
I have the following Vue component and data:
Vue.component('receipt', {
template: '#receipt-template',
data: function() {
return {
tip: 8.50
};
},
computed: {
subtotal: function() {
return this.sales.price;
console.log(this.sales.price);
}
},
props: ['header', 'date', 'sales' ]
})
new Vue({
el: '#content',
data: {
sales1: [
{amount: 1, desc: 'A book title', price: 13.99},
{amount: 3, desc: 'An espresso title', price: 5.00},
{amount: 6, desc: 'A drink title', price: 4.25},
{amount: 2, desc: 'A pastrt', price: 3.99}
],
sales2: [
{amount: 1, desc: 'A title', price: 9},
{amount: 2, desc: 'An title', price: 0},
{amount: 3, desc: 'A title', price: 5},
{amount: 4, desc: 'A ', price: 99}
]
}
})
And the following template:
<div class="page page2 current">
<!-- Call our custom receipt vue component -->
<receipt header="Between the Covers & Grinders Café" date="Sept. 23, 2016 10:52 am" :sales="sales1"></receipt>
<receipt header="Between the Covers & Grinders Café" date="Sept. 25, 2016 3:08 pm" :sales="sales2"></receipt>
<div class="clearfix"></div>
</div><!--end page2-->
<template id="receipt-template">
<div class="receipt">
<div class="receipt-header">
<h2>{{ header }}</h2>
</div><!--end receipt-header-->
<div class="receipt-body">
<div class="receipt-labels">
<p>Sales</p>
<p>{{ date }}</p>
<div class="clearfix"></div>
</div><!--end receipt-labels-->
<div class="receipt-sales">
<div class="receipt-sale-row" v-for="sale in sales">
<p>{{ sale.amount }}</p>
<p>{{ sale.desc }}</p>
<p class="sale-price">${{ sale.price }}</p>
</div><!--end receipt-sale-row-->
</div><!--end receipt-sales-->
<div class="receipt-subtotals">
<p>Subtotal</p>
<p>{{ subtotal }}</p>
<p>Tax</p>
<p>$2.64</p>
<div class="clearfix"></div>
</div><!--end subtotals-->
<div class="receipt-totals">
<p>Tip</p>
<p>{{ tip }}</p>
<p>Total</p>
<p></p>
<div class="clearfix"></div>
</div><!--end totals-->
<div class="receipt-card">
<p>Visa 1825</p>
<p>$41.25</p>
<div class="clearfix"></div>
</div><!--end card-->
</div><!--end receipt-body-->
</div><!--end receipt-->
</template>
I can't figure out how to compute the 'subtotal'. What I need to do is have the computed function 'subtotal' return the total of all prices for each 'sales' object. What am I doing wrong?
You need to add up all the price components in this.sales.
subtotal: function() {
let result = 0;
this.sales.forEach((sale) => result += sale.price);
return Math.round(100 * result) / 100;
}
Vue.component('receipt', {
template: '#receipt-template',
data: function() {
return {
tip: 8.50
};
},
computed: {
subtotal: function() {
let result = 0;
this.sales.forEach((sale) => result += sale.price);
return Math.round(100 * result) / 100;
}
},
props: ['header', 'date', 'sales']
});
new Vue({
el: '.page.current',
data: {
sales1: [{
amount: 1,
desc: 'A book title',
price: 13.99
}, {
amount: 3,
desc: 'An espresso title',
price: 5.00
}, {
amount: 6,
desc: 'A drink title',
price: 4.25
}, {
amount: 2,
desc: 'A pastrt',
price: 3.99
}],
sales2: [{
amount: 1,
desc: 'A title',
price: 9
}, {
amount: 2,
desc: 'An title',
price: 0
}, {
amount: 3,
desc: 'A title',
price: 5
}, {
amount: 4,
desc: 'A ',
price: 99
}]
}
});
.receipt-subtotals p,
.receipt-labels p,
.receipt-sale-row p,
.receipt-totals p {
display: inline-block;
margin: 1rem;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div class="page page2 current">
<!-- Call our custom receipt vue component -->
<receipt header="Between the Covers & Grinders Café" date="Sept. 23, 2016 10:52 am" :sales="sales1"></receipt>
<receipt header="Between the Covers & Grinders Café" date="Sept. 25, 2016 3:08 pm" :sales="sales2"></receipt>
<div class="clearfix"></div>
</div>
<!--end page2-->
<template id="receipt-template">
<div class="receipt">
<div class="receipt-header">
<h2>{{ header }}</h2>
</div>
<!--end receipt-header-->
<div class="receipt-body">
<div class="receipt-labels">
<p>Sales</p>
<p>{{ date }}</p>
<div class="clearfix"></div>
</div>
<!--end receipt-labels-->
<div class="receipt-sales">
<div class="receipt-sale-row" v-for="sale in sales">
<p>{{ sale.amount }}</p>
<p>{{ sale.desc }}</p>
<p class="sale-price">${{ sale.price }}</p>
</div>
<!--end receipt-sale-row-->
</div>
<!--end receipt-sales-->
<div class="receipt-subtotals">
<p>Subtotal</p>
<p>${{ subtotal }}</p>
<p>Tax</p>
<p>$2.64</p>
<div class="clearfix"></div>
</div>
<!--end subtotals-->
<div class="receipt-totals">
<p>Tip</p>
<p>{{ tip }}</p>
<p>Total</p>
<p></p>
<div class="clearfix"></div>
</div>
<!--end totals-->
<div class="receipt-card">
<p>Visa 1825</p>
<p>$41.25</p>
<div class="clearfix"></div>
</div>
<!--end card-->
</div>
<!--end receipt-body-->
</div>
<!--end receipt-->
</template>
So I was following a tutorial on code academy on Angular.js. I understood every step and these are the final files which displays a simple game board. My question is: why did we need to go through the trouble of creating a directive called game and linking that to game.html for displaying the content? We already have the $scope given in the ScopeController file. Why couldn't we just go to the index.html file and just display using expressions with ng-repeat like this:
{{scope.visitor_score}}. So couldn't we have just done that all in the index.html file instead of making a directive?
index.html:
<!doctype html>
<html>
<head>
<link href='https://fonts.googleapis.com/css?family=Roboto:400,100,300' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Oswald' rel='stylesheet' type='text/css'>
<link href="https://s3.amazonaws.com/codecademy-content/projects/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<script src="js/vendor/angular.min.js"></script>
</head>
<body ng-app="GameboardApp">
<div class="header">
<h1 class="logo">GameBoard</h1>
</div>
<div class="main" ng-controller="ScoreController">
<div class="container">
<div class="row">
<game info="score" ng-repeat="score in scores"></game>
</div>
</div>
</div>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/ScoreController.js"></script>
<!-- Directives -->
<script src="js/directives/game.js"></script>
</body>
</html>
app.js:
var app = angular.module('GameboardApp',[]);
ScopeController.js
app.controller('ScoreController', ['$scope', function($scope) {
$scope.scores = [
{
datetime: 1420848000000,
visitor_team: {
city: "Charlotte",
name: "Hornets"
},
home_team: {
city: "New York",
name: "Knicks"
},
period: "Final",
visitor_score: 110,
home_score: 82
},
{
datetime: 1420848000000,
visitor_team: {
city: "Dallas",
name: "Mavericks"
},
home_team: {
city: "Los Angeles",
name: "Clippers"
},
period: "Final",
visitor_score: 100,
home_score: 120
},
{
datetime: 1420848000000,
visitor_team: {
city: "Brooklyn",
name: "Nets"
},
home_team: {
city: "Detroit",
name: "Pistons"
},
period: "Third Quarter",
visitor_score: 69,
home_score: 74
},
{
datetime: 1420848000000,
visitor_team: {
city: "Indiana",
name: "Pacers"
},
home_team: {
city: "Philadelphia",
name: "76ers"
},
period: "Third Quarter",
visitor_score: 70,
home_score: 72
},
{
datetime: 1420848000000,
visitor_team: {
city: "San Antonio",
name: "Spurs"
},
home_team: {
city: "Minnesota",
name: "Timberwolves"
},
period: "Halftime",
visitor_score: 58,
home_score: 43
},
{
datetime: 1420848000000,
visitor_team: {
city: "Orlando",
name: "Magic"
},
home_team: {
city: "Portland",
name: "Trail Blazers"
},
period: "First Quarter",
visitor_score: 13,
home_score: 26
}
]
}]);
game.html:
<div class="col-sm-4">
<div class="row scorecard">
<p class="period">{{ info.period }} </p>
<div class="visitor col-xs-4">
<h2 class="visitor-score">{{ info.visitor_score }} </h2>
<h3>
<span class="visitor-city">{{ info.visitor_team.city }} </span><br/>
<span class="visitor-name">{{ info.visitor_team.name }} </span>
</h3>
</div>
<div class="dash col-xs-3">
<h2>-</h2>
</div>
<div class="home col-xs-4">
<h2 class="home-score">{{ info.home_score }} </h2>
<h3>
<span class="home-city">{{ info.home_team.city }} </span><br/>
<span class="home-name">{{ info.home_team.name }} </span>
</h3>
</div>
</div>
</div>
game.js:
app.directive('game',function(){
return{
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'js/directives/game.html'
}
}
);
Yes, you could. But you'd better not.
Clean code is simple and direct. Clean code reads like well-written
prose.
---- Grady Booch, author of Object-Oriented Analysis and Design with Applications
It's the matter of getting your code clean, beautiful and reusable.
Indeed, suppose you will need to show that repeated list on 10 differnt pages. Copypasting these 22 lines would be a very, very, very bad idea.
If you have it only in one place, well, you might want to leave it with ng-repeat, but it's likely you're going to reuse that, so you will have to refactor later anyway.
I think it might be useful for you to read some of Bob Martin's books or check out his videos, thay are awesome.
Cheers!
First off new to Angular here :)
I have a page that shows a list of items from a JSON object. That Json object has an array in it of dates
$obj = [
{
id: '1',
GoalName: 'Smoke Less',
StartDate: '9/1/2015',
EndDate: '9/30/2015',
GoalType: "positive",
Category: "Health",
Weight: "3",
TimesPerWeek: 4,
Dates: {
"09/11/2015": 0,
"09/10/2015": 1,
"09/08/2015": 1
}
}
I got ng-repeat to show off the items the array, but I am struggling to understand how to control the checkboxes. When I present the items I set a date on the screen and I want to check the array to see if that date is present and if it is then check the checkbox. And additionally if the user then clicks the checkbox it updates the item. I vaguely understand that I need to make a model of the checkboxes, but don't fully understand how that works.
app.controller('TrackGoals', function ($scope) {
$scope.today = Date.today();
});
<ul class="list" id="thehabits" ng-repeat="goal in goals">
<li class="expanded-cell">
<div class="pull-right form-group cell-content">
<label>
<input type="checkbox" class="option-input checkbox" ng-model="ids[goal.dates.id].value">
</label>
</div>
<div class="cell-content">
<span id="habittext" class="title">{{ goal.GoalName }} </span>
</div>
</li>
</ul>
Try this:
var app = angular.module('myApp', []);
app.controller('TrackGoals', function($scope) {
$scope.goals = [{
id: '1',
GoalName: 'Smoke Less',
StartDate: '9/1/2015',
EndDate: '9/30/2015',
GoalType: "positive",
Category: "Health",
Weight: "3",
TimesPerWeek: 4,
Dates: {
"09/11/2015": 0,
"09/10/2015": 1,
"09/08/2015": 1
}
}, {
id: '2',
GoalName: 'Smoke Less',
StartDate: '9/1/2015',
EndDate: '9/30/2015',
GoalType: "positive",
Category: "Health",
Weight: "3",
TimesPerWeek: 4,
Dates: {}
}];
$scope.setCheckboxVal = function(val) {
var arr = [];
for (var i in val) {
if (val.hasOwnProperty(i)) {
arr.push({
date: i,
value: val[i]
});
}
}
return !!arr.length;
};
$scope.showData = function() {
console.log(JSON.stringify($scope.goals));
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app='myApp'>
<head>
<meta charset="UTF-8">
<title>Test</title>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="angular.min.js"></script>
</head>
<body ng-controller="TrackGoals">
<ul class="list" id="thehabits" ng-repeat="goal in goals">
<li class="expanded-cell">
<div class="pull-right form-group cell-content">
<label>
<input type="checkbox" class="option-input checkbox" ng-model="goal.checkboxVal" ng-init="goal.checkboxVal=setCheckboxVal(goal.Dates)">
</label>
</div>
<div class="cell-content">
<span id="habittext" class="title">{{ goal.GoalName }} </span>
</div>
</li>
</ul>
<button type="button" ng-click="showData()">Show data</button>
</body>
</html>
I have the following problem, I'm making an application in Visual Studio 2013, and have used Bootstrap 3 for this, I have a Master Page with the libraries and I have the following page that loads the Content of the page.
I'm trying to display graphics in 3 Tabs, however only shows me the graph of the active panel and not load others.
Do not know what else to do, I understand that the problem is related with Bootstrap and can not find documentation of how fix it. If you were using Morris.js could use the Redraw function, however I am using DevExpress Charts
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<script src="Scripts/js/knockout-3.0.0.js"></script>
<script src="Scripts/js/globalize.min.js"></script>
<script src="Scripts/js/dx.chartjs.js"></script>
<div class="container">
<div class="row">
<div class="col-md-5">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Tab Panel<span class="badge pull-right">Area 500</span></h3>
</div>
<div class="panel-body">
<script type="text/javascript">
$(function () {
var dataSource = [
{ country: "Russia", area: 12 },
{ country: "Canada", area: 7 },
{ country: "USA", area: 7 },
{ country: "China", area: 7 },
{ country: "Brazil", area: 6 },
{ country: "Others", area: 55 }
];
$("#chartTab1").dxPieChart({
dataSource: dataSource,
series: [
{
argumentField: "country",
valueField: "area",
label: {
visible: true,
connector: {
visible: true,
width: 1
}
}
}
],
title: "Area of Countries"
});
})
</script>
<script type="text/javascript">
$(function () {
var dataSource = [
{ country: "Russia", area: 12 },
{ country: "Canada", area: 7 },
{ country: "USA", area: 7 },
{ country: "China", area: 7 },
{ country: "Brazil", area: 6 },
{ country: "Others", area: 55 }
];
$("#chartTab2").dxPieChart({
dataSource: dataSource,
series: [
{
argumentField: "country",
valueField: "area",
label: {
visible: true,
connector: {
visible: true,
width: 1
}
}
}
],
title: "Area of Countries"
});
})
</script>
<script type="text/javascript">
$(function () {
var dataSource = [
{ country: "Russia", area: 12 },
{ country: "Canada", area: 7 },
{ country: "USA", area: 7 },
{ country: "China", area: 7 },
{ country: "Brazil", area: 6 },
{ country: "Others", area: 55 }
];
$("#chartTab3").dxPieChart({
dataSource: dataSource,
series: [
{
argumentField: "country",
valueField: "area",
label: {
visible: true,
connector: {
visible: true,
width: 1
}
}
}
],
title: "Area of Countries"
});
})
</script>
<ul class="nav nav-tabs" id="myTab">
<li class="active">Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="Tab1">
<div id="chartTab1"></div>
</div>
<div class="tab-pane" id="Tab2">
<div id="chartTab2"></div>
</div>
<div class="tab-pane" id="Tab3">
<div id="chartTab3"></div>
</div>
</div>
<script>
$('#myTab a').click(function (e) {
e.preventDefault();
$(this).tab('show');
})
</script>
</div>
</div>
</div>
</div>
</div>
</asp:Content>
you are using both the data-api and the programmatic api in your code. remove this script from your code
<script>
$('#myTab a').click(function (e) {
e.preventDefault();
$(this).tab('show');
})
</script>
your data-toggles in your html will take care of your tabs.