This is an interesting question. I'm using a simple JSON Get request to get all the competetions according to date, and show result as a list.
the JSON response is kind of :
[
{
"id":33
"competition":565
},
{
"id":66
"competition":345
}
]
Then I should make another json request to get the name of each json item :
myserver.com/{id}
which look like :
{
"name":"Serie A"
}
I want to show a list of all the names of the competetions I have on the first json request according to date.
here is my angular js code for showing the list of a simple JSON request :
<div ng-controller="customersCtrl">
<ul>
<li ng-repeat="m in matches">
{{ m.id }}
</li>
</ul>
</div>
<script>
var app = angular.module('starter', []);
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://Myserver.com/matches?date=2015-05-19")
.success(function (response) {$scope.matches = response;});
</script>
You can iterate through the matches and get the names with a new call:
app.controller('customersCtrl', function($scope, $http) {
$http.get("http://myserver.com/matches?date=2015-05-19")
.success(function (response) {
$scope.matches = response;
for (var i = 0; i < response.length; i++) {
setName($scope.matches, i);
}
});
var setName = function (matches, index) {
$http.get("http://myserver.com/" + matches[index].id)
.success(function (response) {
matches[index].name = response.name;
});
}
});
Below code will first fetch all the competitions and then using their ids it will fetch names all the events parallely. it will give all the competition with details in one go only.
Warning: If you have large numbers of all competition then it will make same number of calls to get competition details all of them.
app.service('competition', function($http) {
this.getAllCompetitions = function() {
var baseUrl = 'http://Myserver.com';
return $http.get(baseUrl + '/matches?date=2015-05-19')
.then(function(allCompetitions) {
/* sample `data`
[
{
"id":33
"competition":565
},
{
"id":66
"competition":345
}
]
*/
var qArr = [];
allCompetitions.forEach(function(competition, index) {
var promise = $http.get(baseUrl + '/' + competition.id)
.then(function(competitionDetail) {
/* sample `competitionDetail`
{
"name":"Serie A"
"competition":565
}
*/
return {
competitionDetail: competitionDetail,
index: index
};
});
aArr.push(promise);
});
return $q.all(qArr).then(function(listOfData) {
listOfData.forEach(function(item) {
allCompetitions[item.index] = angular.extend(allCompetitions[item.index], item.competitionDetail);
});
return allCompetitions;
});
});
}
});
Related
I'm struggling with trying to figure out what I'm doing wrong, mostly down to not having a good understanding of AngularJS due to being new. The main goal is that I'm trying to list out all the values in the additionalText list out on the front-end, but it seems to be causing issue with this error:
Error: [$http:badreq] Http request configuration url must be a string or a $sce trusted object. Received: []
Context:
I have table in my application that relies on the API, this variable contains a list and outputs the following:
{
"name": "TEST",
"description": "TEST",
"additionalText": [
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
],
"lockId": 0
}
The API is working as expected, I can carry out all the necessary REST calls successfully. So I'm not struggling with that, the front-end is where I am having some difficulty.
HTML:
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList[entity.name]">
<i>{{additionalText.name}}</i><br>
</span>
</td>
AngularJS:
$scope.refreshTextTable= function() {
SpringDataRestService.query(
{
collection: "APIURL"
},
function (response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
},
function (response) {
// TODO: Error Handling
}
);
};
Any help would be greatly appreciated, I'm really struggling with this one.
Can you try this below code:
$scope.refreshTextTable = function() {
SpringDataRestService.query({
collection: "APIURL"
},
function(response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function(additionalTextRole) {
return function(response) {
$scope.additionalTextList = response.additionalText;
};
})(additionalTextRole));
}
},
function(response) {
// TODO: Error Handling
}
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min.js"></script>
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList">
<i>{{additionalText.name}}</i><br>
</span>
</td>
The error message says the url must be a string.
For debugging purposes, console.log the URL:
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
var url = additionalTextRole.additionalText;
console.log(i, url);
$http.get(url).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
Also note that the response object returned by the $http service does not have a property named additionalText. So it is likely that the intention is response.data.additionalText. To avoid the IIFE, use the forEach method:
additionalTextRoles.forEach( role => {
var url = role.additionalText;
console.log(url);
$http.get(url).then((function(response) {
$scope.additionalTextList[role.name] = response.data.additionalText;
});
});
I use the Tab Template, with list of chats and chats detail. I've put the data into a json file, and add it like this in my code : $http.get("http://abcd/Chats.json").
The data are showing on the List of Chats, but it doesn't work on the Detail Page.
I've tested a lot of solution, but I'm still getting an error...
Here is my code:
SERVICE
angular.module('starter.services', [])
.factory('Chats', function($http) {
// Might use a resource here that returns a JSON array
return {
getChats: function() {
return $http.get("http://abcd/Chats.json").success(function(response){
chats=response;
return chats;
});
},
get: function(chatId) {
for (var i = 0; i < chats.length; i++) {
if (chats[i].id === parseInt(chatId)) {
return chats[i];
}
}
return null;
}
};
});
CONTROLLER
.controller('ChatsCtrl', function($scope, Chats) {
Chats.getChats().success(function(response){
$scope.chats =response;
});
})
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
$scope.chat = Chats.get($stateParams.chatId);
} )
My error is: cannot read property of chat undefined..
Any help please?
Try to define chats as a var inside your factory.
.factory('Chats', function($http) {
var chats;
...
I have the following code that has static JSON content (which is working in its current state). Now, I want to call a remote JSON service to get the data instead of static content. I made a fake web service to return the same JSON data: http://appserver.falconinet.com/events.lasso
So here's what I have now. I think I am close...?
angular.module('starter.services', [])
.factory('Events', function ($http) {
var events = [];
return {
all: function () {
return $http.get("http://appserver.falconinet.com/events.lasso");
starter.services.all().then(function successCallback(response) {
$scope.events = data;
})
}
}
return {
all: function () {
return events;
},
remove: function (event) {
events.splice(events.indexOf(event), 1);
},
get: function (eventId) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return null;
}
}
})
And here's my controller:
// events
.controller('EventsCtrl', function ($scope, Events) {
$scope.events = Events.all();
console.log($scope.events);
$scope.remove = function (event) {
Events.remove(event);
}
})
.controller('EventDetailCtrl', function ($scope, $stateParams, Events) {
$scope.event = Events.get($stateParams.eventId);
})
Your factory is perfect, just return events when you removed in order to see the modifications :
appModule.factory('Events', function() {
// Might use a resource here that returns a JSON array
// Some fake testing data
var events = [{
id: 0,
title: 'Swing Dance Party',
subtitle: 'Lets Get Dancing!',
when: 'Thursday, Feb 19, 2015 (6:30-9PM)',
picture: 'http://goldsea.com/Text/images/8198.jpg',
desc: 'Dance, dance, dance and enjoy mixed drinks, wine, or 40 beers on tap. Krista Mccart & Steve Davis will be doing a short 30 minute class for first time beginners at 6:30 and the dance starts at 7:00. The dance and lesson are free!!!'
}, {
id: 1,
title: 'St. Patricks Day Party',
subtitle: 'with Special Guest The Menders',
when: 'Saturday, March 14th (9PM)',
picture: 'img/menders.png',
desc: 'Based out of Gastonia, NC, The Menders have been blending influences such as the Beatles, Jack White, The Doors, and Ryan Adams into a folk-laced garage rock sound. Since 2011, they\'ve been honing their craft around NC at venues such as Double Door Inn, The Visulite, The Milestone, Tremont Music Hall, and Snug Harbor. With an upcoming debut self-titled album, lyrics dealing with the complexities of life and death, 4 part harmonies, and energetic live performances, The Menders seek to offer their fans and listeners a music experience that is sure to leave a lasting impression.'
}];
return {
all: function() {
return events;
},
remove: function(event) {
events.splice(events.indexOf(event), 1);
return events;
},
get: function(eventId) {
for (var i = 0; i < events.length; i++) {
if (events[i].id === parseInt(eventId)) {
return events[i];
}
}
return null;
}
}
})
Now create your controller :
appModule.controller('EventsCtrl', ['$scope', 'Events', function($scope, Event) {
var events = Event.all();
console.log('events', events);
var first_event = Event.get(0);
console.log('first_event', first_event);
$scope.remove = function(event) {
console.log(Events.remove(event));
}
}]);
In your case, you need to define a controller and inside of this, inject the Events factory.
In the «all» method: $http.get("http://appserver.falconinet.com/events.lasso"); will return a promise, so in the controller, you need to implement the .then() function, then you can assign the json response data in the $scope.events array.
Something like this:
(function() {
angular.module("starter.services", [])
// Controller
.controller("EventsCtrl", ["$scope", "Events", function($scope, Events) {
$scope.events = [];
Events.all().then(function(response) {
$scope.events = response.data;
});
$scope.remove = function(event) {
$scope.events.splice(event, 1);
}
}
])
// Factory service
.factory("Events", ["$http", function($http) {
return {
all: function() {
return $http.get("http://appserver.falconinet.com/events.lasso");
}
}
}
]);
})();
<html data-ng-app="starter.services">
<head>
<meta charset="utf-8" />
<title>Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body data-ng-controller="EventsCtrl">
<div>
<ul>
<li data-ng-repeat="event in events">{{event.title}} Remove
</li>
</ul>
</div>
</body>
</html>
You'll want to use angularjs [$http service]1
return {
all: function() {
return $http.get("http://appserver.falconinet.com/events.lasso");
},
[edit]: Also keep in mind that $http requests will be called asynchronously, so if you are injecting this factory into a controller you'll need bind any variables on success. E.g.:
starter.services.all().then(function successCallback(response) {
$scope.variableName = data;
})
[edit]: In response to your suggested edits, you're missing some of the key differences between where you should be setting scope variables (in the controller) and where your factory is calling. To demonstrate, I made a working plunk with what you're trying to accomplish: http://plnkr.co/edit/IlIPXHMkkw6lo08eZVIk?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, Events) {
Events.all().then(function successCallback(response) {
$scope.events = response.data;
});
});
app.factory('Events', function($http) {
return {
all: function() {
return $http.get("http://appserver.falconinet.com/events.lasso");
}
}
});
My goal is to get $http to work on my local filesystem by caching some static JSON objects in a $cacheFactory. I wish to avoid network requests entirely and use only cached content.
The issue is that $http is making server requests regardless of the existence of cached content. My code is as follows.
Cache Factory
myApp.factory('jsonCache', function($cacheFactory){
// create new cache object
// (tried $cacheFactory.get('$http') as well, but same result)
var cache = $cacheFactory('jsonCache');
// put static value in cache
cache.put('/json/file1.json', {"key":"value"});
return cache;
});
Factory using $http
myApp.factory('AjaxFactory', function($http, jsonCache){
console.log(jsonCache.info()); // {id: 'jsonCache', size: 1}
// this will make a request to "http://localhost/json/file1.json"
// even though there is an entry for that URL in the cache object
$http.get('/json/file1.json', {cache: jsonCache}).success(/* ... */);
return { /* ... */ };
});
At this point I'm thinking it may be the format of the data I'm using in cache.put(), but unsure.
Please see demo code below, commends should help you a bit
var app = angular.module('app', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
//
// For any unmatched url, redirect to /state1
$urlRouterProvider.otherwise("/state1");
//
// Now set up the states
$stateProvider.state('state1', {
url: "/state1",
template: "<h1>State1 </h1> <pre>{{cache | json}}</pre>",
controller: 'state1Ctrl'
})
.state('state2', {
url: "/state2",
template: "<h1>State2 </h1><pre>{{cache | json}}</pre>",
controller: 'state2Ctrl'
});
});
app.controller('state1Ctrl', function($scope, myCache) {
var cache = myCache.cache.get('jsonCache');
//check if cached data exist
if (cache) {
//use cached data
$scope.cache = myCache.cache.get('jsonCache');
//if not update cache
} else {
myCache.update().success(function(data) {
//set cache
myCache.cache.put('jsonCache', data.info);
console.log(myCache.cache.info());
//get cached data
$scope.cache = myCache.cache.get('jsonCache');
}).error(function() {
console.log("error");
});
}
});
app.controller('state2Ctrl', function($scope, myCache) {
var cache = myCache.cache.get('jsonCache');
if (cache) {
$scope.cache = myCache.cache.get('jsonCache');
} else {
myCache.update().success(function(data) {
myCache.cache.put('jsonCache', data.info);
console.log(myCache.cache.info());
$scope.cache = myCache.cache.get('jsonCache');
}).error(function() {
console.log("error");
});
}
});
app.factory('myCache', function($cacheFactory, $http) {
// create new cache object
var cache = $cacheFactory('jsonCache');
// put static value in cache
function update() {
alert("update")
return $http.get("https://ws.spotify.com/search/1/track.json?q=kaizers+orchestra");
}
return {
cache: cache,
update: update
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
<script src="
https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
<body ng-app="app">
<div ui-view></div>
<!-- We'll also add some navigation: -->
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
</body>
I was actually able to get it working as desired on this plunk http://plnkr.co/edit/x1nfjwEoJOxzZN5PUyrX?p=preview
angular.module("myApp", [])
.factory('jsonCache', function($cacheFactory) {
// create new cache object
// (tried $cacheFactory.get('$http') as well, but same result)
var cache = $cacheFactory('jsonCache');
// put static value in cache
cache.put('file1.json', {
"key": "From Cache Factory"
});
return cache;
})
.factory('jsonFactory', function($http, jsonCache) {
var get = function(url) {
return $http.get(url, {
cache: jsonCache
});
};
return {
get: get
};
})
.controller("Ctrl", function($scope, jsonFactory, jsonCache) {
$scope.cacheInfo = jsonCache.info();
jsonFactory.get('file1.json').success(function(res) {
$scope.json = res;
});
});
I think the issue with my original code was the result of one of the many 3rd party module dependencies. (doh!)
My workaround for the code as it was, was the following:
myApp.factory('jsonFactory', function($http, $q, jsonCache){
var get = function(url){
var data = jsonCache.get(url);
// if data exists in cache, wrap in promise and return
// or do regular $http get
if(data){
return $q(function(resolve, reject){ resolve(data); });
} else {
return $http.get(url);
}
};
return {
get: get
};
});
I am trying to display nested JSON in a page. I'm not sure how to drill down into it.
In my app js file I have an parameter called initialData that I want to call a function getProducts() when the view is called...
'use strict';
var quoteApp = angular.module('quoteApp', ['ui.router']);
quoteApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'ng-views/choose.html',
controller: "quoteBuilderController",
resolve: {
initialData: ['quoteApi', function (quoteApi) {
return quoteApi.getProducts();
}]
}
})
});
my quoteApi looks like this in case you want to see it...
(function () {
'use strict';
angular.module('quoteApp').factory('quoteApi', quoteApi);
quoteApi.$inject = ['$http'];
function quoteApi($http) {
var service = {
getProducts: getProducts,
getPrices: getPrices
};
var baseUrl = 'http://www.website.com/api/Pricing';
return service;
function getProducts() {
return httpGet('/GetProductCatalogue');
}
function getPrices() {
return httpGet('/GetPrices');
}
/** Private Methods **/
function httpExecute(requestUrl, method, data){
return $http({
url: baseUrl + requestUrl,
method: method,
data: data,
headers: requestConfig.headers }).then(function(response){
return response.data;
});
}
function httpGet(url){
return httpExecute(url, 'GET');
}
}
})();
So quoteApi.getProducts() returns JSON that looks like this...
{
"Cat1": [
{
"product_id": 1,
"product_name": "Prod1"
},
{
"product_id": 2,
"product_name": "Prod2"
}
],
"Cat2": [
{
...
}
]
}
My controller for the view looks like this...
(function () {
'use strict';
angular.module('quoteApp').controller('quoteController', ['$scope', '$http', '$timeout', quoteController]);
quoteController.$inject = ['initialData', 'quoteApi'];
function quoteController($scope, initialData) {
$scope.cat1Products = initialData;
};
})();
So my question is, how can I get 'initialData' to load products from Cat1 only? Should I try to do this from the html? It seems like it should be straight forward enough but I can seem to get it. Thank you.
You need to transform your response from your http request further so you only return the piece you require, and you may also want to consider using the .then() approach:
$http.get('/someUrl').then(function(response) {
//Do something with response.data.Cat1 here
}, function(errResponse) {
console.error('Error while fetching data');
});
Just take out cat1 from your initialData object
function quoteController($scope, initialData) {
$scope.cat1Products = initialData['Cat1'];
};