Apache FallbackResource and request path behaviour - angularjs

I'm making a simple website with angularjs on a Apache 2.4 webserver. My website folder looks like this:
APACHE24\HTDOCS\TEST
| .htaccess
| index.html
|
+---js
| angular-route.js
| angular.min.js
| app.js
|
\---partials
show-gem.html
I setup some routes, like these ones:
$routeProvider.when("/gem/:gemId", {
controller: "ShowGemController",
controllerAs: "showGemCtrl",
templateUrl: "partials/show-gem.html"
});
And i enabled FallbackResource /test/index.html into my .htaccess file.
Question:
Whenever I manually enter the URL I get the right page (e.g. I write http://localhost:8080/test/gem/123 and I get the corresponding page), but how can this happen? Shouldn't I be redirected to index.html since /test/gem/123 is not an existing resource? And how can angular know it should display that particular template?

FallbackResource is, essentially, a short-hand method for rewriting your URIs. As such, there won't be any redirection to index.html, but the URI you request will be mapped to index.html, where Angular can process it.
For more information, refer to the following article:
http://fideloper.com/apache-fallbackresource
I've always preferred to use mod_rewrite to handle this, as it's a lot more fine-grained, and gives you control.

Related

Angular directive templateUrl trying to GET from Express

I'm trying to get a third-party Angular directive (ngCart) to work with my Angular application. It seems like the ngcart directives are looking for a templateUrl as a relative path to the directive, and instead it seems like Express is trying to serve up the files instead of the directive finding the HTML file at the relative templateUrl path.
Project structure
projectName
| - bower_components/
| - node_modules/
| - public/
| - css
| - index.html
| - app.js (angular app)
| - src/
| - server.js (express app)
| - routes/
| - models/
| - package.json
server.js
...
app.use("/", express.static("public"));
app.use('/bower_components', express.static(__dirname + '/../bower_components'));
app.listen(8000, function () {
console.log("App is listening");
});
third-party directive file causing issues:
templateUrl: function(element, attrs) {
if (typeof attrs.templateUrl == 'undefined') {
return 'template/ngCart/addtocart.html'; // This is the relative path that's freaking out
} else {
return attrs.templateUrl;
}
}
The console error I'm getting is:
GET http://localhost:8000/template/ngCart/addtocart.html 404 (Not Found)
It seems like express is trying to serve up the HTML file in the template folder inside the third-party directive, but I just want it to be a relative path to the HTML file without express being involved.
As pointed out by #Claies in the comments, someone brought this concern up with the creator of ngCart (thread found here), to which he responded saying that you basically are supposed to copy the template files into a folder called "template" in your main public directory. It isn't documented anywhere in the ngCart documentation though, so hopefully this can help someone in the future.
It appears this is the most common way to bring in third-party angular directives that have their own template files.
Update:
I'm no expert in AngularJS, I've been fighting this exact issue with a programming buddy all afternoon.
Eventually we tripped across another question on SO which describes a vastly more elegant solution.
(I've also commented on the GitHub issue tracking page, for future reference.)
In short:
<ngcart-summary template-url="/libraries/ngCart/template/ngCart/summary.html"></ngcart-summary>

Serve up web files from different directory - Error 400 Bad Request

I have an MVC app that uses AngularJS. I am in the process of organizing the folder structure to be feature based rather than type based.
An example folder structure is now
App (Folder within main project, at same level as Views)
Assets
CSS
JS
Pages
Home
home.js
home.tests.js
home.html
About (etc)
Now the problem is that when ui-router tries to load home.html the web server throws a 400 error. If I go to the file manually in the browser it works. What is the problem here? Why can I not serve files up from this directory. Note that I actually right click the 400 message in the console and choose open in new tab. So I know the file I am looking at is the URL being requested from AngularJS
Here is my ui-router setup
.state('home', {
url: '/home',
templateUrl: '/app/pages/home/home.html',
controller: 'mainPageController'
})
Note:
I serve up a .js file from the same directory which seems to work fine!
I had the exact same problem and it was caused by another developer trying to fix an IE caching bug.
I found the solution here by Ben Cull: https://stackoverflow.com/a/30014936/710268.
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
//disable IE ajax request caching
$httpProvider.defaults.headers.get["If-Modified-Since"] = "Fri, 01 Jan 2010 00:00:00 GMT";
My problem was that the "If-Modified-Since" header was set to '0' and for some reason that was causing html template files to not load.
By default the router is going to start at the top level of your MVC project (i.e. where your Views and App folder sit) and not the folder where your JavaScript is served from.
So in Angular your templateUrl needs to be App/Pages/Home/home.html.
So in your angular router configuration have the property:
templateUrl: 'App/Pages/Home/home.html'

Configure Amazon S3 static site with Angular JS ui.router html5Mode(true) on page refresh

How can I configure an Amazon S3 static webpage to properly route Angular ui.router html5Mode routes? On page refresh, it will make a request for a file that doesn't exist, and angular can't handle it. In the docs, they recommend changing your URL rewrites on the server.
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
However, S3 is storage, and doesn't offer the same redirection options
I have been trying to use the built in redirection rules such as
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals >
</Condition>
<Redirect>
<HostName>[[ your application's domain name ]]</HostName>
<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
</RoutingRules>
However, this just leads to a redirect loop.
Any suggestions?
In the Frequently Asked Questions, they rewrite almost everything to serve the index.html page. For HTML5 fallback mode you need to use #!/ (hashbang).
You could change this:
<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
with
<ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
More details on this answer: https://stackoverflow.com/a/16877231/1733117
You may also need to configure your app for using that prefix:
angular.module(...)
...
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Make sure you have the index route configured for your website. Mostly it is index.html
Remove routing rules from S3 configurations
Put a Cloudfront in front of your S3 bucket.
Configure error page rules for your Cloudfront instance.
In the error rules specify:
Http error code: 404 (and 403 or other errors as per need)
Error Caching Minimum TTL (seconds) : 0
Customize response: Yes
Response Page Path : /index.html
HTTP Response Code: 200
Basically there are 3 options, use an EC2 instance to perform the actual server rewrites to the configured HTML5 routes, or, like dnozay suggested, use the fallback mode and re-write requests to use the #! hashbang. Finally, you could just use the standard angular routes, which is the option I went with. Less hassle, and when Angular 2.0 rolls around, you can update to that.
https://stackoverflow.com/a/16877231/1733117
Doesn't really address the routing issue here.
here is another option using nginx proxy_pass, it also allows you to have multiple projects in subfolders and use subdomains
S3 Static Website Hosting Route All Paths to Index.html

AngularJS and PhoneGap: $location.path causes subsequent tempateUrl lookup to fail

I'm having trouble getting path lookup to work with a AngularJS v1.2.0 and PhoneGap/Cordova Android application. I've come pretty far with html5mode(true) by setting <base href="."/> in index.html and then changing $routeProvider.when('/') to $routeProvider.when('/android_asset/www/index.html'). After that I am able to get redirectTo('login') to reach $routeProvider.when('/login') and there render templateUrl: 'static/partials/login.html' as expected.
The problem I have is that if I instead try to redirect to the login page from my Javascript code with $location.path('/login');, the route is found but templateUrl loading fails with an insecurl exception.
I've tried whitelisting access to file:// by using the new angular-sanitize module, but that does not help.
How can I make $location.path() do the same things as redirectTo so that the partial is loaded? Or is there some other way to solve this problem?
UPDATE: I got a bit forward by adding a call to replace() after the path function, e.g.:
$location.path('/login').replace();
but that seems like a hack, and it still causes the templateUrl in the otherwise route to fail with the same exception.
Any ideas on what might be wrong? Is it that html5mode(true) just does not work at this moment with Phonegap and the only way to fix this is to set it to false and add hashtags to every path (like is done in the angular phonegap seed project)?
For future reference, this is how I managed to solve the problem:
AngularJS currently does not seem to support html5mode(true) inside a Cordova application because of the insecurl problem I reported. What I had to do is add
var h5m = (typeof html5Mode !== 'undefined') ? html5Mode : true;
$locationProvider.html5Mode(h5m);
which gives me the possibility to explicitly set html5Mode in the PhoneGap index.html with a global variable:
<script>
var html5Mode = false;
</script>
So now $location.path('/login') as well as redirectTo: 'login' works, but links in html files, don't. To get those working in PhoneGap, with html5Mode disabled, I had to add #/ in front of every link, e.g. login.
That makes PhoneGap work, but breaks the web page which uses History API with html5Mode(true). The last piece of the puzzle was to add <base href="/"/> to the web page's index.html (and leave it out of the index.html of the PhoneGap project.) So now even though I have a link that says #/login in the web page, I get to the url http://example.com/login and don't see any hashes in the address bar.
**
So in the end I have History API working in my web page and History API disabled in the PhoneGap project (where there really is no need for History API as there is no address bar). The only downside is the extra #/ I have to put in each template html file, but that is a minor annoyance compared to the ability to use all of the same html and javascript files for both web and mobile.
I had this same problem as well. I managed to fix it by skipping the leading slash in the route config:
$routeProvider
// route for the foo page
.when('/foo', {
templateUrl: 'foo.html', //previously: '/foo.html'
controller: 'fooController'
}) //etc.

angularjs: route redirection

I have been using ui-router $stateProvider state manager for my application but I haven't defined any routes using $routeProvider.
Now, I would like my urls to be rewritten this way:
http://mydomain/app/feature
to
http://mydomain/feature
the /app folder being the folder that contains my angularjs application as well as the index.html page.
How should I do that ?
Seems to be a server side configuration as #DeividiCavarzan said. I made something like that on apache2, setting Aliases on myApp.conf file whereI was able to do things like:
Alias /myMainPage /app/views/main.html
Hope I've been helpfull.

Resources