JSON Angular Array pulling data from 3rd Loop - arrays

I am struggling to pull the data from the 3rd loop (Names) in the array below.
Any idea what i am doing wrong?
sample.json
{
"otc": [
{
"name": "Tums",
"language": [
{
"title": "English",
"names": [
{"name": "Tums"},
{"name": "Pepto"}
]
},
{
"title": "China"
},
{
"title": "Germany"
}
,
{
"title": "Mexico"
}
,
{
"title": "India"
}
,
{
"title": "United Kingdom"
}
]
},
{
"name": "Dramamine",
"language": [
{
"title": "title2album1"
},
{
"title": "title2album2"
},
{
"title": "title2album3"
}
]
}
]
}
And this is my index.html
<body ng-app="list">
<div ng-controller="ListCtrl">
<ul>
<li ng-repeat-start="meds in otc">
<strong> {{meds.name}}</strong> //This displays just fine
</li>
<li ng-repeat="lang in meds.language"><em>{{lang.title}}</em></li> //This displays just fine
<li ng-repeat-end ng-repeat="drugs in lang.names">{{drugs.name}}</li> //This doesnt display
</ul>
</div>
<script>
angular.module('list', []);
function ListCtrl($scope, $http) {
$http({method: 'GET', url: 'sample.json'}).success(function(data) {
$scope.otc = [];
angular.forEach(data.otc, function(value, key) {
$scope.otc.push(value);
});
$scope.isVisible = function(name){
return true;
};
});
}
</script>

It looks like your JSON data is a bit incomplete, since you're missing the names key in all of the language objects except for the English one.
Beyond that, your html/angular-view code is a bit off. The ng-repeat's should be nested inside of one-another. This is done by having the opening/closing html tags that contain the ng-repeat directive completely surround the inner <li> tags.
It's a bit hard to tell, but if you want nested lists, you need to add <ul> tags like in my example below.
I believe your index html should look something like:
<ul>
<li ng-repeat="meds in otc">
<strong> {{meds.name}}</strong> //This displays just fine
<ul>
<li ng-repeat="lang in meds.language">
<em>{{lang.title}}</em>
<ul>
<li ng-repeat="drugs in lang.names">{{drugs.name}}</li>
</ul>
</li>
</ul>
</li>
</ul>
The reason why the li ng-repeat tags should be nested is because ng-repeat creates its own isolate scope. Which means that inside of an ng-repeat tag, it only has access to the data made available by the ng-repeat="data in datar" part.
So having:
<li ng-repeat="lang in meds.language"><em>{{lang.title}}</em></li> //This displays just fine
<li ng-repeat="drugs in lang.names">{{drugs.name}}</li> //This doesnt display
as sibling elements, and not the second as a child of the other, the 2nd ng-repeat list does not know what the var lang is. So the drugs in lang.names fails.
Btw, this snippet assumes that the output you want is:
Tums
English
Tums
Pepto
China
Germany
etc
Dramamine
title2album1
title2album2
etc
If you wanted the output as a flat list, you can use the following CSS
ul ul {
padding: 0;
margin: 0;
list-style-type: disc;
}

Related

Access images from local JSON file on the web page in angularjs

Where am i going wrong?
I want to access images from datahl.json file on the web page but unable to access them.Please check the codes and help me.
If possible please refer the solution to plunker editor.
index.html
<div class="col-sm-4" ng-repeat = "hbl in hbls">
<div class="thumbnail" ng-repeat = "h in hbl.data_list"
style="width:100%;">
<img ng-src="{{h.img}}" alt="" style="height:50vh;">
<div class="caption">
<p><strong>{{h.name}}</strong></p>
</div>
</div>
</div>
app.js This is my js codes
var app = angular.module('hostellApp', []);
app.controller('hostellController', function($scope, hblsFactory){
$scope.hbls;
hblsFactory.getHbls().then(function(response){
$scope.hbls = response.data;
});
$scope.sayHello = function(){
console.log("Hello");
}
});
app.factory('hblsFactory', function($http){
function getHbls(){
return $http.get('datahl.json');
}
return {
getHbls: getHbls
}
});
datahl.json This is my local JSON file
`
{
"view_type": 5,
"title": "Hostels By Locality",
"position": 5,
"data_list":
[
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/IMG_20180526_1139570.8091572935412125.jpg",
"name": "Mahavir Nagar"
},
{
"img": "https://graph.facebook.com/1666751513414902/picture?
type=large",
"name": null
},
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/cropped1148015742983667713.jpg",
"name": "New Rajiv Gandhi"
},
{
"img": "https://s3.us-east-2.amazonaws.com/images-city-
teens/cropped998427941.jpg",
"name": "Jawahar Nagar"
}
]
}`
The data you get from your JSON file is not an array but an object. This means that you only need one ng-repeat.
Change your first ng-repeat to ng-repeat="h in hbls.data_list"(added an 's' to hbl) and delete your second ng-repeat.
Working plunker: https://plnkr.co/edit/OOd1M1dNFjSB7uaqZZB6?p=preview

Is there a way to escape dot notation in AngularJS groupBy expression?

I am using this AngularJS filter: https://github.com/a8m/angular-filter#groupby
I have a piece of data (JSON) involving key names containing dots, which seems to be mistaken with nested properties.
Is there a way to prevent the filter from parsing the dot notation or an alternate way to specify the name of the field used for grouping ?
Note: I can't change the way data are build from the server.
My code looks like this :
<div ng-repeat="(key, values) in items | groupBy: 'category_id.name'" >
<div class="item-row">
{{key}}
</div>
<div class="badge-row" ng-repeat="item in values">
{{item.name}}
</div>
</div>
And here is the JSON data I get from the server :
[
{
"id": "1",
"name": "test",
"category_id.name": "Main"
},
{
"id": "2",
"name": "foo",
"category_id.name": "Other category"
},
{
"id": "3",
"name": "bar",
"category_id.name": "Test"
}
]
When running this code, at the moment, I am getting 'undefined' as key value.
Angular Filter uses $parse, so that you can order by fields in nested objects
I have a workaround for this problem. If it helps.
Template:
(key, values) in items | groupBy: rawProperty('category_id.name')
Controller:
$scope.rawProperty = function(key) {
return function(item) {
return item[key];
};
};
JS Bin Demo
Hope it helps.

Filtering Angular templates by JSON property gets Digest infinite loop

I am attempting to filter the results of an ng-repeat in a directive template. The below solution works as in it displays well on the screen, however I now get the error: Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! I referenced this page and the solution did not work: https://docs.angularjs.org/error/$rootScope/infdig
Any suggestions on how I can fix this? Or a better way to go about it?
HTML:
<filtered-set items="businesses | filter : {cat: 'jedi'} : true | filter:query |orderBy: orderList"></filtered-set>
Template:
<div class="bscroll mThumbnailScroller" data-mts-axis="x">
<ul>
<li class="business-card" data-ng-repeat="business in items" data-ng-click="select(business)">
<h2>{{business.name}}</h2>
<p>{{business.cat}}</p>
</li>
</ul>
</div>
Angular JS:
.controller('starWarsCtrl', function ($scope) {
$scope.businesses = [
{"name": "Obi-Wan Kenobi",
"index":88,
"cat": "jedi"},
{"name": "Yoda",
"index":69,
"cat":"jedi"},
{"name": "Lando",
"index":31,
"cat": "smuggler"},
{"name": "Han Solo",
"index":90,
"cat": "smuggler"},
{"name": "Darth Vader",
"index":98,
"cat": "sith"},
{"name": "Jar-Jar Binks",
"index":80,
"cat": "alien"},
{"name": "Mace Windu",
"index":45,
"cat": "jedi"},
{"name": "Chewy",
"index":76,
"cat": "smuggler"}
];
.directive('filteredSet', function() {
return {
restrict: 'E',
scope: {
items: '='
},
templateUrl: 'partials/filtered-set.html'
};
});
There may be a way to solve my above question as-is however I found a much better solution to avoid that problem. Here is what I did instead:
I created this function in my controller, it basically grabs all the JSON properties matching the "cat" property:
angular.forEach($scope.data, function(item) {
//item.cat is a string
if (categories.indexOf(item.cat) == -1) {
categories.push(item.cat);
}
});
return categories;
}
and my HTML, which is essentially a ng-repeat within an ng-repeat:
<div data-ng-app="app" data-ng-controller="starWarsCtrl">
<ul>
<li data-ng-repeat="cat in getCategories()">
<h2>{{cat}}</h2>
<div ng-click="select(i)" ng-repeat="i in data | filter:{cat: cat}">
<p>{{i.name}}</p>
</div>
</li>
</ul>
</div>
I also created a Codepen with my solution: http://codepen.io/Auzy/pen/adeqrP
I hope this helps!

Only show content associated with user

I have a service that does a request,
.factory('movieService', ['$http', function($http) {
return {
loadMovies: function() {
return $http.get('/movies_users.json');
}
};
}])
This is the JSON output and is the result of 2 tables being joined. A user table and a movie table. As you can see the users are associated with 1 or more movies.
[
{"id":1,
"email":"peter#peter.nl",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
},
{
"id":5,
"title":"Star Wars: Episode VII - The Force Awakens",
"movie_id":"140607"
}
]
},
{"id":2,
"email":"jan#jan.com",
"movies":[
{
"id":4,
"title":"Creed",
movie_id":"312221"
}
]
}
]
I then have this function in my controller,
movieService.loadMovies().then(function(response) {
$scope.movies = response.data;
});
This stores the data from the service into the movie scope.
If I do,
"ng-repeat" => "movie in movies"
The ng-repeat shows all the movies added by all the users. How would I only show the movies associated with the current user in a view?
This seems to be what you want - let me know if it helps.
Note that you have an extra " on movie_id" that is certainly not helping
angular.module('myApp', [])
.controller('ctrl', function($scope) {
$scope.users = [
{"id":1,
"email":"peter#peter.nl",
"movies":[
{
"id":4,
"title":"Creed",
movie_id:"312221"
},
{
"id":5,
"title":"Star Wars: Episode VII - The Force Awakens",
"movie_id":"140607"
}
]
},
{"id":2,
"email":"jan#jan.com",
"movies":[
{
"id":4,
"title":"Creed",
movie_id:"312221"
}
]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
<div ng-repeat="user in users">
{{user.email}}
<div ng-repeat="movie in user.movies">
{{movie.title}}
</div>
</div>
<h2>Movies for user 2</h2>
<div ng-repeat="movie in users[1].movies">
{{movie.title}}
</div>
</div>
Found in a quick google search:
How do I filter an array with AngularJS and use a property of the filtered object as the ng-model attribute?
<div ng-repeat="movie in movies | filter {email:'user#email.com'}">
Edit: it looks like you actually have a list of users, so you could do a filter on an ngrepeat on users, then you'd have a nested ngrepeat on movies (unfiltered because they're attached to a user). But depending on how your app actually needs to work you could just filter the data when it comes back and throw out the users you don't need. Which introduces the question, do you have access to the server side code? If so you could filter there and not return data that is associated with a different user in the first place

How to load (n>2)-level nested data from denormalized dataset with Firebase/AngularFire?

Given a denormalized data structure like:
{
"users" : {
"-JMMXslDJkPYmgcwXUzP" : {
"items" : [ "-JMMXYaWlg_ftL2sKsdp", ... ],
"name" : "user0"
},
...
},
"items" : {
"-JMMXYac7EMZcr4LIL5u" : {
"properties" : [ "-JMMWdpWig-L8oIqbeI1", ... ],
"name" : "item0"
},
...
},
"properties" : {
"-JMMWdpe3WEyjnUM12o2" : {"name": "property0"},
...
}
}
I'm currently loading nested children like so:
<ul ng-init="users = $ref('users')">
<li ng-repeat="user in users">
<h1>{{ user.name }}</h1>
<ul>
<li ng-repeat="item_id in user.items" ng-init="item = $ref('items/'+item_id)">
<h2>{{ item.name }}</h2>
<ul>
<li ng-repeat="property_id in item.properties" ng-init="property = $ref('properties/'+property_id)">
<h3>{{ property.name}}</h3>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Here's the plunker showing how unbearably slow loading becomes with only 3-levels-deep-nested data: http://plnkr.co/edit/yrRx2FYJEc5BM1MaSQDe?p=preview
How can I speed up the loading/rendering of this data?
Note that the solution posted here (creating one reference for each collection instead of each collection item) will not work for me, since any/all of my nested collections will be too big.
The problem here is the compiler. Each time any of those records changes, all of those ng-repeat ops are being re-run, and the data is being downloaded again and again. Instead, use a cache of items.
Since I've written an example of a user cache previously, I'll just borrow from that and switch out the variables to match your examples. You'll need to adapt it to work with multiple items belonging to each user; forgive me for that laziness:
The view:
<li ng-repeat="user in users" ng-init="item = items.$load(user.item_id)">
{{user.name}}: {{item.name}}
</li>
And the controller:
// CONTROLLER
app.controller('ctrl', function ($scope, $firebase, itemCache) {
$scope.users = $firebase(fb.child('users'));
$scope.items = itemCache(fb.child('items'));
$scope.$on('$destroy', $scope.items.$dispose);
});
app.factory('itemCache', function ($firebase) {
return function (ref) {
var cachedItems = {};
cachedItems.$load = function (id) {
if( !cachedItems.hasOwnProperty(id) ) {
cachedItems[id] = $firebase(ref.child(id));
}
return cachedItems[id];
};
cachedItems.$dispose = function () {
angular.forEach(cachedItems, function (item) {
item.$off();
});
};
return cachedItems;
}
});

Resources