Basic AngularJS service request - javascript

I am trying to make changes to a very basic sample app so to decouple the static portion of the application from the server side based on Springboot. I want to run the AngularJS static portion of the app on nginx and make remote service calls to the Springboot application.
Here is gist of the application ...
angular.module('blah', ['ent1', 'errors', 'status', 'info', 'ngRoute', 'ui.directives']).
config(function ($locationProvider, $routeProvider) {
$routeProvider.when('/errors', {
controller: 'ErrorsController',
templateUrl: 'assets/templates/errors.html'
});
$routeProvider.otherwise({
controller: 'MyController',
templateUrl: 'assets/templates/albums.html'
});
}
);
function MyController($scope, $modal, $location, $http, a, b, st) {
$scope.init = function() {
console.log($location.host());
---> $location.host("http://somewhereelse:8080/");
console.log($location.host());
....
};
}
Some details have been removed for readability sake.
As you can see, I have injected $location into my controller, which I assume is where I would change the host. However, the before and after console.log still show me "localhost".
How do I make a remote API call to a service using AngularJS? Like I said, it is probably a very basic question.

Hope you are trying to make some API calls from your angular application. For that you can use angular $http service.
A sample code will look like this:
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
For More details see the official doc:
https://docs.angularjs.org/api/ng/service/$http

Related

Routes loaded from an api - controller never called

I'm trying to load routes into my angularJS app by running an ajax call and setting up routes on my RouteProvidor. The following is my code to do so.
var app = angular.module('app', ['ngRoute']);
var appRouteProvider;
app.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
appRouteProvider = $routeProvider;
appRouteProvider.when('/', {
templateUrl : '../../app/templates/home.html',
controller : 'IndexController'
});
}]).run(function($http, $route){
url = siteApiRoot+'api/routes';
$http.post(url, jQuery.param([]), {
method: "POST",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}
).success(function(data){
for(i in data){
appRouteProvider.when(data[i].route, {
templateUrl : data[i].template,
controller : data[i].controller
});
}
console.log($route.routes);
});
});
The console.log outputs a correct set of routes to the console which seems to indicate that the routes have been correctly assigned. But if I were to open any url that should be handled by the route. Nothing happens. The basic assets load i.e. navigation bar and footer which are constant throughout but the controller for the route is never called. What am I missing here guys.
-- UPDATE
Tehcnically I have routes that follow the following patterns:
List of entries:
/<city>/<category>
/<city>/<subdistrict>-<category>
/<city>/<entry-slug>
I'm not sure how well to define the above - basically the first two routes would invoke one controller and one view while the third woudl invoke another. However I'm stuck with how to define this kind of routing in AngularJS provided that etc are all slugs in a database. Pretty much left with hardcoding an array of routes but that also doesn't work as it seems.
Plus I also have other pages that are static - eg /about /site/contact - a bit lost on routing here.
You can't change the router configuration after initialisation, but you can use a parameterized route to handle everything.
You can fetch the routing data in an external service, and find the appropiate entry for the current parameters with whatever lookup logic you need. I assume the point of this is to have different templates and controllers for these routes.
The template you can solve with a simple ng-include, but you'll have to manually instantiate the controller. Look into $injector instead of the $controller call here for more details on this one, as you'll probably need full dependency injection for them. The RouteController here just passes its own scope to the created controller (which at this point really is just like any generic service), which is already attached to the container.html by the router. Note that the ng-include creates a child scope, so you have to be careful if you want to assign new variables on the scope in templates.
(If this is a problem, you can manually fetch, build and attach the template too: take a look into $templateRequest, $templateCache and $compile services. (You will have to create a directive to attach it to the DOM))
Here is the barebones sample code:
var app = angular.module('app', ['ngRoute']);
app.service("getRouteConfig", function($http) {
var routeRequest = $http.post(url, jQuery.param([]), {
method: "POST",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}
return function(params) {
return routeRequest.then(function(routes) {
// find route entry in backend data for current city, category/slug
return routes[params.city][params.slug];
});
}
})
app.controller("RouteController", function(route, $scope, $controller) {
$controller(route.controller, {$scope: $scope});
})
app.config(function($routeProvider) {
$routeProvider.when('/', {
templateUrl : '../../app/templates/home.html',
controller : 'IndexController'
});
$routeProvider.when('/:city/:url', {
templateUrl : '../../app/templates/container.html',
controller : 'RouteController',
resolve: {
route: function(getRouteConfig, $routeParams) {
return getRouteConfig($routeParams);
}
}
});
});
container.html:
<ng-include src='$resolve.route.template'>
Angular config functions are for setting up configuration, which is used for initialising services. This means that trying to alter the config from the run() function will result in nothing happening, as the config has already been utilised.
One possible option is to provide the config from the server inside the actual js file sent to the client. Otherwise there is no easy way to alter config using $http.
There is more discussion here: use $http inside custom provider in app config, angular.js

Completely Lost on AngularJS Authentication Implementation

I am not new to programming, but I am new to AngularJS. I am working with my first AngularJS site and am looking to add an authentication & authorization layer to my app. I am trying to follow this article which seems to be very straight forward: https://medium.com/#mattlanham/authentication-with-angularjs-4e927af3a15f
However, I find that too many AngularJS articles only give snippets without actually giving guidance on where to actually implement the code! Very, very frustrating . . .
I have a:
app.js in my app root directory
controller.js for a page that I want to put behind an authorization layer
I also have the corresponding REST services to handle the user authentication
Can someone please help me distinguish what items from the article should go in app.js (if any???) and which ones should go in my individual page?
My app.js has looked like:
var app = angular.module('appname', [$stateProvider]);
app.config(function($stateProvider, $urlRouterProvider){
alert("auth fired");
$stateProvider
.state("account", {
url: "/account.html",
templateUrl: "/account.html",
controller: "HistoryCtrl",
authenticate: true
})
.state("login", {
url: "/login.html",
templateUrl: "/login.html",
controller: "LoginCtrl",
authenticate: false
});
// Send to login if the URL was not found
$urlRouterProvider.otherwise("/login.html");
});
And the page I want to secure looked like:
var app = angular.module('appname', []);
app.controller('HistoryCtl', function($scope, $http) {
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
}]);
$http({
method: "post",
url: "http://serviceURL/v1/account",
headers:{'Content-Type': 'application/json'},
data: {"txtToken":"myusertoken"}
}).success(function (response) { $scope.names = response.entries;});
});
app.run(function ($rootScope, $state, AuthService) {
$rootScope.$on("$stateChangeStart", function(event, toState, toParams, fromState, fromParams){
if (toState.authenticate && !AuthService.isAuthenticated()){
// User isn’t authenticated
$state.transitionTo("login");
event.preventDefault();
}
});
});
But none of these seemed to fire and there were no errors in the console. How would one go about implementing the snippets from the article? Can someone please break it out according to the file in which each snippet should go? Do I need to declare app.js as a source file in my HTML or is using the app name in the HTML tag sufficient?
Welcome to Angular! Can you verify that you have an ng-app='appname' directive in your HTML? You'll need this to "bootstrap" the entire application. You'll also need to declare ui.router as a dependency, which you'll need in order for this to work.
I work at Stormpath and we have a guide which shows you how to build an Angular application from scratch, including authorization (using our module). You can find it here: Stormpath's AngularJS Guide
Hope this helps!

Dynamic directive templates using app level resolve AngularJS

Currently i am implementing a completely stateless token-based authentication with AngularJS and a REST API as backend service. This works pretty well, but about one state i am currently not aware of and wanted to ask you how to handle it.
My intend is only to save my authentication token in the local storage from the client. On initial loading from the application i want to retrieve all user information from the REST API (GET /me) and save it in the $scope from my AngularJS project.
After implementing it, i have several problems to be sure that the retrieved user information are completely resolved and could work with the informations (like the access rights from the user).
I just want you to show an example where i ran into a kind of "asynchronous problem".
angular.directive('myDirective', ['MyAsyncService', function(MyAsyncService) {
return {
restrict: 'E',
templateUrl: function(element, attributes) {
console.log(MyAsyncService.getData());
}
}
}]
At this example my asynchronous service haven't the information yet, when the directive is rendered. Also retrieve the async data in the resolve function from ngRoute/ui-router or in the run() method from AngularJS couldn't solve my problem.
So back to my question ... It is better to save some information from the user on client side to avoid some of this problems? From my point of view it would be better not to save any kind of user information (like access rights, username, id, email address, ...) due security purposes.
How you handle you the authentication and authorization in a token-based AngularJS application?
Thanks in advance, hopefully you can get me back on track.
You need to resolve() authentication - especially this type of authentication at the app level.
If you aren't using ui.router - take a look.
When we resolve() on a route what we are saying is - do not do anything else until this thing is finished doing what it's doing.
This also assumes you are familiar with promises.
Your resolve dependency will ultimately expect that this asynchronous request is returning a promise so that it may chain controller logic after the callback finishes execution.
For example:
$stateProvider
.state('myState', {
resolve:{
auth: function($http){
// $http returns a promise for the url data
return $http({method: 'GET', url: '/myauth'});
}
},
controller: function($scope, auth){
$scope.simple = auth;
}
});
But there's more. If you want the resolve to happen at the begining of application execution for any route - you also need to chain your state declarations:
$stateProvider
.state('app', {
abstract: true,
templateUrl: 'app/views/app.tpl.html',
resolve:{
auth: function($http){
// $http returns a promise for the url data
return $http({method: 'GET', url: '/myauth'});
}
},
controller: function($scope, auth){
$scope.resolvedauth = auth;
}
}
.state('app.home', {
url: '/home',
templateUrl: 'home/views/home.tpl.html',
controller: function($scope){
//Should be available.
console.log($scope.$parent.resolvedauth);
}
});
Now that your children inherit from the app level resolve, you could control the template by doing something like this:
.directive('myDirective', function() {
return {
templateUrl: function(elem, attr){
return 'myDirective.'+attr.auth+'.html';
}
};
});
And the declaration itself:
<my-directive auth="resolvedauth.status" />

Angular JS Root Scope

I am working with angular js at view layer. I need to use some global variable that will be used and modified by all the controllers method in my application:
var app = angular.module('myWebservice', ['ngCookies']).run(
function($rootScope) {
$rootScope.authToken = null; });
app.controller('UserController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.login= function() {
$http.defaults.headers.post = {'Accept' : 'application/json',
'Content-Type' : 'application/json'};
$http.post('/myServise/api/user/login-user', {
emailId : $scope.username,
password : $scope.password
}).success(function(data, status) {
if (status == 200) {
$rootScope.authToken = data.object.authToken;
}).error(function(data, status) {
console.debug(data);});
}// Else end
};// End Login
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.getRootScopeValues = function()
//$scope.getRootScopeValues = function($rootScope)
{
$scope.token = $rootScope.authToken;
console.log($scope.token);// Undefined
console.log($rootScope.authToken);// Undefined
}
});
I am new to Angular JS, I have also tried to use service but I don't know why I am not able to access global variable (authToken). Please help me I am stuck at this point ....Thanks in advance...
I am not sure how your application works but looks like you have a problem of asynchronous calls (while $http is working you are trying to access the variable which is not set yet). Please look at this answer about Asynchronous calls. Maybe this is your case? Also I should note that using $rootScope is always a bad idea. Try to avoid it. You should use service instead which is also a singleton object and always a much better and maintainable approach.
I need to use some global variable that will be used and modified by all the controllers method in my application
The best way to achieve this is using a Service, but you don't have to if you would like to leave it at the $rootScope
I have tried to use service as well but same results "Undefined"
Because the call for the authToken is asynchronous, the controller could run before the token returns from remote server.
You can add the token retrieval logic to the route definition as a 'resolve' field like this:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/your/route', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
token: function() {
//return a promise with the token here
}
}
})
However, this is NOT good in your case as you will have to setup the 'resolve' for every route. If you are using AngularUI Route that supports nested routes, you can simply add the 'resolve' to the root state/route. This is what I've been using in my project.
If you are not using AngularUI Route, there's another way of doing it. You can assign the returned value of the $http.post to a variable in the $rootScope e.g. $rootScope.tokenPromise.
The returned of $http.post is a promise, you can use the 'then; method to register callbacks, and these callbacks will receive a single argument – an object representing the response.
In your controller, you will have put some extra lines, you will get the token asynchronously like this
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$rootScope.tokenPromise.then( function(token){
console.log(token); //depends on the returned data structure
} )
});
In your application 'run' block, you will have to create a promise at $rootScope.tokenPromise. you can either use $http to retrieve the token and get the promise there in the run block, or create a pending promise and retrieve the token elsewhere in other places, after which you can resolve the promise.

Change ng-view after get data in Angular.JS

I'm going to get some data from server using $http and JSON response. $http.get() are called after route change. But template are changed before data is downloaded. My goal is:
User press a hyperlink in menu, that changes a route,
Shows Loading Spinner (DOM Element is in another controller which is on page everytime)
Initializing $scope.init() (via ng-init="init()") in controller which is in my new template, this also initializing get data from server
Data are downloaded, now I can hide spinner and change visible template
How can I do this? My App looks for example:
Javascript:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope, $http) {
$scope.init = function() {
$http({method: 'GET', url: 'http://ip.jsontest.com/'}).success(function(data) {
console.log(data);
$scope.ip = data.ip;
});
}
});
myApp.config(function($routeProvider) {
$routeProvider.when('/link', {
controller: 'MyCtrl',
templateUrl: 'embeded.tpl.html'
});
});
HTML:
<script type="text/ng-template" id="embeded.tpl.html">
<div ng-controller="MyCtrl" ng-init="init()">
Your IP Address is: {{ip}}
</div>
</script>
<div>
<ul>
<li>change route</li>
</ul>
<div ng-view></div>
</div>
You need to resolve data before routing happens, thus, move your $http to config section.
This is good tutorial for that, http://www.thinkster.io/pick/6cmY50Dsyf/angularjs-resolve-conventions
This is config part.
$routeProvider.when('/link', {
controller: 'MyCtrl',
templateUrl: 'embeded.tpl.html',
resolve: {
data: function ($q, $http) {
var deferred = $q.defer();
$http({method: 'GET', url: 'http://ip.jsontest.com/'}).then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
}
}
and this is controller part
//`data` is injected from routeProvider after resolved
myApp.controller('MyCtrl', function($scope, $http, data) {
$scope.ip = data.ip
});
I think promise in AngularJS is very important concept for any async. processing.
You need to use this technique every time you have callback.
I will not do it all for you, however I will point you in the right direction.
First you need the ngRoute module.
var myApp = angular.module('myApp', ['ngRoute']);
And the JS file:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.js"></script>
Now you routes will be working and you do not need to call a special init function in your controller since they get instanciated on every route change when used with ng-view.
For the spinner, you could add some interceptors to all ajax requests using the $httpProvider. Inside the interceptors you could emit some events on the $rootScope and listen to then in a specialed custom attribute directive e.g. spinner where the magic would occur ;)

Categories

Resources