I'm learning how to use angular and I'm not really that familiar with making request to an api. I'm trying to practice using http://api.football-data.org/index. The json data I wanted to get from my angular factory is http://api.football-data.org/v1/competitions/426/leagueTable. Right now I'm getting an error in the console
'angular.js:13920 TypeError: Cannot read property 'getLeagueData' of undefined at new ...'
My CLI shows that I am loading all my script files and I tested my controller before trying to bring in the factory and creating the getLeagueData function and it was working so I know my issue is after creating the basic controller. I thought it might have to do with my headers needing the authentification token I received but I'm not sure if I haven't added it correctly. Here is my code
HTML
<!DOCTYPE html>
<html lang="en" ng-app='bplApp'>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title><%= title %></title>
<!-- Bootstrap -->
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!--Font Awesome-->
<link rel="stylesheet" href="/bower_components/font-awesome/css/font-awesome.min.css">
<!--Custom-->
<link rel='stylesheet' type='text/css' href='/stylesheets/main.css'>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class='leagueCheck' ng-controller='tableController as table'>
<div class='container'>
<div class='row'>
<div class='col-xs-12'>
{{table.test}}
</div>
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src='/bower_components/angular/angular.min.js'></script>
<!--Module-->
<script src='bplApp.js'></script>
<!--Controller-->
<script src='/controllers/tableController.js'></script>
<!--Service-->
<script src='/services/footballData.js'></script>
Module
var app = angular.module('bplApp',[]);
Controller
app.controller('tableController', ['$scope', 'footballData', function($scope, footballData){
var self = this;
self.test = 'is working';
self.leagueStats = [];
footballData.getLeagueData().then(function(data){
self.leagueStats = data;
console.log(self.leagueStats);
})
}])
Factory
app.factory('footballData', [function($http){
return {
getLeagueData: function(){
return $http({
method: 'GET',
url: 'http://api.football-data.org/v1/competitions/426/leagueTable',
headers:{
'X-Auth-Token': '3e629af30fce46edaa6ead20e007a276'
}
})
}
}
}])
The original ajax code sample that the api shows for using it looks like this
$.ajax({
headers: { 'X-Auth-Token': 'YOUR_API_TOKEN' },
url: 'http://api.football-data.org/v1/fixtures?timeFrame=n1',
dataType: 'json',
type: 'GET',
}).done(function(response) {
// do something with the response, e.g. isolate the id of a linked resource
var regex = /.*?(\d+)$/; // the ? makes the first part non-greedy
var res = regex.exec(response.fixtures[0]._links.awayTeam.href);
var teamId = res[1];
console.log(teamId);
});
You used the array notation at your factory. Either use it directly or declare the $http in the array:
app.factory('footballData', ["$http", function($http){
return {
getLeagueData: function(){
return $http({
method: 'GET',
url: 'http://api.football-data.org/v1/competitions/426/leagueTable',
headers:{
'X-Auth-Token': '3e629af30fce46edaa6ead20e007a276'
}
})
}
}
}])
OR
app.factory('footballData', function($http){
return {
getLeagueData: function(){
return $http({
method: 'GET',
url: 'http://api.football-data.org/v1/competitions/426/leagueTable',
headers:{
'X-Auth-Token': '3e629af30fce46edaa6ead20e007a276'
}
})
}
}
})
Which approach to choose is up to you, there is some docs to assist you on your decision.
Related
I've created a simple one module app in AngularJS. the body is wrapped in a controller and this controller fetch dummy data from jsonplaceholder (an array of users). I also created a component and attached it to the same controller, named <my-comp> and using attr binding I'm trying to pass the object array I receive from the http call, however it throws the following error:
angular.js:15697 Error: [$parse:syntax] http://errors.angularjs.org/1.8.2/$parse/syntax?p0=%7B&p1=invalid%20key&p2=2&p3=%7B%7Busers%7D%7D&p4=%7Busers%7D%7D
Can you help me find where I'm making the mistake?
I'll leave a (not) working snippet.
angular.module('mainApp', [])
.controller("controlador", function($q, $http, $scope) {
$scope.users = [];
$http({
method: 'GET',
url: 'https://jsonplaceholder.typicode.com/users'
}).then(function successCallback(response) {
console.log('response', response.data)
$scope.users = response.data;
}, function errorCallback(response) {
console.log('response', response)
})
})
.component("myComp", {
bindings: { attr1: '=' },
controllerAs: "modelo",
template: '<p ng-repeat="user in attr1">{{user.name}}</p>'
})
<!DOCTYPE html>
<html ng-app="mainApp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>components binding symbols</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.2/angular.min.js" integrity="sha512-7oYXeK0OxTFxndh0erL8FsjGvrl2VMDor6fVqzlLGfwOQQqTbYsGPv4ZZ15QHfSk80doyaM0ZJdvkyDcVO7KFA==" crossorigin="anonymous"></script>
</head>
<body ng-controller="controlador">
<my-comp attr1="{{users}}"></my-comp>
<script src="app.js"></script>
</body>
</html>
Thanks.
{{...}} means evaluating the expression inside it.
To pass a variable, for example in case of your 2 way binding (attr1: '='), you simply need to do attr1="users".
Your snippet where you use the component will then look like this:
<body ng-controller="controlador">
<my-comp attr1="users"></my-comp>
<script src="app.js"></script>
</body>
I am just getting started with AngularJs and I'm making a simple site navigation app that queries an API for values. Currently I'm trying to make an accordion sidebar applet (is that the correct term for a child app of a parent app?) that loads the primary sections, then lists the categories within when the section headers are clicked.
Well I got it to work without throwing an error (yay!) but if I apply the css, then the accordion becomes timid and bashful, only revealing whats inside for less than a second before hiding the contents again. And a lot of times I have to click on the header twice before something happens.
I'm guessing its a problem with Bootstrap because as I mentioned, It's not like that if I remove the css and just have raw html output. Here's my code:
index.html
<!DOCTYPE html>
<html ng-app="navApp" ng-strict-di>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css" />
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="../../assets/js/html5shiv.js"></script>
<script src="../../assets/js/respond.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-resource.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-route.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js" type="text/javascript"></script>
<script src="~/Areas/AngularTest/scripts/app.js"></script>
</head>
<body ng-cloak>
<div ng-controller="menuController">
<div ng-include src="'templates/sidebar.html'"></div>
</div>
</body>
</html>
Using Grunt to combine my js files into one app.js so here are the separate pieces.
scripts/controllers/navController.js
var navApp = angular.module('navApp', [
'ngResource',
'ui.bootstrap',
'ngAnimate'
]);
navApp.controller('menuController', [
'$scope',
'navSectionList',
'navGetCategories',
function ($scope, navSectionList, navGetCategories) {
$scope.navSectionList = navSectionList.query();
$scope.getSectionID = function (event) {
var sectionID = event.currentTarget.attributes["data-id"].value;
$scope.sectionID = sectionID;
$scope.navGetCategories = navGetCategories
.getResource(sectionID)
.query();
};
}
],
function ($scope) {
$scope.oneAtATime = true;
$scope.status = {
isFirstOpen: true,
isFirstDisabled: false
};
}
);
scripts/services/navService.js
navApp.factory('navSectionList', [
'$resource', function ($resource) {
return $resource('/api/navigation/section/list', {}, {
query: { method: 'GET', params: {}, isArray: true }
});
}
]);
navApp.factory('navGetCategories', ['$resource', function ($resource) {
var service = {
getResource: function (sectionID) {
return $resource('/api/navigation/category/' + sectionID, {}, {
query: { method: 'GET', params: {}, isArray: true }
});
}
};
return service;
}]);
templates/sidebar.html
<div class="sidebar">
<uib-accordion close-others="oneAtATime">
<div uib-accordion-group class="panel-default" heading="Products" is-open="status.isFirstOpen" is-disabled="status.isFirstDisabled">
<ul>
<li>New Arrivals</li>
<li>On Sale</li>
</ul>
</div>
<div uib-accordion-group class="panel-default" heading="{{section.name}}" ng-click="getSectionID($event)" ng-repeat="section in navSectionList" data-id="{{section.id}}">
<ul ng-repeat="categories in navGetCategories">
<li ng-show="categories.pid == section.id">
{{categories.name}}
</li>
</ul>
</div>
</uib-accordion>
</div>
I don't really understand AngularJs well enough at this point to figure out what is going on. What do you think I should do to fix this?
Oh God I did it again. So it turns out that you gotta be careful about which version of bootstrap.css you are using. If its one that Angular-UI does not support, you'll get all that funny business going on.
Replacing the css with the following helped fix this problem.
https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css
Version 4 was too advanced for ui.bootstrap.
I'm pretty new with Ionic and AngularJS. I tried to create an app but it seems that the content of app.js is wrong .
This is my code look like :
app.js
angular.module('starter', ['ionic', 'starter.controllers'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state('app', {
url: "/ListeUsers",
views: {
templateUrl: "templates/ListeUsers.html",
controller: 'UsersCtrl'
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/ListeUsers');
});
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ionic/js/angular/angular-resource.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/UserControllerIonic.js"></script>
<script src="js/UsersServiceIonic.js"></script>
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
</body>
</html>
userControllerIonic.js
angular.module('starter.controllers', ['starter.services'])
.controller('UsersCtrl', function($scope,userService) {
$scope.Users=userService.getUsers();
});
UsersServiceIonic.js
angular.module('starter.services', ['ngResource'])
.factory('userService',function () {
var Users =[];
return{
getUsers:function(){
return $http.get("http://localhost:26309/api/User/getAll/").then(function (response) {
users=response;
return users;
});
},
getUser : function(UserName) {
return $http.get("http://localhost:26309/api/User/getUserByNom/" + UserName).then(function (serviceResp) {
return serviceResp.data;
});
}
}
})
ListeUsers.html
<ion-list>
<ion-item ng-repeat="user in Users"
>{{user.nom}}</ion-item>
</ion-list>
i can't find the problem
There are 2 issues you need to fix here for your app to work:
You need to correct he default fallback url from /app/ListeUsers to /ListeUsers because /app/ListeUsers path will be valid if the state was a child-state of app. See more details here: https://github.com/angular-ui/ui-router/wiki/Nested-States-and-Nested-Views
Your service methods are returning promises. You cannot assign a promise to a $scope variable and expect the app to be working. Change your controller code to use the parameter from the .then method callback of the returned promise as below:
angular
.module('starter.controllers', ['starter.services'])
.controller('UsersCtrl', function($scope,userService) {
userService.getUsers()
.then(function (response) {
$scope.Users= response;
});
});
I am having some problems, I appear to be getting the data in the callback but can't seem to get to it, to be honest I'm not entirely sure what is going on.
When I click the "Get Movie" button, I get the following in the console:
Error: response is undefined
app</$scope.addBook#http://onaclovtech.com/apps/movies/:42:1
Wa.prototype.functionCall/<#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:162:14
Mc[c]</<.compile/</</<#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:178:390
zd/this.$get</h.prototype.$eval#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:101:134
zd/this.$get</h.prototype.$apply#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:101:399
Mc[c]</<.compile/</<#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:178:370
Xc/c/<#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:27:145
q#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:7:357
Xc/c#https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js:27:129
When I look at the network tab after the button press I get the following:
http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=[api-key]&q=The%20Way%20Of%20The%20Gun&page_limit=1&callback=angular.callbacks._0
When I look at the debugger I get a movies.json response object that looks like this:
angular.callbacks._0(
{"total":1,"movies":[{"id":"15775","title":"The Way of the Gun","year":2000,"mpaa_rating":"R","runtime":119,"critics_consensus":"","release_dates":{"theater":"2000-09-08","dvd":"2001-06-19"},"ratings":{"critics_rating":"Rotten","critics_score":48,"audience_rating":"Upright","audience_score":71},"synopsis":"","posters":{"thumbnail":"http://content7.flixster.com/movie/11/17/79/11177993_tmb.jpg","profile":"http://content7.flixster.com/movie/11/17/79/11177993_tmb.jpg","detailed":"http://content7.flixster.com/movie/11/17/79/11177993_tmb.jpg","original":"http://content7.flixster.com/movie/11/17/79/11177993_tmb.jpg"},"abridged_cast":[{"name":"Ryan Phillippe","id":"162676004","characters":["Parker"]},{"name":"Benicio Del Toro","id":"162652510","characters":["Longbaugh"]},{"name":"James Caan","id":"162656402","characters":["Joe Sarno"]},{"name":"Juliette Lewis","id":"162654115","characters":["Robin"]},{"name":"Taye Diggs","id":"162655514","characters":["Jeffers"]}],"alternate_ids":{"imdb":"0202677"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/15775.json","alternate":"http://www.rottentomatoes.com/m/way_of_the_gun/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/15775/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/15775/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/15775/similar.json"}}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q=The+Way+Of+The+Gun&page_limit=1&page=1"},"link_template":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q={search-term}&page_limit={results-per-page}&page={page-number}"}
)
So the data all appears to be there, I am just having a hard time figuring out how to get it.
Could someone help point me in the direction of getting the data correctly?
(I do plan to move the angularjs controller to a .js file eventually, but for now it's in the .html file, sorry)
This is my original code:
Index.html
<!DOCTYPE html>
<html ng-app="myapp" manifest="covers.appcache">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.6/angular.min.js"></script>
<script src="https://cdn.firebase.com/js/client/1.0.11/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/0.7.1/angularfire.min.js"></script>
<script src="rottentomatoes.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<style type="text/css">
<!--
/* Move down content because we have a fixed navbar that is 50px tall */
body {
padding-top: 50px;
padding-bottom: 20px;
}
-->
</style>
<!-- Optional theme -->
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
</head>
<body ng-controller="MyController">
<div align="left">
<button type="button" class="btn btn-primary btn-lg active" ng-click="addBook()">Get Movie</button>
</div>
<br />
<div>
{{data}}
{{success}}
<script>
var app = angular.module("myapp", ["video"])
.controller('MyController', ['$scope', '$video', function($scope, $video) {
$scope.addBook = function(e) {
var response = $video.search('[api-key]', 'The Way Of The Gun', '1');
response
.success(function(data, status) {console.log('SUCCESS' + data); $scope.data = data; $scope.status = status;})
.error(function(data, status) {console.log('ERROR' + status); $scope.data = data; $scope.status = status;});
// Found somewhere that said I needed a jsonp_callback function, I just tried it to see if it did anything, doesn't appear to
function jsonp_callback(data) {console.log('JSONP' + data); $scope.data = data; };
}
}]);
app.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
});
</script>
</body>
</html>
rottentomatoes.js
angular.module('video', []).factory('$video', ['$http', function($http) {
return {
search: function(api_key, query, page_limit) {
var method = 'JSONP';
var url = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?";
$http({
method: method,
url: url + "apikey=" + api_key +
"&q=" + query +
"&page_limit=" + page_limit + '&callback=JSON_CALLBACK'
});
}
};
}]);
In the $video.search() method, you return nothing hence the error occurred.
You could just return the $http() call like this and it should work:
angular.module('video', []).factory('$video', ['$http', function($http) {
return {
search: function(api_key, query, page_limit) {
var method = 'JSONP';
var url = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?";
return $http({
method: method,
url: url + "apikey=" + api_key +
"&q=" + query +
"&page_limit=" + page_limit + '&callback=JSON_CALLBACK'
});
}
};
}]);
As general tips:
use an unminified angular.js instead of angular.min.js while debugging, it will give you more meaningful errors.
no need to define the jsonp_callback function, angular will handle that for you
avoid naming your own service with a $ prefix i.e. $video. The $ prefix is preserved for anything that built-in in the angularjs.
I am trying to get data from resource then add it to isolate scope of directive but when i want to print it to screen i get error as undefined current_page here is the script
/**
* Created by yigit on 10.01.2014.
*/
var app = angular.module('kategori', [
'ngResource',
'apiBaseRoute'
]);
app.factory('Data', ['$resource', 'apiBaseRoute', function($resource, config){
return $resource(config.apiBasePath + 'kategori/?page=:page',{page:1},{
query:{
isArray: false,
method: 'GET'
}
});
}]);
app.controller('KategoriListCtrl',['$scope', 'Data', function($scope, Data){
$scope.allData = {data:null};
Data.query({}, function(data){
$scope.kategoriList = {data:data.cat.data};
$scope.allData.data = data.cat;
});
}]);
app.directive('paginate', function(){
return{
scope:{paginatorData: '=paginate'},
link: function(scope){
alert(scope.paginatorData.current_page);
}
}
});
<!DOCTYPE html>
<html ng-app="kategori">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body>
<div class="col-md-6 col-md-offset-3" ng-controller="KategoriListCtrl">
{{allData.current_page}}
<div paginate="allData"></div>
</div>
<script src="js/lib/angular.min.js"></script>
<script src="js/lib/angular-resource.js"></script>
<script src="js/kategori.js"></script>
<script src="js/apiroute.js"></script>
</body>
</html>
I read this article nested scope
But could not solve my problem.
So, the code alerts undefined. How can i solve this?
Can you show your HTML? You'll need to pass the property like this:
<div data-paginate="paginate"></div>