Move var friends = [ ] from services.js in 'tabs' template to external JSON file


#1

I have been working with Angular for a little while now and am for the most part learning at faster pace…but, it’s obvious I still need to learn how to walk before I run.

I’ve built a couple Angular sites that utilized $http with ng-repeat to pull data from a locally hosted json file. Getting that to work was painless. So, now I am back to Ionic and would like to build a news app for an association client of mine that works very similar to the ‘tabs’ template, where you click on the name and it changes view and places the name in the title area. The template currently has dummy variable data hard coded into the service, but I need to be able to pull data from an external json file. I’ve tried every which way to get the friends data to pull from a json file but cannot for the life of me figure it out. Right now I am just trying to get it to work before I begin using real data from my client and for the sake that this is the Ionic tab template, it is more familiar to forum members. Thank you so much for taking a look and offering some advice and guidance.

I should be embarrassed to post here what I’ve tried so far, so here it goes - my services.js

angular.module('starter.services', [])

/**
 * A simple example service that returns some data.
 */

    .factory('Friends', function($http) {
      // Might use a resource here that returns a JSON array
    
      // Some fake testing data
      var friends = [];
    		$http.get('assets/data/friends.json').success(function (data) {
    			$scope.listings = data;
    		}).error(function (data) {
    		});
    
    	return {
        all: function() {
          return friends;
        },
        get: function(friendId) {
          // Simple index lookup
          return friends[friendId];
        }
      }
    });

and my json file

{ "friends": 
	[
		{
			"id": 0,
			"name": "Scruff McGruff"
		},
		{
			"id": 1,
			"name": "G.I. Joe"
		},
		{
			"id": 2,
			"name": "Miss Frizzle"
		},
		{
			"id": 3,
			"name": "Ash Ketchum"
		}
	]
}

#2

Hello @rooster

Try to put this code on your factory:

//=================================================
// $http call
//=================================================
.factory('getJSON',['$http',function($http){
	return {
		get: function(){
			return $http.get('http://www.externalsite.com/json.json');
		}
	};
}])

now, in your controller, handle the answer with this code:
note the getJSON service injected in the controller declaration.

//=================================================
// HomeCtrl
//=================================================
.controller('myCtrl', function($scope, getJSON) {
    getJSON.get().then(function (respuesta) {
      $scope.list = respuesta.friends;
    }, function(error){
      alert(error);
    });

})

#3

@Bonda Thanks. I am getting a blank page, probably because of my ng-repeat.

Here is my ng-repeat code. I noticed you use $scope.list = respuesta.friends; Should I include ‘list’ in my repeat somewhere? Thank you again.

<ion-view title="Friends">
  <ion-content>
    <ion-list>
      <ion-item ng-repeat="friend in friends" type="item-text-wrap" href="#/tab/friend/{{friend.id}}">
        {{friend.name}}
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

#4

instead of

$scope.list = respoesta.friends;

do

$scope.friends = respuesta.friends

The ng-repeat is looking for “friends” not list on the scope. Does that make sense?


#5

@bjorn Makes total sense, but I am still getting a blank page with no errors. Thank you for your help.


#6

OK, so I thought it might be something to do with me trying to load it from a project directory, so I loaded it on a server and no I get an alert popup that says "The page at localhost: 8100 says: [object object]

Well at least its an error :slight_smile:


#7

@Bonda and @bjorn I feel like such an idiot that I can’t figure this out. I have not altered the ‘tab’ template, all I want to do is fetch remote json data to replace the hard coded variable data and retain the return code below as this is tied to the detail view and allows me to share the data across multiple views. I have literally spent 2 days on this trying every single combination of code I found from other forums and stackexchange. I am running a local server so its not a CORS issue an the Mozilla console shows the json file loading correctly. Any other ideas before I go completely insane? :slight_smile: Thank you again.

return {
        all: function() {
          return friends;
        },
        get: function(friendId) {
          // Simple index lookup
          return friends[friendId];
        }
      }

#8

If you have any code on codepen or plunkr, even on git, we can help you with better indications.

if what you want is to get the data from the server once and then have it on a service for further local consults between views, you can either save the data from the server (the previous [object,object]) into for example the $rootScope, or save the info into the service like that:

.factory('Friends', function($http) {
  var friends = [];

	return {
    this.fetch: function(){
      $http.get('assets/data/friends.json').success(function (data) {
	friends = data;
        return friends;
      }).error(function (data) {
        alert("something nasty happened");
      });
    },
    all: function() {
      if(friends.length == 0){ this.fetch(); }else{ return friends; }
    },
    get: function(friendId) {
      return friends[friendId];
  }
});

#9

@rooster don’t worry we have all been there. best to place your code on codepen /plunkr/gist. Makes it easier to help you.


#10

@bjorn @Bonda

Here is a Plunker http://plnkr.co/edit/52486EGgWmuRQYJ6URwU - as you can see, this one is a clone of the ‘Tab’ template. Now, what I am trying to do is to replace the var info in the services.js as shown below with $http.get(‘http://www.abcsd.org/friends.json’) , which is the exact same data and still retain the :all and :get functions so I can use data from the json file in the friend-detail.html view. At this point, I almost forgot what I really need this for, but if finally solving the puzzle and learning something new, 2.5 days of life is worth it…I think :slight_smile: Thank you again for sticking with me; you would be surprised how many forums I found that others are trying to do the same thing…

var friends = [
    { id: 0, name: 'Scruff McGruff' },
    { id: 1, name: 'G.I. Joe' },
    { id: 2, name: 'Miss Frizzle' },
    { id: 3, name: 'Ash Ketchum' }
  ];

#11

@rooster Ok, let’s see if the data is actually being returned to your app in the first place.

First thing: When you type in http://www.abcsd.org/friends.json into your browser, does that show the json file?

Second check: Also what you can do to see if you aren’t running into CORS issues (cross domain requests),

  1. launch the chrome developer tools,
  2. go to the network tab, and look for the request where this happens
  3. Check the response tab
  4. Are you getting the data back

#12

@bjorn Yes, I see the contents of the file when I browse the address. In the network tab, I don’t see a response tab, but in network, it shows the file with a 304 status, method GET


#13

Next check. Let’s see if there is actually any js data there.
In your controller, print out to console:

.controller('FriendsCtrl', function($scope, Friends) {
  $scope.friends = Friends.all();
  console.log($scope.friends);
})

Then check in the console tab of dev tools. If you see [object], see if you can expand it and if there is data there.


#14

@bjorn

all I see in console is array [ ] and it is not expandable. Just to be sure, here is my services.js file as it is right now.

.factory('Friends', function($http) {
		var friends = [];
		$http.get('http://www.abcsd.org/friends.json').
			success(function(data, status, headers, config) {
				// this callback will be called asynchronously
				// when the response is available
			}).
			error(function(data, status, headers, config) {
				// called asynchronously if an error occurs
				// or server returns response with an error status.
			});

  return {
    all: function() {
      return friends;
    },
    get: function(friendId) {
      // Simple index lookup
      return friends[friendId];
    }
  }
});

#15

Ah ok.
Two issues I can see.

  1. never assigning friends again
  2. dealing with an asynchrnous callback (http://stackoverflow.com/questions/16286605/initialize-angularjs-service-with-asynchronous-data)

Could you try the following:

Move the $http.get into the all: function:

all: function() {
   $http.get(...).success(function(...){ return data; }).error(function(...){return data;})
}

#16

I made the change with no luck and then changed var friends = [ ]; to var friends = { }; for a test since I noticed this on StackExchange at one time. It didn’t list the JSON data but did give me the object { } in the console. I expanded it and it didn’t show the JSON data but did show a bunch of proto:Object settings… UGH!!


#17

actually, what is the { return data; }) in the above code; is that something I need to add as it not part of my current file per my post above.


#18

Notice on the code of the post 14, that when you call the factory friends, you’re doing a http get, but the result of that get is not stored anywhere. You’ll need to store it in the var friends before returning it.

Also, notice that you’re returning friends in a sync function, but the http function is async.
That means that you’re returning the var friends before finishing the http.

That can be easily tested by putting a console.log(“something”) in the all function of your factory and another inside the success function of your http. You’ll see that the return is called before finishing the http.

Follow the steps in my first post of this thread to solve your issue.

This plunkr have the correct code to work http://plnkr.co/edit/lMwlugVDV6Giz0bnBDEA?p=preview
but won’t work because the server abcsd.org don’t allow ajax calls from the plunkr server


#19

@bonda Thank you, I feel much smarter…and tired from this exercise, but am thankful for your and @bjorn 's help in expanding my knowledge. I noticed from your Plunk that you placed code from above on the friend-detail controller; I placed it in the friendctrl initially which was probably one of my issues.

I re-set it back up and I can see that the view shows 5 slots (same amount of objects in JSON) but no data, so something is working. I changed the path to the JSON file to my local directory but have run into the same results. I know the JSON file is formatted correctly because it loads if I call it directly from the controller, but of course that isn’t what I need, but at least I know the JSON is formatted.

Ok, I placed console.log($scope.friends) inside my FriendsCtrl and this is what orinted out from the console Object { then: qFactory/defer/deferred.promise.then(), catch: qFactory/defer/deferred.promise.catch(), finally: qFactory/defer/deferred.promise.finally(), success: $http/promise.success(), error: $http/promise.error() }

Any clues? Man, this is almost laughable as it seems this should be one of the easier tasks to complete in Angualr (I am talking about myself, not you guys of course) Thank you.