Iterate over JSON in Angular controller - json

This service
angular.module('categoryService', ['ngResource']).
factory('Category', function($resource) {
return $resource('data/categories.json');
});
reads this file:
[{"id":1,"name":"Close Reading","created_at":"2013-09-11T00:19:00.906Z","updated_at":"2013-09-21T13:21:05.123Z","subtitle":"Deliberate, careful reading will improve students’ grasp of every text."},{"id":2,"name":"Choosing Complex Texts","created_at":"2013-09-11T00:20:26.072Z","updated_at":"2013-09-21T13:21:07.698Z","subtitle":"What should your students be reading?"},{"id":3,"name":"Writing \u0026 Language","created_at":"2013-09-11T00:20:31.219Z","updated_at":"2013-09-21T13:21:08.008Z","subtitle":"What are the foundations of good written communication?"},{"id":4,"name":"Vocabulary","created_at":"2013-09-11T00:20:52.209Z","updated_at":"2013-09-21T13:21:08.824Z","subtitle":"Discover ways to expand students’ vocabulary."},{"id":5,"name":"Speaking \u0026 Listening","created_at":"2013-09-11T00:20:59.205Z","updated_at":"2013-09-21T13:21:09.744Z","subtitle":"Improve communication skills in your classroom."},{"id":6,"name":"Media Literacy \u0026 Technology","created_at":"2013-09-11T00:21:04.671Z","updated_at":"2013-09-21T13:21:10.042Z","subtitle":"Explore and apply the latest trends in digital media."},{"id":7,"name":"Differentiation","created_at":"2013-09-11T00:21:09.644Z","updated_at":"2013-09-21T13:21:10.363Z","subtitle":"Different students have different needs."},{"id":8,"name":"Reading Support","created_at":"2013-09-11T00:21:18.683Z","updated_at":"2013-09-21T13:21:10.820Z","subtitle":"Enrich your students’ reading experience."},{"id":9,"name":"Engagement \u0026 Motivation","created_at":"2013-09-11T00:21:35.022Z","updated_at":"2013-09-21T13:21:11.766Z","subtitle":"What makes students thirsty for learning?"},{"id":10,"name":"Performance Task Assessment","created_at":"2013-09-11T00:21:39.589Z","updated_at":"2013-09-21T13:21:12.107Z","subtitle":"Prepare students for the next generation of assessment."}]
and works as expected if I use
<li ng-repeat="category in categories" class="category-nav">
but I can't seem to access the single category inside the controller. I have tried the following:
function CategoryCtrl($scope, Category, $stateParams, _) {
$scope.categories = [];
$scope.categories = Category.query();
/*
$scope.category = _.where($scope.categories, {id: $stateParams.category_id};
or
$scope.categories[$stateParams.category_id];
or
calling eval(), JSON.parse or angular.fromJson on $scope.categories
*/
}
I can't seem to get to the objects inside what looks like an array of objects. How do I get to $scope.categories[i] or similar inside the controller?

Use a callback function, when you fire the query method, it is asynchronized, so you have to do it when you get the response:
function CategoryCtrl($scope, Category, $stateParams, _) {
$scope.categories = [];
$scope.categories = Category.query(function (categories) {
console.log(categories); //here you should see the data
$scope.category = _.where(categories, {id: $stateParams.category_id};
});
console.log($scope.categories); //here you probably won't get the data
}

Try this
angular.module('categoryService', ['ngResource'])
.factory('Category', function($resource) {
var temp = $resource('category.json', {},
{
get: {method:'GET', isArray:true},
});
return temp;
});
Controller :
function CategoryCtrl($scope, Category) {
$scope.categories = [];
Category.get({}, function(response) {
$scope.categories = response;
console.log($scope.categories[0]);
});
}
DEMO

Related

Unable to retrieve JSON array with AngularJS $resource

I've been trying retrieve values from JSON and so far, been unsuccessful. It does get called on the front-end when I refresh the page, but the information is not passing to the next method. I think the issue might be down to the promises.push... line, as I've tried to debug the method underneath and the information is not being passed on at all.
AngularJS:
var promises = [];
promises.push(SpringDataRestService.get({"collection": "subjects"}).$promise);
// Require each of these queries to complete before continuing
$q.all(promises).then(function (data) {
// Grab the first result
$scope.available = data[0].subjects;
$scope.selected = [];
// If this is an update, get the second result in set
if (data.length > 1) {
// For each permission that is assigned to this role, add ID (name) to selected
for (var i = 0; i < data[1].data.subjects.length; i++) {
var perm = data[1].data.subjects[i];
$scope.selected.push(perm.name);
}
}
$scope.tableEditOptions = new NgTableParams({}, {
dataset: $scope.available
});
$scope.available, 'name');
}).catch(function (data) {
// ERROR
});
JSON:
[
{
"name": "FWGWG",
"description": "WGWGWG",
"lockId": 0
},
{
"name": "QFQFQF",
"description": "QFQFQFQ",
"lockId": 0
}
]
I'm confident as well my for loop is wrong due to assigning the values as well, since I don't think it should be data.subjects, but I understand these threads are only 1 issue per question. Any help would be greatly appreicated.
Use the query method for arrays:
var promise = SpringDataRestService.query({"collection": "subjects"}).$promise;
promise.then(function (dataArr) {
console.log(dataArr);
//...
}).catch(function (errorResponse) {
console.log(errorResponse);
});
With the REST services, the get method returns a JavaScript object and the query method returns a JavaScript array.
From the Docs:
$resource Returns
A resource "class" object with methods for the default set of resource actions optionally extended with custom actions. The default set contains these actions:
{
'get': {method: 'GET'},
'save': {method: 'POST'},
'query': {method: 'GET', isArray: true},
'remove': {method: 'DELETE'},
'delete': {method: 'DELETE'}
}
...
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
For more information, see
AngularJS $resource Service API Reference

AngularJS problems with $resource and web servers

I have been testing this code for 2 months, it is the first exercise in my tutorial to learn AngularJS.
The challenge is to count all .json files in a folder and increment it with 1 so that when I save another json file it will always have a higher ID then the previous one. I am having lots of trouble with web servers, first of all NodeJS does not seem to allow JSON posts in its standard configuration. So I have found a modified web-server.js from stockoverflow from a different question:
$resource.save is not functioning
https://github.com/glepretre/angular-seed/commit/9108d8e4bf6f70a5145b836ebeae0db3f29593d7#diff-d169b27b604606d4223bd5d85cad7da1 I have also tried the web-server.js that came with the tutorial:
http://pastebin.com/Ckfh4jvD that seemed to work better. WAMP also did not work I could not get Apache to allow JSON posts.
Problem is the web-server posts the json or sees the json as an object not as an array, even though I have used "isArray: true" and I use .query() instead of .get(). And I have tried many other things like transformResponse: []. I need the array to get .length to work! Also sometimes it GETS an array and POSTS an object which it later reads as object again it is getting really weird.
The code works sometimes as posted or sometimes I need to change :id to :id.json, usually this means the server is retrieving it as an object again which is not what I wan but this differs between the 2 nodeJS servers.
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id', {id: '#id'}, {"getAll": {method: "GET", isArray: true}});
var number = resource.query();
console.log(number);
return {
getEvent: function () {
var deferred = $q.defer();
resource.get({id: 1},
function (event) {
deferred.resolve(event);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
save: function (event) {
var deferred = $q.defer();
event.id = number.length;
resource.save(event,
function (response) {
deferred.resolve(response);
},
function (response) {
deferred.reject(response);
}
);
return deferred.promise;
}
};
}]);
EDIT: This seems to work better however I need to figure out how to put an .then() into this service?
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id.json',
{id: '#id'}, {method: "getTask", q: '*' },
{'query': { method: 'get'}});
var number = resource.query();

Create a collection from inside a collection

I have a collection, which when fetched gets a json and puts into collection:
The JSON format is:
[
{
name: 'Hello',
age: '22',
bio: [{
interest: 'soccer',
music: 'r&B'
}]
}
]
I want to make another collection from bio (without fetching again).
The reason is I want to access both name, age and bio and a parse function can have only one return?
var user = new Backbone.Collection.extend({
url: '/user',
parse: function (response) {
//I want both of this?
//return response;
return response.bio;
}
});
I am passing this collection on success function of fetch into two different views.
//Controller File....
.............
mycollection.fetch({
success: function() {
//Details View wants response
PrimaryLayout.main.show(new detailsView{collection: mycoll});
//Bio View wants response.bio
PrimaryLayout.body.show(new bioView{collection: mycoll});
}
})
What would be the best way to tackle this? Can I clone a collection and just have bio in it?
I've generally solved this by instantiating the sub-collection in parse:
var User = Backbone.Model.extend({
parse: function(json) {
// instantiate the collection
json.bio = new Backbone.Collection(json.bio);
// now person.get('bio') will return a Collection object
return json;
}
});
var Users = Backbone.Collection.extend({
model: User,
// ...
});
I think this is what you are looking for : Backbone Associations. Have a look at the tutorials and examples there.

AngularJS resource return empty json

Part of Code:
From Service part:
$resource('/Serializer/community/V1/latestPost/:start/:end,{
},{
query: {method:'GET',
params:{start:new Date().getTime(), end:1},
isArray:true}
})
From Controller part:
Post['latestPost_timestamp'].query({start: minTime,end:1},function (data) {
alert(JSON.stringify(data));
});
Result:
From console or link open on browser:
[3993,3983,3974,3964,3954,3944,3934,3926,3920,3910]
From controller:
[{},{},{},{},{},{},{},{},{},{}]
Why it return empty {} in controller?
I would like it to be return in [3993,3983,3974,3964,3954,3944,3934,3926,3920,3910] but not
[{},{},{},{},{},{},{},{},{},{}].
Can anyone help? Thanks
That's because a $resource should be an object and not a primitive, like a number in your case. If a resource could be a primitive, then you would have a problem with being able to both do this:
var posts = Post.query({start: minTime,end:1}, function() {
for (var i = 0; i < posts.length; i++) {
var post = posts[i];
// If post here should be equal to for example 3993 in
// your JSON, you wouldn't be able to call any methods
// on it. The following two statements sort if illustrates it:
assert(post === 3993);
post.$save();
}
});
A resource is an object because of this, so you should probably change your server code to return something like [{id: 3993}, {id: 3983}, ...] instead, so that you can access the id by post.id.

Angular JS detailed view with only one json

I'm introducing in Angular with its Tutorial "Phonecat".
Against the tutorial I'd like to build a simple app with a list and detail view with only one json, containing all informations.
The list-view (showing complete content of the json) works fine but I'm struggle with how to set my Angular services for the detail-view.
I am using the XHR method:
Controller.js:
function PlaygroundDetailCtrl($scope, Playground) {
$scope.playgrounds = Playground.query();
}
Services.js
angular.module('playgroundcatServices', ['ngResource']).
factory('Playground', function($resource){
return $resource('playgrounds/playgrounds.json', {}, {
query: {method:'GET', isArray:true}
});
});
playground.json
[
{
"id:" 1,
"properties": "true"
"lat": "51.347789"
"lon": "12.232234"
},
{
"id:" 2,
"properties": "false"
"lat": "51.347789"
"lon": "12.766667"
}
]
I want Angular to display only one entry (id:1) with its properties.
What is the smartest way to do that: showing again all and then filter?
I am stumped.
Use an Angular filter on your view (there's no need to filter the data on the service):
<div ng-repeat="entry in playgrounds | filter:{id: 1}">
<p>properties: {{entry.properties}}</p>
<p>lat: {{entry.lat}}</p>
<p>lon: {{entry.lon}}</p>
</div>
jsfiddle: http://jsfiddle.net/bmleite/Ad6u9/
This worked out quite good:
Controller:
function PlaygroundDetailCtrl($scope, $routeParams, $http) {
$http.get('playgrounds/playgrounds.json').success(function(data){
angular.forEach(data, function(item) {
if (item.id == $routeParams.playgroundId)
$scope.playground = item;
});
});
I've got exactly the same scenario now I think (I'm guessing you're developing with 'mobile' in mind (as I am and want to minimise data transfer) - I'm using one 'master json file', and then on my detail view just filtering that json file (so that the json doesn't have to be reloaded) on the ID value.
This is totally untested but your code from the original question should be modified something like this:
angular.module('playgroundcatServices', ['ngResource'])
.factory('Playground', function($resource){
return $resource('playgrounds/playgrounds.json', {}, {
query: {method:'GET', isArray:true}
});
});
function PlaygroundDetailCtrl($scope, Playground) {
Playground.query(
// params (none in this case)
{},
// Success
function (data) {
$scope.playgrounds = data.filter(function (o) {
return o.id == $routeParams.playgroundId; // assuming you've set this up in your routes definition
})[0];
},
// Error
function (data) {
//error handling goes here
}
);
}
You may want to put something like $scope.isDataLoaded = true; in your 'success' handler as well, and do a watch on that, to use to check to see when the data has finished loading (eg. for in a directive).
I'm not super happy with the [0] in there, but it think the solution is better than a forEach loop myself.