I am creating a basic html site that is using Angular JS and Adal Js to connect to Office 365. Below are the issues faced -
The page is not redirecting for login purpose.
Getting "unexpected token" and "[$injector:modulerr]" error in the
browser console.
I have configured application in Azure AD with following details -
SIGN-ON URL : http://localhost: port number/
APP ID URI : https:// tenant name/ThomasO365
REPLY URL : http://localhost: port number/
Exchange and SharePoint permission has been provided to the application.
Application Code
var o365CorsApp = angular.module("o365CorsApp", ['ngRoute', 'AdalAngular']) // loading the ADAL JS Angular module
o365CorsApp.config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider',
function($routeProvider, $httpProvider, adalProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'index.html',
requireADLogin: true
})
.otherwise({
redirectTo: '/'
});
var adalConfig = {
tenant: '<tentant name>',
clientId: '<client id>',
extraQueryParameter: 'nux=1',
endpoints: {
"https://outlook.office365.com/api/v1.0": "https://outlook.office365.com/"
}
};
adalProvider.init(adalConfig, $httpProvider);
}
]);
o365CorsApp.factory('o365CorsFactory', ['$http',
function($http) {
var factory = {};
factory.getContacts = function() {
return $http.get('https://outlook.office365.com/api/v1.0/me/contacts')
}
return factory;
}
]);
o365CorsApp.controller("HomeController", function($scope, $q, o365CorsFactory) {
o365CorsFactory.getContacts().then(function(response) {
$scope.contacts = response.data.value;
});
});
<html ng-app="o365CorsApp">
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.min.js"></script>
<script type="text/javascript" src="adal-angular.js"></script>
<script type="text/javascript" src="adal.js"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body ng-controller="HomeController">{{contacts.Email}}
<br/>
<p></p>
</body>
</html>
I am referencing this article. I am using Brackets instead of Visual Studio.
Note-
Tenant and Client ID are correct.
Oauth2AllowImplicitFlow is set to true in manifest file.
I'm going through that article and finding some omissions. Here's some issues I found (don't know if they're causing your error though):
Cut and paste of the code introduces extra spaces in the URL's in app.js. Make sure there are no trailing spaces or spaces between the ? and the rest of the URLs.
The code in app.js has values for tenant and clientId that are obviously for the author, and they never tell you how to replace those with valid values for your app. You can get the correct clientId from the Azure Management Portal. tenant is a bit trickier to get the GUID, but luckily you can just put your domain name there (like contoso.onmicrosoft.com).
Other things to check:
Make sure that you enabled the implicit OAuth2 flow by downloading the manifest, setting oauth2AllowImplicitFlow to true, and reuploading (per the article).
Make sure you are signing into the app using an account that is in the same domain as the one you specify in the tenant property.
Try changing your reply URL to remove index.html. That may be messing with the ADAL libraries token parser.
Related
I've setup the adal and adal-angular v.1.0.10 libraries with my SPA application with mostly great success. I am using webpack, but reference these in my html page in hopes of avoiding global scope issues (though I'd like it to be a dependency). Everything works until the browser attempts to open an iframe to acquire a refresh token, and each iframe opens another iframe inside itself. It logs no errors, and I can't find an explanation as to what I'm doing wrong. So I'm forced to only run the application in a fresh incognito browser. I would appreciate even an explanation as to why this is happening, as we are very married to Azure AD.
relevant sections of index.html
<md-button aria-label="Login" ng-if="!userInfo.isAuthenticated" ng-click="login()">
Login
</md-button>
<script src="build/app.bundle.js" charset="utf-8"></script>
<script src="Scripts/adal.min.js" charset="utf-8"></script>
<script src="Scripts/adal-angular.min.js" charset="utf-8"></script>
my app.js
angular.module('myApp', ['AdalAngular', require('angular-route'), require('angular-animate'), require('angular-sanitize'), 'ngCookies', etc..])
.config(['$routeProvider', '$locationProvider', '$mdThemingProvider', '$httpProvider', 'adalAuthenticationServiceProvider',
function ($routeProvider, $locationProvider, $mdThemingProvider, $httpProvider, adalProvider) {
// azure ad init
adalProvider.init({
instance: 'https://login.microsoftonline.com/',
tenant: TENANT,
clientId: CLIENTID,
cacheLocation: 'localStorage',
anonymousEndpoints: []
},
$httpProvider
);
$routeProvider
.when('/home', {
templateUrl: '/App/Layout/home.html'
})
.when('/admin', {
templateUrl: '/App/Admin/admin.html',
requireADLogin: true
})
etc...
$locationProvider.html5Mode(true).hashPrefix('!');
}]);
After a long series of discussions on GitHub, it was brought to my attention that this was an issue with the AuthenticationContext in adal.js. It keeps opening an iframe while trying to authenticate, causing an infinite loop. I got it to work by exposing the AuthenticationContext.
var AuthenticationContext = require('expose?AuthenticationContext!./../Scripts/adal.js');
require('./../Scripts/adal-angular.js');
This may only work with the versions 0.3.0 version of the library. But it's good enough for now. Hopefully they will alter the library in the future to make it more compatible with modern js applications.
In adal.js in 'getRequestInfo' method, the iframe will 'look' into the parent for the AuthenticationContext. This means that the AuthenticationContext has to be on window scope.
//ES6
import AuthenticationContext from "adal-angular/lib/adal";
window.AuthenticationContext = AuthenticationContext;
...
//ES5
window.AuthenticationContext = require("adal-angular/lib/adal");
...
I am trying to get ng-route working with a google-apps-script web app. I have managed to get basic angular.js functionality working with google-apps-script, but I can't seem to get ng-route to work. I have placed ng-view tags inside a page and have included a separate JavaScript page that contains the routeProvider function.
The ng-view never gets rendered and as far as I can make out the routeProvider does not get called.
Can anyone offer any advice on using ng-route with google-apps-script or suggest another way of rendering a partial html page with google-apps-script
Any answers greatly appreciated.
Have simplified my code and added below:
Code.gs
function doGet(e) {
var template = HtmlService.createTemplateFromFile('Index');
// Build and return HTML in IFRAME sandbox mode.
return template.evaluate()
.setTitle('Web App Window Title')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
index.html
<!-- Use a templated HTML printing scriptlet to import common stylesheet. -->
<?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
<html>
<body ng-app="myApp">
<h1>NG View</h1>
<ng-view></ng-view>
<p>angular check {{'is' + 'working!'}}</p>
<? var url = getScriptUrl();?>
<p id="urlid"><?=url?></p>
</body>
</html>
<!-- Use a templated HTML printing scriptlet to import JavaScript. -->
<?!= HtmlService.createHtmlOutputFromFile('JavaScript').getContent(); ?>
Javascript.html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="https://code.angularjs.org/1.3.15/angular-route.js"> </script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
<script>
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider){
console.log('routeProvider config');
var url = document.getElementById("urlid").innerHTML;
console.log('routeProvider config->' +url);
$routeProvider.when("/",
{
templateUrl: url+"?page=_app.html",
controller: "AppCtrl",
controllerAs: "app"
}
);
})
.controller('AppCtrl', function() {
var self = this;
self.message = "The app routing is working!";
});
</script>
_app.html
<div>
<h1>{{ app.message }}</h1>
</div>
When this runs angular check {{'is' + 'working!'}} works fine, but the ng-view does not get rendered the java console shows:
Error: [$sce:insecurl] Blocked loading resource from url not allowed by $sceDelegate policy.
The first obstacle is "sce"
$sce is a service that provides Strict Contextual Escaping services to AngularJS.
Refer link https://docs.angularjs.org/api/ng/service/$sce#trustAsResourceUrl
For the purpose of investigation, I disabled sce (this is not recommended, though)
$sceProvider.enabled(false);
Now the error is shifted to XMLHttpRequest cannot load... No 'Access-Control-Allow-Origin' header is present on the requested resource.
XHR requests to the Google Apps Script server are forbidden
Refer link https://developers.google.com/apps-script/guides/html/restrictions
Google Apps is delivering the files from a different origin than the scripts.google.com and angular js client code is not able to fetch the partial htmls from the same origin.
I guess approach of ng-view is not feasible given the restrictions placed by google apps.
Here is the final modified code
<script>
angular.module('myApp', ['ngRoute'])
.config(function($routeProvider,$sceProvider){
$sceProvider.enabled(false);
console.log('routeProvider config');
var url = document.getElementById("urlid").innerHTML;
console.log('routeProvider config->' +url);
$routeProvider.when("/",
{
templateUrl: url+"?page=_app.html",
controller: "AppCtrl",
controllerAs: "app"
}
);
})
.controller('AppCtrl', function() {
var self = this;
self.message = "The app routing is working!";
});
</script>
There has been some time since the question, but I'll post a reply either way.
If your partial html page is not too complicated and big, you can use template instead of templateUrl in the routeProvider, plus create a variable with the html you want to show. Something like this below:
var partial_page = "<span>partial page</span>"
$routeProvider.when("/",
{
template: partial_page,
controller: "AppCtrl",
controllerAs: "app"
}
It worked for me, but I wouldn't advise doing so for a complicated partial page as it may become difficult to read the code
My AngularJS app makes calls to an API which is currently hosted at one service, but was previously hosted at a different one, and in the near future is likely to be hosted yet somewhere else.
The URL is regularly changing. For example from
myfirst.heroku.com/app/user/mike/profile
to
mysecond.bluemix.com/app/user/mike/profile
etc.
Instead of changing the URL in every location everytime, I want to just have to change the part before the /app....
In an Angular App what is the best way to do this?
NOTE: Many of the URLs I use throughout the app, are in modules that are added as dependencies to my main app. So Module1 and Module2 both use the URL in their controllers and resources and are then included in MainApp. So a good solution for me needs to be accessible to all dependee apps. Is that possible.
I would like to suggest you that you must use angular constant, Its similar to a service but it creates a constant value which can be inject everywhere in our angular project.
This is how we can create constant
Constant service:
angular.module('AppName')
.constant('REST_END_POINT', 'https://rest.domain.com/');
Usages in controller:
angular.module('AppName')
.controller('CTRL_NAME', ['REST_END_POINT', '$scope', function(REST_END_POINT, $scope){
//your business logic.
]);
$location.host() is the client browser's 'prefix.domain.suffix'
You can inject $location into whatever scope or service.
angular.module('app',[]).run(function($rootScope, $location){
$rootScope.host = $location.host();
})
Plunk: http://plnkr.co/edit/gDgrlwZFyWNKUJgbHHKj?p=preview
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.7/angular.js"></script>
</head>
<body>
<i>Host:</i>
<h1>{{host}}</h1>
<script>
angular.module('app',[]).run(function($rootScope, $location){
$rootScope.host = $location.host();
});
</script>
</body>
</html>
I do use request interceptor for this
csapp.factory('MyHttpInterceptor', [function () {
var requestInterceptor = function (config) {
var prefix = "http://api.example.com";
if (config.url.indexOf("/api/") !== -1) {
config.url = prefix + config.url;
}
}
}]);
configure this intercept in app.config like
csapp.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('MyHttpInterceptor');
});
now all your api requests would be prefixed with api.example.com.
I am building a web Single Page Application using AngularJS. I need that clicking on link change URI in client browser without http request.
http://example.com/ ---> it shows my single page application and clicking on a specific link I need the URL is http://example.com/about but without send http request and show hidden div.
I don't know what you precisely want to do but if you only want do one http request you can perhaps use angular ui router with something like
$stateProvider
.state('main', {
url: "/",
templateUrl: "main.html"
})
.state('about', {
url: "/about",
templateUrl: "main.html",
controller: function($scope) {
$scope.showDiv = "true";
}
})
That way you can switch state and because everything you need is already loaded, nothing gets loaded anymore. Or perhaps you can also use parameters.
But why is it so bad to have one additional request? That would be something interesting to know! :)
EDIT: The easy approach with $location
(https://docs.angularjs.org/guide/$location)
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
<base href="/">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="html5-mode">
<div ng-controller="LocationController">
<button ng-click="changeUrl()">Change url</button>
</div>
</body>
</html>
app.js:
angular.module('html5-mode', [])
.controller("LocationController", function ($scope, $location) {
$scope.$location = {};
$scope.changeUrl = function () {
// https://docs.angularjs.org/guide/$location
console.log("The current path: " + $location.path());
console.log("Changing url...");
$location.path('/newValue')
};
})
.config(function ($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Be sure to set the basePath correct.
Take a look at html2js. This is a grunt task to convert your html templates into a pre-cached js file.
Ideally you would run this as part of your build process. As well you can run a watch task to compile your HTML templates into the pre-cache whenever you save a template -- this is nice for development.
If you are already using gulp, there is a package for you. There are many alternatives to html2js that do essentially the same thing. So if it doesn't suit your needs, try another.
So with this in place, when you navigate to another page -- the HTML template will just be pulled out of angular's cache, and not grabbed from the server.
What's the AngularJS way to access cookies? I've seen references to both a service and a module for cookies, but no examples.
Is there, or is there not an AngularJS canonical approach?
This answer has been updated to reflect latest stable angularjs version. One important note is that $cookieStore is a thin wrapper surrounding $cookies. They are pretty much the same in that they only work with session cookies. Although, this answers the original question, there are other solutions you may wish to consider such as using localstorage, or jquery.cookie plugin (which would give you more fine-grained control and do serverside cookies. Of course doing so in angularjs means you probably would want to wrap them in a service and use $scope.apply to notify angular of changes to models (in some cases).
One other note and that is that there is a slight difference between the two when pulling data out depending on if you used $cookie to store value or $cookieStore. Of course, you'd really want to use one or the other.
In addition to adding reference to the js file you need to inject ngCookies into your app definition such as:
angular.module('myApp', ['ngCookies']);
you should then be good to go.
Here is a functional minimal example, where I show that cookieStore is a thin wrapper around cookies:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>
<body ng-controller="MyController">
<h3>Cookies</h3>
<pre>{{usingCookies|json}}</pre>
<h3>Cookie Store</h3>
<pre>{{usingCookieStore|json}}</pre>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular-cookies.js"></script>
<script>
angular.module('myApp', ['ngCookies']);
app.controller('MyController',['$scope','$cookies','$cookieStore',
function($scope,$cookies,$cookieStore) {
var someSessionObj = { 'innerObj' : 'somesessioncookievalue'};
$cookies.dotobject = someSessionObj;
$scope.usingCookies = { 'cookies.dotobject' : $cookies.dotobject, "cookieStore.get" : $cookieStore.get('dotobject') };
$cookieStore.put('obj', someSessionObj);
$scope.usingCookieStore = { "cookieStore.get" : $cookieStore.get('obj'), 'cookies.dotobject' : $cookies.obj, };
}
</script>
</body>
</html>
The steps are:
include angular.js
include angular-cookies.js
inject ngCookies into your app module (and make sure you reference that module in the ng-app attribute)
add a $cookies or $cookieStore parameter to the controller
access the cookie as a member variable using the dot (.) operator
-- OR --
access cookieStore using put/get methods
This is how you can set and get cookie values. This is what I was originally looking for when I found this question.
Note we use $cookieStore instead of $cookies
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
<script src="http://code.angularjs.org/1.0.0rc10/angular-cookies-1.0.0rc10.js"></script>
<script>
angular.module('myApp', ['ngCookies']);
function CookieCtrl($scope, $cookieStore) {
$scope.lastVal = $cookieStore.get('tab');
$scope.changeTab = function(tabName){
$scope.lastVal = tabName;
$cookieStore.put('tab', tabName);
};
}
</script>
</head>
<body ng-controller="CookieCtrl">
<!-- ... -->
</body>
</html>
Angular deprecated $cookieStore in version 1.4.x, so use $cookies instead if you are using latest version of angular. Syntax remain same for $cookieStore & $cookies:
$cookies.put("key", "value");
var value = $cookies.get("key");
See the Docs for an API overview. Mind also that the cookie service has been enhanced with some new important features like setting expiration (see this answer) and domain (see CookiesProvider Docs).
Note that, in version 1.3.x or below, $cookies has a different syntax than above:
$cookies.key = "value";
var value = $cookies.value;
Also if you are using bower, make sure to type your package name correctly:
bower install angular-cookies#X.Y.Z
where X.Y.Z is the AngularJS version you are running.
There's another package in bower "angular-cookie"(without the 's') which is not the official angular package.
FYI, I put together a JSFiddle of this using the $cookieStore, two controllers, a $rootScope, and AngularjS 1.0.6. It's on JSFifddle as http://jsfiddle.net/krimple/9dSb2/ as a base if you're messing around with this...
The gist of it is:
Javascript
var myApp = angular.module('myApp', ['ngCookies']);
myApp.controller('CookieCtrl', function ($scope, $rootScope, $cookieStore) {
$scope.bump = function () {
var lastVal = $cookieStore.get('lastValue');
if (!lastVal) {
$rootScope.lastVal = 1;
} else {
$rootScope.lastVal = lastVal + 1;
}
$cookieStore.put('lastValue', $rootScope.lastVal);
}
});
myApp.controller('ShowerCtrl', function () {
});
HTML
<div ng-app="myApp">
<div id="lastVal" ng-controller="ShowerCtrl">{{ lastVal }}</div>
<div id="button-holder" ng-controller="CookieCtrl">
<button ng-click="bump()">Bump!</button>
</div>
</div>
http://docs.angularjs.org/api/ngCookies.$cookieStore
Make sure you include http://code.angularjs.org/1.0.0rc10/angular-cookies-1.0.0rc10.js to use it.
Add angular cookie lib : angular-cookies.js
You can use $cookies or $cookieStore parameter to the respective controller
Main controller add this inject 'ngCookies':
angular.module("myApp", ['ngCookies']);
Use Cookies in your controller like this way:
app.controller('checkoutCtrl', function ($scope, $rootScope, $http, $state, $cookies) {
//store cookies
$cookies.putObject('final_total_price', $rootScope.fn_pro_per);
//Get cookies
$cookies.getObject('final_total_price'); }
AngularJS provides ngCookies module and $cookieStore service to use Browser Cookies.
We need to add angular-cookies.min.js file to use cookie feature.
Here is some method of AngularJS Cookie.
get(key); // This method returns the value of given cookie key.
getObject(key); //This method returns the deserialized value of given
cookie key.
getAll(); //This method returns a key value object with all the
cookies.
put(key, value, [options]); //This method sets a value for given
cookie key.
remove(key, [options]); //This method remove given cookie.
Example
Html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.1/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.1/angular-cookies.min.js"></script>
</head>
<body ng-controller="MyController">
{{cookiesUserName}} loves {{cookietechnology}}.
</body>
</html>
JavaScript
var myApp = angular.module('myApp', ['ngCookies']);
myApp.controller('MyController', ['$scope', '$cookies', '$cookieStore', '$window', function($scope, $cookies, $cookieStore, $window) {
$cookies.userName = 'Max Joe';
$scope.cookiesUserName = $cookies.userName;
$cookieStore.put('technology', 'Web');
$scope.cookietechnology = $cookieStore.get('technology'); }]);
I have Taken reference from http://www.tutsway.com/simple-example-of-cookie-in-angular-js.php.
The original accepted answer mentions jquery.cookie plugin. A few months ago though, it was renamed to js-cookie and the jQuery dependency removed. One of the reasons was just to make it easy to integrate with other frameworks, like Angular.
Now, if you want to integrate js-cookie with angular, it is as easy as something like:
module.factory( "cookies", function() {
return Cookies.noConflict();
});
And that's it. No jQuery. No ngCookies.
You can also create custom instances to handle specific server-side cookies that are written differently. Take for example PHP, that convert the spaces in the server-side to a plus sign + instead of also percent-encode it:
module.factory( "phpCookies", function() {
return Cookies
.noConflict()
.withConverter(function( value, name ) {
return value
// Decode all characters according to the "encodeURIComponent" spec
.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent)
// Decode the plus sign to spaces
.replace(/\+/g, ' ')
});
});
The usage for a custom Provider would be something like this:
module.service( "customDataStore", [ "phpCookies", function( phpCookies ) {
this.storeData = function( data ) {
phpCookies.set( "data", data );
};
this.containsStoredData = function() {
return phpCookies.get( "data" );
}
}]);
I hope this helps anyone.
See detailed info in this issue: https://github.com/js-cookie/js-cookie/issues/103
For detailed docs on how to integrate with server-side, see here: https://github.com/js-cookie/js-cookie/blob/master/SERVER_SIDE.md
Here's a simple example using $cookies. After clicking on button, the cookie is saved, and then restored after page is reloaded.
app.html:
<html ng-app="app">
<head>
<meta charset="utf-8" />
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular-cookies.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="appController as vm">
<input type="text" ng-model="vm.food" placeholder="Enter food" />
<p>My favorite food is {{vm.food}}.</p>
<p>Open new window, then press Back button.</p>
<button ng-click="vm.openUrl()">Open</button>
</body>
</html>
app.js:
(function () {
"use strict";
angular.module('app', ['ngCookies'])
.controller('appController', ['$cookies', '$window', function ($cookies, $window) {
var vm = this;
//get cookie
vm.food = $cookies.get('myFavorite');
vm.openUrl = function () {
//save cookie
$cookies.put('myFavorite', vm.food);
$window.open("http://www.google.com", "_self");
};
}]);
})();