AngularJS writing an app with no server - angularjs

I'm trying to write an AngularJS client side only app.
I thought I might be able to load it from chrome by typing in the address bar:
file:///C:/path/to/project//index.html
I also tried to invoke chrome with the flag --allow-file-access-from-files
Unfortunatly nothing happened - just the busy sign on the tab name is working.
Why does is not loading my app?
I'm using the following code:
index.html:
<!doctype html>
<html ng-app="app">
<head>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
<script src="app.js"></script>
<title></title>
</head>
<body style="background-color: white;">
<h1>Index</h1>
<a id="link" href="/login">Go to login</a>
<ng-view></ng-view>
</body>
</html>
app.js:
angular.module('app', ['ngRoute']).
config(function($routeProvider) {
$routeProvider.
when('/', {controller: HomeCtrl, templateUrl: 'app.html'}).
when('/login', {controller: LoginCtrl, templateUrl: 'login.html', resolve: function() {}}).
otherwise({redirectTo:'/'});
});
function HomeCtrl($scope) {
$scope.numbers = [1,2,3,4,5];
}
function LoginCtrl($scope) {
}
app.html:
<div ng-controller="HomeCtrl">
<ul ng-repeat="number in numbers" >
<li>{{number}}</li>
</ul>
</div>
Edit:
2 possible solutions:
Close all chrome instances and run from command line: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files --allow-file-access
Run Firefox which does not have this restriction (Like #GeekBoy mentioned)

As far as I know google chrome does not allow javascripts to be run from file system. But I did a quick google search and found this. Might be useful
Link
On the flipside you can use firefox. Firefox doesn't have such restrictions as far as I know

Try changing the following lines:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
to
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
I think since you're using a file-based way to get at index.html, it's assuming the // also points to a local system resource. By specifically indicating http://, it will look at the actual locations.

I know that this is an old question but for anyone that might still be interested, here is a small project that demonstrates how to write an angularjs client-side app. It is a complete AngularJS 1.63 single page application with routing that does not need a web server: https://github.com/jlinoff/aspa-nows.
There were two key challenges to getting it working: getting the the page href references right because of the newly introduced default hash prefix: ! (see aa077e8 for details), and embedding the template HTML code into index.html as ng-template scripts to avoid CORS errors. Once those fixes were made, it worked as expected.
The project README.md explains what needed to be done in detail and the full source code is available.

Related

Why won't Angular-ui-router's <templateUrl> work when all my files are hosted in S3 bucket?

I'm building a sample AngularJS single-page application that uses Angular-UI-Router. But instead of the usual setup where the Angular application is served up through a web-server, I am running a server-side application that just serves up the index.html page in response to HTTP requests. All other resources needed are just pointers to my AWS S3 bucket or somewhere else.
I am doing this because I want to pre-populate the tags on the server-side with og:title from my database so that the Facebook scraper sees the proper values (as I discussed here). This can't be done purely on the user's client. That's why I have to jump through these hoops.
So when you curl my endpoint, it responds with the following HTML from my index page:
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta property="og:title" content="Saqib's Pre-filled OG Title!"/>
</head>
<body ng-app="pangolinApp">
<table>
<tr>
<td><a ui-sref="splash"><button>Splash</button></a></td>
<td><a ui-sref="blue"><button>Blue</button></a></td>
<td><a ui-sref="green"><button>Green</button></a></td>
<td><a ui-sref="red"><button>Red</button></a></td>
</tr>
</table>
<ui-view></ui-view>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.3/angular-ui-router.min.js"></script>
<script src="http://static.predictagram.com/js/app.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/splashController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/blueController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/greenController.js" type="text/javascript"></script>
<script src="http://static.predictagram.com/js/redController.js" type="text/javascript"></script>
</body>
</html>
It renders onto the page as expected. Great:
Here are the ui-router states specified in http://static.predictagram.com/js/app.js:
var app = angular.module("pangolinApp", ["ui.router"]);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('splash', {url:'/', templateUrl : "html/splash.html", controller : "SplashCtrl"})
.state('blue', {url:'/blue', template: '<p>Hello From Blue!!</p> <p>Color = {{color}}</p>', controller : "BlueCtrl"})
.state('green', {url:'/green', templateUrl: 'html/green.html', controller : "GreenCtrl"})
.state('red', {url:'/red', templateUrl: 'html/red.html', controller : "RedCtrl"});
$locationProvider.html5Mode(true);
});
However, the problem is that only the Blue button actually works. The other ones don't. I can see that when you press each button it enters the respective controller (because I have put a console.log line in each one). But only the template specified for the blue state is working.
Clearly this is because the blue state uses template and all the other states uses templateUrl. So I suspect it cannot find the files html/red, html/green. html/splash.html. Maybe they are not being served? I don't know. How can I ensure my AngularJS Single-Page-App can access those html templates??
EDIT:
Here is pic of the structure of my angular application. But it is stored in my S3 bucket. So replace angular_app/ with http://static.predictagram.com/:
When you set templateUrl as: templateUrl: 'html/green.html' you are telling angular, that your templates can be found at that local folder (html).
As you are trying to take the templates from a remote server, you have to get them with absolute routes. For example: templateUrl: 'http://yourserver/templates/green.html'
As it is not meant to work like that, you are going to have CORS errors, you can take a look to this question/answer and it may help you:
How get a template from a remote URL with AngularJS

AngularJS controller reference becomes undefined

I've just started learning AngularJS and built a small yet simple application, which consists of multiple controllers as shown here:
I have a SiteMaster.html page, inside this page I use ng-view as shown here:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Scripts/angular.min.js"></script>
<script src="Scripts/angular-route.min.js"></script>
<script src="Scripts/app.js"></script> <!-- Consists of Routing -->
<script src="Templates/Params/paramsController.js"></script>
<title>Angular Routing Tutorial</title>
</head>
<body ng-app="mainApp">
<h1>sitemaster Template</h1>
<div ng-view></div>
</body>
</html>
As you can see the last script tag is the controller for the params page, Ideally I don't want this script tag reference on the SiteMaster instead I would like to place it inside the params.HTML page that way it's only loaded when it's required, now I've moved this script tag from the SiteMaster.Html to the params.Html page as shown here:
<script src="paramsController.js"></script>
<div ng-controller="paramsCtrl">
<h1>
Passed a parameter via url
</h1>
</div>
Yet when I run the project I get the following error:
Error: [ng:areq] http://errors.angularjs.org/1.5.2/ng/areq?p0=paramsCtrl&p1=not%20a%20function%2C%20got%20undefined
So my question is, how do I get this paramsController.js reference to work within the params.html page? instead of having it on the SiteMaster.html page?
Please note, when the paramsController.js is placed inside the SiteMaster.Html page it works as expected.
Any help would be appreciated.
Update
After adding ocLazyLoad I have done the following:
Added the script reference to sitemaster.html
Inside my app.js I have done the following:
var app = angular.module('mainApp', ['ngRoute', "oc.lazyLoad"]);
Inside my paramsController.js I have the following:
angular.module("mainApp").controller('paramsCtrl', function ($scope, $routeParams, $ocLazyLoad) {
console.log($routeParams);
var param1 = $routeParams.page_number;
alert(param1);
});
And now I've hit a road block I'm unsure where or how I go about loading this controller via ocLazyLoad ? I following this documentation : https://oclazyload.readme.io/docs
First of all, your path is wrong. Change
<script src="paramsController.js"></script>
to
<script src="Templates/Params/paramsController.js"></script>
Also, include the following in your <head> section:
<base href="/">
And the second thing, I'm not sure, even that will not work as Angular has already been initialized. So you need to use a library like ocLazyLoaded to dynamically load resources.
Also, consider reading this post https://stackoverflow.com/a/17675432/2405040
Update:
In your params.html
<!-- Remove this line
<script src="paramsController.js"></script>
-->
<div ng-controller="paramsCtrl">
<h1>
Passed a parameter via url
</h1>
</div>
And now modify your $routeProvider configuration:
(From the docs https://oclazyload.readme.io/docs/with-your-router)
$routeProvider.
when('/foo', {
templateUrl: 'Templates/Params/params.html',
resolve: {
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('Templates/Params/paramsController.js');
}]
}
})

Angular.js templates not loading

I am new to angular.js and just trying to get my head around the basics and hopefully this is something simple, but I am having trouble loading in a templateUrl.
My index.html is as follows:
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>AngularJS Tutorials</title>
</head>
<body>
<div ng-app="app">
<h1>Introduction to Angular.JS</h1>
<div ui-view></div>
</div>
<!-- Scripts -->
<script type="text/javascript" src="js/angular.min.js"></script>
<script src="js/angular-ui-router.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
My app.js is:
angular
.module('app', [
'ui.router'
])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'templates/home.html'
})
}])
My home.html is: <h1>home template</h1>
So I dont know why this isn't working, but the error is:
XMLHttpRequest cannot load file:///Users/code/Desktop/angular/templates/home.html. Cross origin requests are only supported for HTTP.
Thanks in advance, Gab
This error comes due to a security restriction put by the browser. You can try below steps:
Try to run your code in some other browsers
Add the templates inside index.html itself by placing the content inside script tag. These script elememts should appear after ng-app. (ref link)
<script type="text/ng-template" id="home.html">
Content of the template goes here
</script>
First thing you use <ng-view> </ng-view> for loading your templates. and second is use <script type="text/ng-template" id="home.html"> for you each partial view. third thing is not mandatory but use otherwise at last that makes sense. Here is fiddle for you check it out
fiddle
If you want to run your page locally, I suggest you install a http-server and run it in there ...
Then you avoid CORS issues like that
Example:
with node.js installed
cd ~/myProjectFolder
npm i http-server
http-server ./
Then you could also just enter localhost:8080 in your browser and wouldn't have to point it to some URI/folder

AngularJS routing doesn't work in Safari Extension

I have a very simple AngularJS app that I'm using to test the creation of a new Safari Extension. When I run it from localhost in a regular Safari page all works, but when I run the same code in the context of an extension routing is not working.
I have spent some time tracing the Angular routing code in both scenarios (which is kind of fun) to try to find differences but have not been able to except for the redirect path (http://localhost/.../helloworld.html#/login vs. safari-extension://com.yourcompany.../helloworld.html#/login). Hitting the extension path directly in a browser window renders the same thing I'm seeing in the extension - basic AngularJS functionality is working (updating "sometext") but routing is not (the route specification doesn't replace the ng-view). No errors are being thrown.
helloworld.html
<!DOCTYPE html>
<html ng-app="obApp">
<head>
<title>Hello World, AngularJS</title>
<script type="text/javascript" src="angular.js"></script>
<script type="text/javascript" src="angular-route.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="controllers.js"></script>
</head>
<body>
Write some text in textbox:
<input type="text" ng-model="sometext" />
<h1>Hello {{ sometext }}</h1>
<div ng-view></div>
</body>
</html>
app.js
var obApp = angular.module('obApp', ['ngRoute', 'obControllers']);
obApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'login.html',
controller: 'LoginCtrl'
}).
otherwise({
redirectTo: '/login'
});
}]);
controllers.js
var obControllers = angular.module('obControllers', []);
obControllers.controller('LoginCtrl', ['$scope',
function($scope) {
// do stuff
}
]);
login.html
HERE I AM!
UPDATE:
It has something to do with the XHR request to get the routing page - from a regular web page the XHR.send() returns readyState=4 and status=200, from the extension it returns readyState=3 and status=0 (when it moves to readyState=4 status is still 0). It makes me suspect cross-origin XMLHTTPRequest restrictions but it's definitely requesting the page from the exact same domain (safari-extension://...)
HELP! :-)
I'm answering my own question here because it looks like this is how I'm going to need to proceed, but if someone has a better idea please let us know.
I've hacked the AngularJS core library (ugh) to return a status of 200 if there is a response to the request under the condition of the location protocol being "safari-extension" (otherwise return 404). The authors did the same for the condition of the protocol being "file" because it also always returns a 0 status in that case too so I don't feel too bad.
I'll see if I can bring Google's attention to it, either so they can enlighten me as to what I'm missing or else possibly have them add it in a future rev.
UPDATE:
Looking at the history of this code in the GitHub project I see that they implemented the identical fix I was going to propose in a later version of AngularJS. :-)

Doesn't work examples from angularfire tutorial

When I try to run page as described in https://www.firebase.com/docs/angular/
<html ng-app="sampleApp">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
<script src="//cdn.firebase.com/js/client/1.0.6/firebase.js"></script>
<script src="//cdn.firebase.com/libs/angularfire/0.6.0/angularfire.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="SampleController">
<input type="text" ng-model="text"/>
<h1>You said: {{text}}</h1>
</body>
</html>
and app.js:
angular.module("sampleApp", ["firebase"])
.factory("sampleService", ["$firebase", function($firebase) {
var ref = new Firebase("https://sizzling-fire-8112.firebaseio.com/");
return $firebase(ref);
}])
.controller("SampleController", ["$scope", "sampleService",
function($scope, service) {
service.$bind($scope, "text");
}
]);
There is: You said: {{text}} on the web screen.
What I did wron?
Thanks ;)
I suppose you are opening this page not via webserver, but directly from filesystem.
If so, never do that way. There can be various restrictions with AJAX, canvas, etc.
In your example you're trying to load outer scripts with protocol relative URLs.
In case of opening page from filesystem, URLs are being transformed into file://... format.
To solve this problem you should use a webserver. If you can't use it for some reasons, add http: to the beginning of the outer URLs, so it will be:
http://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js
instead of
//ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js

Resources