AngularJS: Service not returning data - angularjs

I have been trying to get data from a json file through service in AngularJS(1.5.3). I am unable to retrieve the data from json and display it in the view. I get blank values instead. Below is the code:
//Service
angularStoreApp.factory('dataService', ['$http', function ($http, $q) {
return {
getProducts: function () {
var promise = $http.get('/api/json/products.json')
.then(function successCallback(response) {
if (typeof response.data === 'object') {
return response.data;
} else {
// invalid response
return "Invalid data";
}
}, function errorCallback(response) {
return "Invalid data";
})
return promise;
}
};
}]);
//Controller
/// <reference path="SearchController.js" />
angularStoreApp.controller('SearchCtrl', ['$scope', 'dataService', function ($scope, dataService) {
$scope.ProductItems = [];
dataService.getProducts()
.then(function (data) {
$scope.ProductItems = data;
});
}]);
<blockquote>
<h4 style="color: salmon">Welcome to the New Store
<br />
Please select the products you want and add them to your shopping cart.
<br />
When you are done, click the shopping cart icon to review your order and checkout.
<br />
</h4>
<div class="row">
<div class="col-sm-12" ng-repeat="ProductItem in ProductItems track by $index">
{{ProductItem.Name}}, {{ProductItem.Price}}
</div>
</div>
Update:
Below is the json data that I have.
[{
"itemName": "Notepad",
"itemPrice": 12,
"itemQuantity": 0
},
{
"itemName": "Pen",
"itemPrice": 8,
"itemQuantity": 0
},
{
"itemName": "Pencil",
"itemPrice": 5,
"itemQuantity": 0
}];
Could anyone help me out.

I think the problem is in your first line!
you should pass all the services as string:
angularStoreApp.factory('dataService', ['$http', '$q' function ($http, $q) {

In order to get the code snippet working, you need to
initialize the module in the js: var angularStoreApp = angular.module('storeapp', []);
add ng-app in the view
add ng-controller in the view (or use routing)
Forgetting to add $q to the dependencies is indeed a mistake, but it doesn't prevent your app from working, as long as you don't use $q.
Below is an adjusted, working code snippet. I simulated the http call by returning json wrapped in a promise. If it still doesn't work, the problem is the HTTP call, i.e. the part I commented out. Execute the call in the browser and verify that the correct JSON is returned.
var angularStoreApp = angular.module('storeapp', []);
//Service
angularStoreApp.factory('dataService', ['$http', '$q',
function($http, $q) {
return {
getProducts: function() {
//simulate promise with json:
return $q.when([{
'Name': 'name 1',
'Price': 1.23
}, {
'Name': 'name 2',
'Price': 4.56
}]);
//var promise = $http.get('/api/json/products.json')
// .then(function successCallback(response) {
// if (typeof response.data === 'object') {
// return response.data;
// } else {
// invalid response
// return "Invalid data";
// }
// }, function errorCallback(response) {
// return "Invalid data";
// })
// return promise;
}
};
}
]);
//Controller
/// <reference path="SearchController.js" />
angularStoreApp.controller('SearchCtrl', ['$scope', 'dataService',
function($scope, dataService) {
$scope.ProductItems = [];
dataService.getProducts()
.then(function(data) {
$scope.ProductItems = data;
});
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="storeapp" ng-controller="SearchCtrl">
<blockquote>
<h4 style="color: salmon">Welcome to the New Store
<br />
Please select the products you want and add them to your shopping cart.
<br />
When you are done, click the shopping cart icon to review your order and checkout.
<br />
</h4>
<div class="row">
<div class="col-sm-12" ng-repeat="ProductItem in ProductItems track by $index">
{{ProductItem.Name}}, {{ProductItem.Price}}
</div>
</div>
</div>

I've replicated your code in jsbin and it is working fine through I've changed the code for brevity.
The issue might be with below code as it looks for products.json in root folder not in your project folder.
$http.get('/api/json/products.json')
Try with removing '/' in the URL.
$http.get('api/json/products.json')

I found the answer after reading the following links
http://www.dwmkerr.com/promises-in-angularjs-the-definitive-guide/
http://bguiz.github.io/js-standards/angularjs/resolving-promises-for-a-controller/
The following is how I modified my code to get it working:
In the config routing section I used the resolve property for that route
var angularStoreApp = angular.module('AngularStore', ['ngRoute']);
angularStoreApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/products', {
templateUrl: '/Views/Store.html',
controller: 'SearchCtrl',
resolve: {
resolvedJSON: function (dataService) {
return dataService.getProducts();
}
}
})
.when('/product/:productName', {
templateUrl: '/Views/product.html',
controller: 'ProductCtrl'
})
.otherwise({
redirectTo: '/products'
});
}]);
Now I injected the resolvedJSON in my controller as follows
/// <reference path="SearchController.js" />
angularStoreApp.controller('SearchCtrl', ['$scope', 'resolvedJSON', function ($scope, resolvedJSON) {
$scope.ProductItems = [];
$scope.ProductItems = resolvedJSON;
}]);
And my service code as follows:
angularStoreApp.factory('dataService', ['$http', function ($http, $q) {
return {
getProducts: function () {
return $http.get('/api/json/products.json')
.then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
return "Invalid data";
})
}
};
following is my json data
[{
"itemName": "Notepad",
"itemPrice": 12,
"itemQuantity": 0
},
{
"itemName": "Pen",
"itemPrice": 8,
"itemQuantity": 0
},
{
"itemName": "Pencil",
"itemPrice": 5,
"itemQuantity": 0
}]
My view(Store.html) is something like this:
<div class="row">
<div class="col-sm-12" ng-repeat="ProductItem in ProductItems track by $index">
{{ProductItem.itemName}}, {{ProductItem.itemPrice}}
</div>
</div>
Hope this helps anyone facing a similar issue as mine. Thank you everyone who steered me to a better and simple answer.

u forgot the '$q' for minification
u should use the var deferred = $q.defer();// (I will add a full code)
example jsfiddle
angular.module('app', [])
.controller('ctrl', function(dataService, $scope) {
var vm = this;
$scope.ProductItems = [];
dataService.getProducts()
.then(function(data) {
$scope.ProductItems = data;
});
})
.factory('dataService', ['$http', '$q', function($http, $q) {
function getProducts() {
var deferred = $q.defer();
$http.get('https://httpbin.org/get')
.then(function successCallback(response) {
if (typeof response.data === 'object') {
// let say we get list of Products
deferred.resolve([{
id: 1,
name: 'Product1'
}, {
id: 2,
name: 'Product2'
}, {
id: 3,
name: 'Product3'
}]);
} else {
// invalid response
return "Invalid data";
}
}, function errorCallback(response) {
return deferred.reject("Invalid data");
})
return deferred.promise;
}
return {
getProducts: getProducts
};
}]);

I think one of the problems you have is already mentioned #Ahmad Mobaraki ,and another one is in your dataService, the promise object returned by $http.get('/api/json/products.json') is already consumed by then() function, so what you need to do is to create a new promise and return it.
Code example:
//service
angularStoreApp.factory('dataService', ['$http', '$q', function ($http, $q) {
return {
getProducts: function () {
var defered = $q.defer();
$http.get('/api/json/products.json')
.then(function successCallback(response) {
if (typeof response.data === 'object') {
defered.resolve(response.data);
} else {
// invalid response
defered.reject("Invalid data");
}
}, function errorCallback(response) {
defered.reject("Invalid data");
});
return defered.promise;
}
};
}]);
//Controller
angularStoreApp.controller('SearchCtrl', ['$scope', 'dataService', function ($scope, dataService) {
$scope.ProductItems = [];
dataService.getProducts()
.then(function (data) {
$scope.ProductItems = data;
});
}]);
hope this can help you :)

Related

Angular not loading data from external json

Not sure what I have wrong here in this setup to simply display books in a json,
I think it might be the view or the controller that may be wrong, but I'm unsure. Thanks for any help.
<div class="book col" ng-repeat="book in myBooks">
<h3 class="title">{{book.title}}</h3>
<p class="author">{{book.author}}</p>
</div>
services.js
app.factory('books', ['$http', function($http) {
return $http.get('books.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
books.json
{
"per_page":20,
"page":1,
"total_pages":1468,
"total_results":29346,
"books":[
{
"uuid":"235b68e4-5b16-4a25-b731-45c7e67c351e",
"id":98024,
"title":null,
"author":null,
"language":null,
"createtime":"2016-05-19T13:09:40.963+00:00"
},
{
"uuid":"5e87daca-e87b-4324-a652-e06d5349bd82",
"id":98055,
"title":null,
"author":null,
"language":null,
"createtime":"2016-05-23T15:50:11.777+00:00"
}
Controller.js
app.controller('BookshelfController', ['$scope', 'books', function($scope, books) {
books.success(function(data) {
$scope.myBooks = data;
});
}]);
Return from your factory an object which contains your function, calling which will return you the result of $http.get()
app.factory('books', ['$http', function($http) {
return {
getBooks: function() {
return $http.get('books.json');
}
};
}]);
Because $http.get returns a Promise object, in your controller use then to get the results from the response.
app.controller('BookshelfController', ['$scope', 'books', function($scope, books) {
books.getBooks().then(function (data) {
$scope.myBooks = data;
}, function (err) {
console.log(err);
});
}]);
Also check your url to be correct.

Angular Js is not working properly

angular js not displaying anything even like simple expressions. i am tying to execute below code but no hope. can anyone help me out.
below code is for view to display.
`<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script type="text/javascript" src="/../../Scripts/angularsample.js"></script>
</head>
<body ng-app="spiceApp">
<div>
<div ng-controller="SpicyController">
<p> lets try some code by using service </p>
<input ng-init="message='Girish'" ng-model="message" />
<button ng-click="notify(message);">Notify{{1+2}}</button>
<p>alert will display only by clicking three times.</p>
</div>
<div ng-controller="List">
<button ng-click="bringList()">getList</button>
<table>
<tr ng-repeat="app in appslist">
<td>
{{app.Name}}
</td>
</tr>
</table>
</div>
</div>
</body>
</html>`
js code
var myApp = angular.module('spiceApp', []);
myApp.controller('SpicyController', ['$scope', '$http', 'userService', , function ($scope, $http, userService) {
//below code is using sservice
$scope.notify = function (msg) {
userService(msg);
};
}]);
myApp.controller('List', ['$scope', 'getList', function ($scope, getList) {
$scope.bringList = function () {
getList.getAppsList().then(function (list) {
$scope.appslist = list;
});
};
}]);
myApp.factory('getList', ['$http',function ($http) {
//this code for getting list from controller.
return getList.getAppsList=function(){
$http({
method: 'GET',
url: 'Home/GetAppsList'
})
.success(function (response) {
return response.data;
}, function (error) {
console.log(error);
});
}
}]);
myApp.factory('userService', ['$window', function (win) {
var msgs = [];
return function (msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join('\n'));
msgs = [];
}
};
}]);`
please tell me where i am wrong. nothing is working. expression is displaying like {{1+2}} in the ouptut.
You have a typo here:
myApp.controller('SpicyController', ['$scope', '$http', 'userService', , function
with the 2 comas so the dependancies are messed up.
i tried in different way with same view but i modified the js file now it's working fine.
var myApp = angular.module('spiceApp', []);
myApp.controller('SpicyController', ['$scope', '$http', 'userService',function ($scope, $http, userService) {
//below code is using sservice
$scope.notify = function (msg) {
userService(msg);
};
}]);
myApp.factory('userService', ['$window', function (win) {
var msgs = [];
return function (msg) {
msgs.push(msg);
if (msgs.length == 3) {
win.alert(msgs.join('\n'));
msgs = [];
}
};
}]);
myApp.controller('List', ['$scope', 'getList', function ($scope, getList) {
$scope.bringList = function () {
getList.getAppsList.then(function (data) {
$scope.appslist = data;
});
};
}]);
var getList = angular.module("spiceApp").factory("getList", ['$http', function ($http, getList) {
return {
getAppsList: (function (response) {
return $http({
method: 'GET',
url: 'GetAppsList'
})
.then(function (response) {
console.log("coming from servicejs", response.data);
//return data when promise resolved
//that would help you to continue promise chain.
return response.data;
});
})()
};
return getList;
}]);

Angular typeahead returning data back from promise , see it in console but not loading into text

I am having issues returning the data to html. Here is my code.
HTML:
<input type="text" ng-model="userEntry" typeahead-template- url="searchResults.html" uib-typeahead="data.EMPLOYEE_NAME for data in search($viewValue)" uib-typeahead-wait-ms="500" />
<script type="text/ng-template" id="searchResults.html">
<div>
<div>
{{match.model.EMPLOYEE_NAME}}
</div>
</div>
</script>
Factory:
App.factory('SearchService', ['$http', '$q', function($http, $q) {
var url = '/api/GetUsers';
var deffered = $q.defer();
var data = [];
var myService = {};
myService.async = function() {
$http.get(url)
.success(function(d) {
data = d;
//console.log(d);
deffered.resolve();
});
return deffered.promise;
};
myService.data = function() {
return data;
};
return myService;
}]);
Controller:
App.controller('SearchUser', ['$scope', 'SearchService', function($scope, SearchService) {
$scope.search = function(val) {
SearchService.async().then(function() {
$scope.data = SearchService.data();
console.log($scope.data);
});
};
}]);
Here is the data coming back:
[{
"EMPLOYEE_ID": "246",
"NETWORK_ID": "onky",
"EMPLOYEE_NAME": "Aaron",
"DIRECTOR_NAME": "Blood",
"VP_NAME": "Sigi"
}, {
"EMPLOYEE_ID": "802",
"NETWORK_ID": "c0",
"EMPLOYEE_NAME": "Georges",
"DIRECTOR_NAME": "Johnson",
"VP_NAME": "Sigi"
}, {
"EMPLOYEE_ID": "124",
"NETWORK_ID": "abr",
"EMPLOYEE_NAME": "MaryamJ.",
"DIRECTOR_NAME": "James",
"VP_NAME": "Sigi"
}]
The use of success is deprecated, you want to change that to use then. You're also returning the promise outside of your success function, so you're returning it too early. It should look more like this:
myService.async = function () {
return $http.get(url)
.then(function (d) {
data = d;
//console.log(d);
deffered.resolve();
return deffered.promise;
});
};

Update template when scope is changed

I have a template in which I output the values (movie titles) from my database,
%div{"ng-repeat" => "movie in movies"}
{{ movie.title }}
And a template in which users can input a movie title,
%div{"ng-controller" => "searchCtrl", :id => "container_search"}
#addMovie{"ng-controller" => "addMovieCtrl"}
%div{"ng-click" => "addMovie()"}
%input{:type => "text", "ng-model" => "title"}
addMovie action.
When a user types in a movie title in the inputfield and clicks the div it gets saved into the database, and when I refresh the page I can see the result. But I want this to happen asynchronously (at the same time, right?).
This is the controller,
angular.module('addMovieseat')
.controller('movieOverviewCtrl', [
'$scope', 'movieService', function($scope, movieService) {
movieService.success(function(data) {
$scope.movies = data;
});
}
]);
And this is the service,
angular.module('addMovieseat')
.factory('movieService', ['$http', function($http) {
return $http.get('movies.json')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}])
.factory('movies', ['$http', function($http){
var o = {
movies: []
};
o.create = function(movie){
return $http.post('/movies.json', movie).success(function(data){
o.movies.push(data);
});
};
return o;
}])
Your service should not do an HTTP request as soon as it's instanciated, and then always return the same result. Instead, it should provide a method that allows getting the movies.
Once that is done, you can simply call the service again right after saving a new movie:
angular.module('addMovieseat')
.factory('movieService', ['$http', function($http) {
return {
loadMovies: function() {
return $http.get('movies.json');
}
};
}])
.factory('movies', ['$http', function($http){
return {
create: function(movie) {
return $http.post('/movies.json', movie);
}
};
}]);
and your controller can now simply do
angular.module('addMovieseat')
.controller('movieOverviewCtrl', [
'$scope', 'movieService', 'movies', function($scope, movieService, movies) {
var init = function() {
movieService.loadMovies().then(function(response) {
$scope.movies = response.data;
});
};
init();
$scope.save = function() {
movies.create({title: $scope.title}).then(init);
};
}]);
Note that you're making your own life more complex than it should by defining two services instead of just one that would have a loadMovies() and a create() functions.

How to pass params to AngularJS factory

I'm fairly new to Angular but am trying to abstract a RESTful call from $http to a factory/resource but I cant seem to pass any params to it. I've read though SO but cannot find an example of this.
My factory code (services.js):
myApp.factory("PropertyDb", function($resource, $log) {
return {
getProperties: function(onSuccess) {
var properties = $resource("http://myurl.com/get_properties.php?", {
callback: 'JSON_CALLBACK',
postcode: 'AA11AA',
minimum_beds: '3',
minimum_price: '97500'
},
{
fetch : {method:'JSONP'},
params: {postcode: 'BB11BB'} // This doesn't override the above or work without the above postcode
});
properties.fetch(
function success(response) {
console.log(response);
onSuccess(response.listing);
},
function error(response) {
console.log(response);
console.log("error");
}
);
},
My Controller code:
myControllers.controller('PropertyListCtrl', ['$scope', 'PropertyDb',
function($scope, PropertyDb) {
$scope.properties = {};
// Adding the postcode below doesnt work...
PropertyDb.getProperties({postcode : 'CC11CC'}, function(responce) {
$scope.properties = responce;
});
}]);
I want to be able to use my factory in my controllers and pass it different params like postcode etc and override the defaults set in the factory. No matter what I try I cannot seem to do this and the docs aren't very easy to follow.
From your example you passed 2 parameters to PropertyDb.getProperties:
postcode Object: {postcode : 'CC11CC'}
callback: function(responce) {$scope.properties = responce;}
The one thing is to use 1st parameter in factory:
myApp.factory("PropertyDb", function($resource, $log) {
return {
getProperties: function(parameter, onSuccess) {
// ^param^ , ^callback^
/* ... */
}
So fixed version of service should be:
myApp.factory("PropertyDb", function($resource, $log) {
return {
getProperties: function(parameter, onSuccess) {
var properties = $resource("http://myurl.com/get_properties.php?", {
callback: 'JSON_CALLBACK',
postcode: parameter.postcode,
minimum_beds: '3',
minimum_price: '97500'
},
{
fetch : {method:'JSONP'},
params: parameter
});
properties.fetch(
function success(response) {
console.log(response);
onSuccess(response.listing);
},
function error(response) {
console.log(response);
console.log("error");
}
);
},
/*...*/
}
});
Try:
myApp.factory("PropertyDb", function($resource, $log) {
return {
getProperties: function(data,onSuccess) { //add 1 more parameter
var properties = $resource("http://myurl.com/get_properties.php?", {
callback: 'JSON_CALLBACK',
postcode: 'AA11AA',
minimum_beds: '3',
minimum_price: '97500'
},
{ //fix your code here
fetch : {
params: data || {postcode: 'BB11BB'},
method:'JSONP'
}
});
properties.fetch(
function success(response) {
console.log(response);
onSuccess(response.listing);
},
function error(response) {
console.log(response);
console.log("error");
}
);
},
But I think a better solution is we only define the $resource once:
myApp.factory("PropertyDb", function($resource, $log) {
//define only once here so we don't need to redefine it whenever we run the method.
var properties = $resource("http://myurl.com/get_properties.php?", {
callback: 'JSON_CALLBACK',
postcode: 'AA11AA',
minimum_beds: '3',
minimum_price: '97500'
},
{ //fix your code here
fetch : {
params: {postcode: 'BB11BB'},
method:'JSONP'
}
});
return {
getProperties: function(data,onSuccess) { //add 1 more parameter
properties.fetch(
data, //send the data.
function success(response) {
console.log(response);
onSuccess(response.listing);
},
function error(response) {
console.log(response);
console.log("error");
}
);
},
I got it, you can use app.factory() as a separate js file to read a file, say get_data.js.
The parameter arg is a file path(now is a web file, you can change it to a relative file path, like js/abc.txt).
var app = angular.module('app', []);
// this part can separate from others as a single file - get_data.js
app.factory('metdata', ['$http', function ($http) {
var load_data = {}; // This is like a new class in factory
load_data.getDataPath = function (arg) { // This is like a method of class
console.log(arg);
load_data.path = arg; // This is like a attribute of class
return $http.get(load_data.path);
};
console.log('print 1 ' + load_data.data);
return load_data; // Call the class, and then call getDataPath function
}]);
app.controller('MainCtrl', ['$scope', 'metdata', function($scope, metdata) {
$scope.loadData = function () {
var dataPath = 'https://raw.githubusercontent.com/OnlyBelter/learnGit/master/readme.txt';
metdata.getDataPath(dataPath).success(function (data) {
console.log(data);
});
};
}]);
<!--this is html file-->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
<body ng-app="app" ng-controller="MainCtrl">
<br>
<div>
<p>Load data:
<button ng-click="loadData()">Load</button>
</p>
</div>
</body>

Resources