I'm asking this because a couple of times now, I've tried to play around with the $locationProvider.html5Mode(true) command along with <base href="/"> and ran into a lot of errors calling the scripts/styles/images for my project. I guess there must be something I am doing wrong, but is there a certain folder structure you should follow so you don't run into these errors? Or is there a specific way that the base href works that I'm not quite understanding?
Recently, I thought I'd try it on a very, very small app. It's effectively a static website, but I want to take advantage of Angular's routing to make sure all of the pages can load instantly. So my structure would be something like this:
my-project
css
images
js
angular
app.js
app.routes.js
mainCtrl.js
views
home.html
about.html
contact.html
index.html
So I know that this folder structure isn't great, but I'll only be using Angular in this project for routing, nothing more, so it fits my needs.
I put into the head <base href="/">, put in body ng-app and ng-controller, and inside the body put a <div ng-view> somewhere too.
I added in the $locationProvider.html5Mode(true) and tried the app out. All of my scripts are then being loaded as http://localhost:8888/script.js which is incorrect. The project is located in a folder so that index.html is located in http://localhost:8888/my-project/index.html. So, it should be loading the scripts from http://localhost:8888/my-project/js/angular/app.js for example.
Is there something that I'm not understanding about the base href? Eventually I may host this app somewhere online, so I want the URLs to scripts etc to all be relevant to the file really. Anyone have any ideas?
Alright, so above the base href tag I would have my CSS styles which would be linked as css/style.css and at the bottom of my body tag I would have my scripts loaded as js/init.js or js/angular/app.js for example. This would try to load it as if the js folder is located directly at localhost:8888/js.
The Angular framework is a Single Page Application (SPA) that is able to run in a browser by essentially tricking the browser into running code snippets rather than make server calls, by making use of the "hash" (#) page anchor. Normally, a URL with a # would jump to a specific anchor point in the page; in the case of Angular or other similar SPA frameworks, the # is redirected to a code segment instead.
Ideally, you would like to not have to reference this # in your page URLs. This is where Html5Mode comes into play. Html5Mode is able to hide the #, by using the HTML5 Push State (aka history API).
When Html5Mode is enabled, the normal links on the page are silently replaced by Angular with event listeners. When these events are triggered, the current page is pushed into the browser history, and the new page is loaded. This gives the illusion that you are navigating to a new page, and even allows for the back button to operate.
This is all fine when you are dealing with links which are clicked from within the running application, but relying on event listeners can't work if you navigate to the page from an external source, where Angular isn't loaded into memory yet. To deal with this, you must be loading your pages from a web server which supports URL rewrites. When the server receives a request for a URL that there isn't a physical page for, it rewrites the URL to load the base HTML page, where Angular can be loaded and take over.
When Angular receives a request for a route which has been rewritten in this manner, it must first determine what the intended route was. This is where the Base HTML Tag comes into play. Angular uses the Base reference to help it to determine which part of the URL is on the server, and which part is a client route. Essentially, where the # in the URL would be if Html5Mode was not enabled.
Unfortunately, Base is an HTML Tag that is used by the browser for more than just Angular. The browser also uses this tag to determine the correct location to load scripts and resources using relative paths from, regardless of the path in the location bar. In general, this isn't a problem if all of the scripts and resources are relative to the location of the Index.html file. When Base is omitted, the browser will load scripts from the apparent base path determined by the current URI. However, once you provide it, the browser will use whatever value you have supplied.
In general, unless you are hosting angular on a sub-page of your site and you want your users to expect something specific in the URL string, you should always control the base on your server, and use Base="/" on the client side.
Related
I'm working in a Single Page web App, witch will require user/password protection.
Modules will be loading depending on the user profile, to restrict the access on a roll-based manner.
I'm using ng-view to load the templates corresponding the user id.
How can I selectively load the corresponding JavaScript file of the template's controller?
<script script src="restrictetd/path/MyAngularControl.js"></script>
There is no point in downloading a JavaScript file if the user has no access to that particular template.
I really appreciate any advice.
You are possibly over complicating your app. Unless your application is utterly massive it will be easier to maintain if you just deliver all of the needed JavaScript to the client. It is clients job to not show actions a user should not be able to do but it is the servers job to actually enforce that.
However to do what you want to do is possible. First thing to do in the route would be to download the JavaScript file and the template but have the route initially return nothing or some loading indicator. Once the JS file is loaded add a script tag to the HEAD or process the JS file to get it loaded. Then load the template and compile it.
One caveat of this process is that NO new modules can be used. I would recommend adding any be controllers / directive to the module you are using for ng-app. New things can be defined this way in an already initalize Angular app however you cannot redefine anything. So if controller xyz already exists, and you load another controller xyz the second load will not do anything.
I'm building my own website using AngularJS. I want my site's navigation to behave without the "browser flash" that exists when you go between pages, e.g. clicking a link on index.html that takes you to foo.html. I also want clean URLs, so for instance I can go to mysite.com/foo and have the browser display the content in foo.html.
Angular's client-side routing in HTML5 mode is an effective solution, but there are exceptions:
If I go to mysite.com, I can configure $routeProvider to map the view to the appropriate partials (e.g. index.html or foo.html) and modify the URL the browser displays. However, if I go to mysite.com/foo by directly typing that URL into the browser, I will get a 404 error because the server is looking for something in mysite.com/foo/ that isn't there. The same will happen if I refresh the page while Angular is pointing to mysite.com/foo.
In short, navigating to mysite.com/foo is only handled properly if navigated from within the Angular app.
How can I handle this so that my site behaves the way I want? Do I use PHP and/or mod_rewrite to redirect the browser back to mysite.com upon 404?
In essence, I want the URL mysite.com/foo to display the mysite.com view + the foo.html partial whether the URL is set by Angular or manually typed in the browser URL bar.
Yes you need something like mod_rewrite.
http://ericduran.io/2013/05/31/angular-html5Mode-with-yeoman/
In my web app I keep part of the pages fully rendered on the server side (to make them easily indexed by google) and some of the pages should be rendered partially with AngularJS. Rendering full pages is straightforward, however, I'm confused when I want to mix it with partially rendered pages.
The problem I see is how to make it possible to navigate from a fully rendered page to partially rendered? Let's say that I have a fully rendered page at the following url: fakedomain.com/products/all Now, I want to allow users to edit their profiles and this would be a partially rendered page (available at fakedomain.com/#/user/profile).
How should I do all the routing and rendering?
I mean, when user clicks the option to edit his/her profile should I render index.html where I have ui-view declared? If yes, how do I make sure that correct partial is used?
btw. I'm using NodeJS on the server side and I'm pretty new to the client side stuff.
You can use AngularJS html5 mode https://docs.angularjs.org/guide/$location which takes away the hashbang. Then you need to route all requests to your app to the index.html (which loads angularjs).
You need to add exceptions for your static pages routes on your nodeJS app or your webserver, so that the requests for the static pages get handled correctly.
That should work allright and keep it an integrated experience for your users.
In Javascript, what is the preferred way to validate if a GWT *.nocache.js file has loaded properly?
Background
My GWT application loads an *.nocache.js file within a simple shell .html page.
If a user visits the page with a stale auth cookie, the .html file loads perfectly from browser cache, but the *.nocache.js file fails to load, because the user needs a fresh auth token.
Since the .js file fails to load, it fails silently. The user sees a blank .html page with no indication that they need to refresh the page.
(note the particular failure here is that the .js file does not load due to wrong mime type. The auth layer handles stale auth cookies by redirecting to the login page. This page is a text/html document so the browser rejects loading it in a tag. Assume for this question that I cannot change this behavior in the application :)
What's the best way to detect this circumstance and, for example, force a refresh of the page.
Note a hard refresh will force a fetch of the .html page from the server, which will be redirect to the login.
One approach would be to tell the browser to not cache the .html file, but I'd prefer another solution that lets the .html file be cached.
Given that you cannot change things in your application, I will answer just to your question.
You need some javascript in your page.html in order to check whether the gwt script has been loaded after a fixed time:
<head>
<script>
setTimeout(function() {
if (!document.getElementById("my_module_name")) {
window.location.reload();
}
}, 4000)
</script>
<script language="javascript" src="my_module_name.nocache.js"></script>
</head>
In the case you use an iframe based linker (standard, xsiframe), the .nocache.js creates an iframe to load the appropriate permutation, and gives it the name of the module, so checking for the presence of that element after a while is enough to know whether the app was loaded.
You could also check for the presence of especial properties which gwt sets to the window like window.__gwt_activeModules
Typically, a GWT app loads first, then you do authentication. You can use a split point, if you want, to load only the login page. Then, after the authentication is confirmed, you load the other parts of your app.
I have never seen a scenario where authentication is done before a page loads. Maybe you can explain why you did it this way.
As for your question, you need a JavaScript to detect if another JavaScript was successfully loaded, but this solution adds an unnecessary level of complexity.
I have a web service that works through giving users javascript to embed in their code. Users can also place that code on other sites to make it work there. However I also need to allow users to create a blacklist of sites that the JS should not function on. For example, a competitor or an inappropriate site.
Is there a way to check where our JS files are being loaded from, and block loading or break functionality on a per account basis?
Edit: The javascript loads an iframe on the site, so another solution would be to somehow block certain domains from loading an iframe from our server, or serve different content to that iframe
Edit 2: We're also trying to avoid doing this from with the JS because it could be downloaded and modified to get pass the block
Inspecting the url of the page
Yes, the javascript file, when it starts executing, can inspect window.url and see if the url of the main document is ok.
To see where the script was loaded from
It can also go through the dom, looking for the script node which brought in the javascript file itself and see from where the JS was loaded.
However
Anyone can load the javascript into a text editor, then change it to eliminate the tests, then host the modified JS on their own server. Obfuscating or minimizing the JS can slow someone down but obscurity is not security.
One thing you could do is have the javascript load another javascript file. That you serve from the server at a given url. The trick here is that that url will not go to a file but to a server end point that will return a javascript file. The you have that endpoint check for the routes for that user and decide if it will return the javascript you want to work or an error javascript of some kind.
This blog shows how to do it in php.dynamic-javascript-with-php