I'm trying to retrieve some JSON from a URL, but I am getting nowhere. This is for a small football application I'm trying to build (probably for personal use), mainly to get better at using Angular 1, (before using Angular 2).
http://api.football-data.org/code_samples
As you can see, there is not Angular JS example that I can use and I am closely trying to copy the javascript example.
http://api.football-data.org/v1/competitions/424
This is the data that I am trying to display, via the ngResource way. I followed a Udemy Tutorial and if possible, I would like someone to do an example, using this way, please. P.S. API KEY IS FREE (http://api.football-data.org/client/register)! JUST E-MAIL AND YOU WILL GET ONE BACK INSTANTLY!
If someone could help me with this. I would very much appreciate it.
Thanks
HTML
<!DOCTYPE html>
<html lang="en-gb" ng-app="quickEleven">
<head>
<title>AngularJS Football Stats</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta charset="UTF-8">
<!-- load bootstrap and fontawesome via CDN -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<style>
html, body, input, select, textarea
{
font-size: 1.05em !important;
}
</style>
<!-- load angular via CDN -->
<script src="//code.angularjs.org/1.3.0-rc.2/angular.min.js"></script>
<script src="//code.angularjs.org/1.3.0-rc.2/angular-route.min.js"></script>
<script src="//code.angularjs.org/1.3.0-rc.2/angular-resource.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<header>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">AngularJS Football</a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><i class="fa fa-home"></i> Home</li>
</ul>
</div>
</nav>
</header>
<div class="container">
<div ng-controller="homeController"></div>
</div>
</body>
</html>
JS
// MODULE
var quickEleven = angular.module('quickEleven', ['ngRoute', 'ngResource']);
// CONTROLLERS
quickEleven.controller('homeController', ['$scope', '$resource', 'cityService', function($scope, $resource, cityService) {
$scope.footballAPI =
$resource("http://api.football-data.org/v1/competitions/424", {headers: {"X-Auth-Token": "<API TOKEN KEY>"}}, { get: { method: "JSONP"}
});
$scope.fussball = $scope.footballAPI.get({});
console.log($scope.fussball);
}]);
Take a time to read about $resource , you did some error, like setting header.
USAGE:
$resource(url, [paramDefaults], [actions], options);
paramDefaults: Default values for url parameters.
So with your defined resouces, the token wont go to header but as parameter, and API will return a 404. You should set headers for every method:
And you don't need to use jsonp, get will work
eg:
$resource("http://api.football-data.org/v1/competitions/:competitionId", {}, {
get: {
method: "GET",
headers: {
"X-Auth-Token": "<API TOKEN KEY>"
}
}
});
For calling the method:
"class" actions without a body: Resource.action([parameters],
[success], [error]) "class" actions with a body:
Resource.action([parameters], postData, [success], [error])
So calling get for competition id 424 is:
$scope.footballAPI.get({
competitionId: 424
}, function(data) {
$scope.fussball = data;
}, function(err) {
console.log('error:', err);
});
Related
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.
Why can't my Angular directive be fetched even if I provided the correct url - getting a $compile error and XMLHttpRequest cannot load error?
I started with an angular app and I can't include a directive as I keep getting 2 different errors.
XMLHttpRequest cannot load / Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
I have researched a bit and there were suggestions to set up a server t avoid that which I don't understand. Why can't I just build the app only using angular/html without a backend if I don't really need it. What could cause that error?
Error: $compile:upload
That apparently happens when the URL of the template is spelled incorrectly- however, I provide the entire path from the root ( templateUrl:
'js/navbar/navbar.html') or is that wrong?
Thank you.
project1/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<title>page</title>
<link rel="stylesheet" type="text/css" href="public/css/style.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/css/materialize.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/js/materialize.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-materialize/0.2.1/angular-materialize.min.js"></script>
<script src="js/app.js"></script>
<script src="js/navbar/navbar.js"></script>
</head>
<body ng-app="myApp">
<header></header>
<navbar></navbar>
<ui-view></ui-view>
</body>
</html>
project1/js/app.js
'use strict';
var app=angular.module('myApp', ['ui.router', 'ui.materialize']);
project1/js/navbar/navbar.js
'use strict';
app.directive('navbar', function () {
return {
restrict: 'E',
templateUrl: 'js/navbar/navbar.html'
}
});
project1/js/navbar/navbar.html
<div class="navbar navbar-static-top navbar-inverse">
<div class="container">
<ul class="nav navbar-nav">
<li>
Hello
</li>
</ul>
</div>
</div>
Always use server to run your angular app or you might get cross origin error. The server will helps you to resove your file paths.Then edit your directive to be
'use strict';
app.directive('navbar', function () {
return {
restrict: 'E',
templateUrl: 'navbar.html'
}
});
I did a little plunker so we are sure your code is free of error.
I am not sure about using the absolute path but if you are going to use it then you have to type something like: "C:projects/project1/js/navbar/navbar.js"
you could use http-server it's easy to install and use.
I hope that answer your question
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.
I am building an application in which I am using MongoDB, ExpressJS, AngularJS, and NodeJS. When the user clicks on certain categories, it sends a GET request to my database, and I know it is working because it returns the results to the console. However, now I am trying to build the front end of the application using angular, but I am stuck trying to figure out how to use controllers and front end routes to 'catch' the returned data from database. Here is my code so far, and any thoughts or pointing in the right direction will be much appreciated!
server.js:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var mongoose = require('mongoose');
require('./app/models/modelMaterials')
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
app.use(bodyParser.urlencoded({extended: true}))
app.use(express.static(__dirname + '/'));
app.get('/', (req, res) => {
res.sendFile(process.cwd() + "/public/index.html");
});
// routes
app.get('/granite', (req, res) => {
db.collection('materials').find({"material_category_id": "35"}).toArray(function(err, results) {
res.json(results);
});
res.redirect('/');
return;
});
index.html:
<!DOCTYPE html>
<html ng-app="marbleApp">
<head>
<title>AngularMongo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<!--Import materialize.css-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/css/materialize.min.css" media="screen,projection"/>
<link rel="stylesheet" href="../public/css/style.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.3/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.18/angular-ui-router.js"></script>
<script src="./controllers/searchController.js"></script>
<script src="./controllers/repeatController.js"></script>
<script src="./app/models/modelMaterials.js"></script>
<script src="/server.js"></script>
<script src="./public/js/index.js"></script>
</head>
<body ng-controller='SearchCtrl'>
<!-- Category navbar; ngRepeat -->
<div class="navbar">
<nav>
<div class="nav-wrapper" id="gray">
<ul class="hide-on-med-and-down" id="category-center">
<li ng-repeat="category in categories">{{category.name}}</li>
</ul>
</div>
</nav>
</div>
<!-- Main search bar -->
<nav style="background-color: #d56324!important">
<div class="nav-wrapper">
<form action="{{ search }}" method="GET">
<div class="input-field">
<input id="search" type="search" required placeholder="Search" ng-model="search">
<label for="search"><i class="material-icons">search</i></label>
<i class="material-icons">close</i>
</div>
</form>
</div>
</nav>
<br>
<!-- Material results from category search; ngRepeat -->
<div class="container" ng-controller="MainCtrl">
<div class="row">
<div class="col m3" ng-repeat="material in materials">
<a href="/cosmicblack"><div class="card">
<div class="card-image small">
<img src="">
</div>
<div class="card-content">
<h5>{{ material.material_name }}</h5>
</div>
</div>
</a>
</div>
</div>
</div>
<!--Import jQuery before materialize.js-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>
</body>
</html>
model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var materialSchema = new Schema({
id: {
type: Number
},
material_category_id: {
type: Number
},
material_name: String,
material_original_name: String,
material_other_names: String,
material_description: String,
material_online_id: String,
material_country_of_origin: {
type: String
},
main_color: {
type: String
},
page_title: String,
pattern: {
type: String
},
last_update: {
type: Date,
default: Date.now
}
});
var Material = mongoose.model('Material', materialSchema);
module.exports = Material;
controller:
var app = angular.module("marbleApp", []);
app.controller('MainCtrl', function($scope, $http) {
$http.get('/granite', function(response) {
}).then(function(data) {
res.json(data);
$scope.materials = data;
});
});
There's a couple of differences between how Angular's $http works compared to Express.
$http.get takes two parameters, a url and an optional config object. You've passed in a function as the config, which probably does nothing.
$http uses Promises while your Express code is using callbacks. One of the differences is that Promise.then doesn't return an error and a response in the same function, instead you need to do Promise.then(successCallback, errorCallback) or Promise.then(successCallback).catch(errorCallback). You don't need to add an errorCallback but if you leave it out then there's no way to know that an error has happened because Promises catch all errors.
res.json does not exist in the context of a Promise because that was passed into your server side callbacks by Express. So that's actually throwing an error but you didn't see because it's inside a Promise. Client side you have to use JSON.parse instead, however $http will already parse JSON responses automatically anyway.
So your client side code should look something like this:
$http.get('/granite')
.then(function(response) {
$scope.materials = response.data;
})
.catch(/*
Handle a failed request, or any errors
thrown inside of a Promise callback.
*/);
The Angular documentation on $http has a lot more examples than this. Most client side code uses Promises rather than callbacks, so you should also read up on them here. Angular uses its own Promise library but it's almost functionally identical to the native JavaScript ones.
var routerApp = angular.module('routerApp', ['ui.router','ngResource']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// HOME STATES AND NESTED VIEWS
.state('partyDetail', {
url: '/party/:partyID',
templateUrl: 'hello.html',
controller: function($scope, $stateParams, UserFactory) {
$scope.id = $stateParams.partyID;
console.log($stateParams.partyID);
UserFactory.get({}, function (userFactory){
$scope.userdata = userFactory.user;
});
}
});
});
routerApp.controller('chappy',[function(){
var thisOne=this;
thisOne.note=[
{id:1,Name:'emp.json',Status:false},
{id:2,Name:'1',Status:true},
{id:3, Name:'2',Status:false}
];
console.log("I'm in controller");
}]);
routerApp.factory('UserFactory', function ($resource,$stateParams) {
console.log($stateParams.partyID);
return $resource(':Id',{Id: $stateParams.partyID }, {
query: {
method: 'GET',
params: {},
isArray: true
}
})
});
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<!-- CSS (load bootstrap) -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- JS (load angular, ui-router, and our custom js file) -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js" ></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular-resource.js"></script>
<script src="app.js"></script>
</head>
<!-- apply our angular app to our site -->
<body ng-app="routerApp">
<!-- NAVIGATION -->
<nav class="navbar navbar-inverse" role="navigation" ng-controller="chappy as chappu">
<ul class="nav navbar-nav" ng-repeat="result in chappu.note">
<li><a ui-sref="partyDetail({ partyID: result.Name })" ><span ng-bind="result.Name"></span></a></li>
</ul>
</nav>
<!-- MAIN CONTENT -->
<div class="container">
<!-- THIS IS WHERE WE WILL INJECT OUR CONTENT ============================== -->
<div ui-view></div>
</div>
</body>
</html>
<!--partial html which is needed to be included in the ui-view-->
<!--hello.html-->
<div>
<p > what were you saying <span ng-bind="id"></span></p>
<p ng-repeat="result in userdata">
<span ng-bind="result.subject"></span>
</p>
</div>
I have created Here a DemoApp in which I have dynamically Created The URi according to the data coming from the different Controller
The Programs seems to work fine at the first glance but it has a problem that the $stateparams even After changes but in the URi it remains the same
The issue here is that maybe my not services is getting called again
but I am not been able to encounter this bug
var routerApp = angular.module('routerApp', ['ui.router','ngResource']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// HOME STATES AND NESTED VIEWS
.state('partyDetail', {
url: '/party/:partyID',
The Console output clearly indicates that the Uri is same as it fetch the data for the first time
Clearly, either factory is not getting called again or $stateparams is not changing
help is appreciated
I had done some debugging of the code and I have find out since I was directly injecting the $stateparams in the factory that's why it is taking the first value it has attained
to sort it out I have included the id:$stateparams in the get request in the controller and it seemed to work
controller: function($scope, $stateParams, UserFactory) {
$scope.id = $stateParams.partyID;
UserFactory.get({'Id': $stateParams.partyID}, function (userFactory){
$scope.userdata = userFactory.user;
});
}
that's It , It will work like whammy