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
I am writing a sample application using angularjs. i got an error mentioned below on chrome browser.
Error is
Error: [ng:areq] http://errors.angularjs.org/1.3.0-beta.17/ng/areq?p0=ContactController&p1=not%20a%20function%2C%20got%20undefined
Which renders as
Argument 'ContactController' is not a function, got undefined
Code
<!DOCTYPE html>
<html ng-app>
<head>
<script src="../angular.min.js"></script>
<script type="text/javascript">
function ContactController($scope) {
$scope.contacts = ["abcd#gmail.com", "abcd#yahoo.co.in"];
$scope.add = function() {
$scope.contacts.push($scope.newcontact);
$scope.newcontact = "";
};
}
</script>
</head>
<body>
<h1> modules sample </h1>
<div ng-controller="ContactController">
Email:<input type="text" ng-model="newcontact">
<button ng-click="add()">Add</button>
<h2> Contacts </h2>
<ul>
<li ng-repeat="contact in contacts"> {{contact}} </li>
</ul>
</div>
</body>
</html>
With Angular 1.3+ you can no longer use global controller declaration on the global scope (Without explicit registration). You would need to register the controller using module.controller syntax.
Example:-
angular.module('app', [])
.controller('ContactController', ['$scope', function ContactController($scope) {
$scope.contacts = ["abcd#gmail.com", "abcd#yahoo.co.in"];
$scope.add = function() {
$scope.contacts.push($scope.newcontact);
$scope.newcontact = "";
};
}]);
or
function ContactController($scope) {
$scope.contacts = ["abcd#gmail.com", "abcd#yahoo.co.in"];
$scope.add = function() {
$scope.contacts.push($scope.newcontact);
$scope.newcontact = "";
};
}
ContactController.$inject = ['$scope'];
angular.module('app', []).controller('ContactController', ContactController);
It is a breaking change but it can be turned off to use globals by using allowGlobals.
Example:-
angular.module('app')
.config(['$controllerProvider', function($controllerProvider) {
$controllerProvider.allowGlobals();
}]);
Here is the comment from Angular source:-
check if a controller with given name is registered via $controllerProvider
check if evaluating the string on the current scope returns a constructor
if $controllerProvider#allowGlobals, check window[constructor] on the global window object (not recommended)
.....
expression = controllers.hasOwnProperty(constructor)
? controllers[constructor]
: getter(locals.$scope, constructor, true) ||
(globals ? getter($window, constructor, true) : undefined);
Some additional checks:-
Do Make sure to put the appname in ng-app directive on your angular root element (eg:- html) as well. Example:- ng-app="myApp"
If everything is fine and you are still getting the issue do remember to make sure you have the right file included in the scripts.
You have not defined the same module twice in different places which results in any entities defined previously on the same module to be cleared out, Example angular.module('app',[]).controller(.. and again in another place angular.module('app',[]).service(.. (with both the scripts included of course) can cause the previously registered controller on the module app to be cleared out with the second recreation of module.
I got this problem because I had wrapped a controller-definition file in a closure:
(function() {
...stuff...
});
But I had forgotten to actually invoke that closure to execute that definition code and actually tell Javascript my controller existed. I.e., the above needs to be:
(function() {
...stuff...
})();
Note the () at the end.
I am a beginner with Angular and I did the basic mistake of not including the app name in the angular root element. So, changing the code from
<html data-ng-app>
to
<html data-ng-app="myApp">
worked for me. #PSL, has covered this already in his answer above.
I had this error because I didn't understand the difference between angular.module('myApp', []) and angular.module('myApp').
This creates the module 'myApp' and overwrites any existing module named 'myApp':
angular.module('myApp', [])
This retrieves an existing module 'myApp':
angular.module('myApp')
I had been overwriting my module in another file, using the first call above which created another module instead of retrieving as I expected.
More detail here: https://docs.angularjs.org/guide/module
I just migrate to angular 1.3.3 and I found that If I had multiple controllers in different files when app is override and I lost first declared containers.
I don't know if is a good practise, but maybe can be helpful for another one.
var app = app;
if(!app) {
app = angular.module('web', ['ui.bootstrap']);
}
app.controller('SearchCtrl', SearchCtrl);
I had this problem when I accidentally redeclared myApp:
var myApp = angular.module('myApp',[...]);
myApp.controller('Controller1', ...);
var myApp = angular.module('myApp',[...]);
myApp.controller('Controller2', ...);
After the redeclare, Controller1 stops working and raises the OP error.
Really great advise, except that the SAME error CAN occur simply by missing the critical script include on your root page
example:
page: index.html
np-app="saleApp"
Missing
<script src="./ordersController.js"></script>
When a Route is told what controller and view to serve up:
.when('/orders/:customerId', {
controller: 'OrdersController',
templateUrl: 'views/orders.html'
})
So essential the undefined controller issue CAN occur in this accidental mistake of not even referencing the controller!
This error might also occur when you have a large project with many modules.
Make sure that the app (module) used in you angular file is the same that you use in your template, in this example "thisApp".
app.js
angular
.module('thisApp', [])
.controller('ContactController', ['$scope', function ContactController($scope) {
$scope.contacts = ["abcd#gmail.com", "abcd#yahoo.co.in"];
$scope.add = function() {
$scope.contacts.push($scope.newcontact);
$scope.newcontact = "";
};
}]);
index.html
<html>
<body ng-app='thisApp' ng-controller='ContactController>
...
<script type="text/javascript" src="assets/js/angular.js"></script>
<script src="app.js"></script>
</body>
</html>
If all else fails and you are using Gulp or something similar...just rerun it!
I wasted 30mins quadruple checking everything when all it needed was a swift kick in the pants.
If you're using routes (high probability) and your config has a reference to a controller in a module that's not declared as dependency then initialisation might fail too.
E.g assuming you've configured ngRoute for your app, like
angular.module('yourModule',['ngRoute'])
.config(function($routeProvider, $httpProvider) { ... });
Be careful in the block that declares the routes,
.when('/resourcePath', {
templateUrl: 'resource.html',
controller: 'secondModuleController' //lives in secondModule
});
Declare secondModule as a dependency after 'ngRoute' should resolve the issue. I know I had this problem.
I was getting this error because I was using an older version of angular that wasn't compatible with my code.
These errors occurred, in my case, preceeded by syntax errors at list.find() fuction; 'find' method of a list not recognized by IE11, so has to replace by Filter method, which works for both IE11 and chrome.
refer https://github.com/flrs/visavail/issues/19
This error, in my case, preceded by syntax error at find method of a list in IE11. so replaced find method by filter method as suggested https://github.com/flrs/visavail/issues/19
then above controller not defined error resolved.
I got the same error while following an old tutorial with (not old enough) AngularJS 1.4.3. By far the simplest solution is to edit angular.js source from
function $ControllerProvider() {
var controllers = {},
globals = false;
to
function $ControllerProvider() {
var controllers = {},
globals = true;
and just follow the tutorial as-is, and the deprecated global functions just work as controllers.
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.
Hi I am working on the angular js 60ish min tutorial an am not able to figure out the routing functionality here is my code
Issue: When I open the html file nothing happens i do noy see any routing happening
view1.html and view2.html are in the same folder with main.html and angular.min.js file.
Please point the mistake in the code or how to debug this.
<!DOCTYPE HTML>
<HTML data-ng-app ="demoapp">
<head><title>New angular js app </title></head>
<body>
<div>
<div ng-view></div>
</div>
<script src = "angular.min.js"></script>
<script>
var demoapp = angular.module('demoapp',[]);
demoapp.config(function($routeProvider){
$routeProvider
.when('/view1',
{
controller:'SimpleController',
templateUrl:'view1.html'
})
.when('/view2',
{
controller:'SimpleController',
templateUrl:'view2.html'
})
.otherwise({ redirectTo:'/view1'});
});
demoapp.controller('SimpleController', function ($scope){
$scope.customers = [
{name:"ishan", city:"Delhi"},
{name:"Ankit", city:"New Delhi"},
{name:"subhash", city:"haridwar"},
];
$scope.addCustomer = function()
{
$scope.customers.push
({
name:$scope.newCustomer.name,
city:$scope.newCustomer.city
});
};
});
</script></body></html>
Since Angular 1.2 you have to include the route module.
var demoapp = angular.module('demoapp',['ngRoute']);
See the docs
Please open console on your browser to detect the errors. If any error is shown, you try to refer to the AngularJS Google CDN latest as follows:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
After this, if your code still isn't working fine, please turn on the Debug script on your browser to investigate more.
Please let me know if any problem still happens.
Hope this will help you!!
var demoapp = angular.module('demoapp',[ngRoute]);
don't forget Include the angular-route.js in your page
Below is my HTML and the code to do a web service call and display the data in ngGrid. The problem is with the route provider, I'm not being able to show the grid in my separate view, but if I do the exact same code without the route provider,and load just that page, it works perfectly fine.
Since I'm very new to angularJS, any suggestions would be appreciated.I've done lot of research but did not work, at least for me. Please consider this if I have missed related post somewhere. Thanks ahead!
<div>
<!--Placeholder for views-->
<div ng-view=""></div>
</div>
//this is what I have in one of my view for grid.
<div class="gridStyle" data-ng-grid="gridOptions">
</div>
/* display/get/call the JSON data from the web service and bind it to the view */
var app = angular.module('salesApp',['ngGrid']);
app.config (['$routeProvider', function ($routeProvider){
$routeProvider
.when('/sales',
{
controller:'salesCtrl',
templateUrl:'Partials/sales.html'
})
.when('/associate',
{
controller:'assocCtrl',
templateUrl:'Partials/associate.html'
})
.otherwise({redirectTo:'/sales'});
}]);
app.controller('salesCtrl', function($scope, $http) {
$http.jsonp('http://some url...')
.success(function (data) {
$scope.sales = data;
});
$scope.gridOptions = {data: 'sales',
columnDefs:[{field:'Region_Num', displayName: 'Region Num'}
],
showGroupPanel: true
};
});
This is an older post; but I was having the same problem. It turns out when I defined the app/Moduile; I was not passing ngGrid in as one of the options:
myApp = angular.module('myApp', ['ngGrid']);
That is clearly not your problem; as I do see the statement in your code; so this answer is probably for other people who find this question via Google.