Angular best practice for writing links (path, href) with html5 mode - javascript

I am looking for best practices to write links and paths in Angular 1.5.
Given the following configuration:
angular.module('my-app', ['ngRoute'])
.config(function ($locationProvider) {
$locationProvider.html5Mode({enabled: true});
});
This does not work when I have a base ref in the html document:
<html>
<head>
<base href="/my-app/"/>
...
</head>
<body>
<a ng-href="/my-section">My section</a>
</body>
</html>
Clicking the link put me at the absolute url /my-section, which does not exists. The same goes for the location service:
$location.path('/my-section') // Change my url at /my-section, not /my-app/my-section
It is easily fixed by replacing all my links with relative ones which has the effect or redirecting me to /my-app/my-section accordingly:
<a ng-href="my-section">My section</a>
$location.path('my-section')
However, according to the documentation of $location service:
Path should always begin with forward slash (/), this method will add
the forward slash if it is missing. https://docs.angularjs.org/api/ng/service/$location
This is basically telling me that the recommendations are to start all links with forward slash. How this is possible in my case ?

I think you should give only '/' as base href, if your app index looks like 'http://example.com/'.
If your index url looks like 'http://example.com/my-app/' then base href value would be '/my-section'.
Actually, it depends on url of the index page. So, please go by this way :)

<html>
<head>
<base href="/"></base>
...
</head>
<body>
<a ng-href="my-app/my-section">My section</a>
</body>
</html>
Set base URL as forward slash

Related

Linkify.js.org (jQuery) HashTags: Change the default URL destination to Twitter?

I'm sanitizing CDATA content from various third-party XML feeds, stripping all HTML server-side and using Linkify.js.org (v3.0.3) to safely reapply HTML tags to the sanitized plaintext links client-side.
My project relies a lot on jQuery (v3.6.0).
The linkify jQuery DOM Data API is working great on links and email addresses, but hashtags are proving problematic. By default, hashtags redirect to https://my-domain.com/current-dir/#<HashTag>, but I'd like them to redirect to https://twitter.com/hashtag/<HashTag>. I know this is possible from the demo examples, but I'd like to stick with a jQuery solution, and maintain the div data attributes if possible.
I've read the documentation from Linkify.js.org/docs/ but can't figure out how to change the hashtag URL without dropping the jQuery div data attributes.
Below is a simple example (it's important I maintain a _blank HREF target):
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Linkify</title>
</head>
<body>
<div data-linkify="this" data-linkify-target="_blank">
Domain Test: domain.com. Email Test: email#address.com. HashTag Test: #Linkify.
</div>
<script src="/js/jquery.min.js"></script>
<script src="/js/linkify.min.js"></script>
<script src="/js/linkify-jquery.min.js"></script>
<script src="/js/linkify-plugin-hashtag.min.js"></script>
</body>
</html>
Work's great, but as mentioned, #Linkify redirects to the same page (e.g; https://my-domain.com/current-dir/#Linkify).
Client-side JS is not my strong point, but is there a data-linkify attribute I can use to change the HashTag destination to Twitter? Or additional jQuery code I can use to modify the behaviour of the linkify-plugin-hashtag.min.js plugin?
Use the hashtag plugin options... And since you do not want to call linkify directly, you'll need to play with the default options.
If you add this, it should work out.
linkify.options.defaults.formatHref.hashtag= (href) =>
'https://twitter.com/hashtag/' + href.substr(1);
You can read more at https://linkify.js.org/docs/plugin-hashtag.html and https://linkify.js.org/docs/options.html

How to update base relative URL in angularapp?

So I have an existing angular app which routes/imports (eg: href and src) from the root path only (ie: /). So the app loads up at http://localhost:8080/ and and the base url is /. I want to change it to be http://localhost:8080/myapp/ so all links will then prefixed with /myapp.
I tried updating this code here from (it's in a Java jsp called app.jps):
<head>
<base href="/" />
to
<head>
<base href="/myapp" />
But this did nothing, I still get errors like this (and others like it): angular.js:11630 GET http://localhost:8080/angularapp/home/home.html?version=4 404 ()
There are many other errors like this, and the page is just blank (white) so far. Do I have to go and piecemeal edit all these urls to include /myapp in front of it? OR is there a better way?
More info:
Template Urls look like this (in app.module.js):
$stateProvider
.state('home', {
url: '/',
templateUrl: '/angularapp/home/home.html?version=' + window.version,
controller: 'HomeCtrl',
controllerAs: 'vm'
})
It seems like you are missing the end slash.
<head>
<base href="/myapp/" />
Please update href to "/myapp/", that should work.
If you change your templateUrl to:
templateUrl: './angularapp/home/home.html?version=' + window.version,
it should take it as a relative path.
Try that and see what it gives you (assuming your base url already comes off http://localhost:8080/myapp/).

Not load a JS file for a specific path

I have a website by mean-stack.
Normally, all my external references are listed in index.html
I realize that one external JS library (e.g., https://cdnjs.cloudflare.com/troublelibrary.js) I am using has some conflit with a part of my website. So a workaround I am looking for is to NOT load it for a specific path https://www.myexample.com/specific.
Does anyone know how to achieve this in the routing?
Edit 1: (see the full question here)
Actually, the library that has conflit is history.js. My initial code which loads it all the time is as follows. As a result https://localhost:3000/home in a browser is always https://localhost:3000/home (i.e., will not add # because of history.js)
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
<script src="https://cdn.rawgit.com/devote/HTML5-History-API/master/history.js"></script>
Then, if I try the following code, as Ben suggests:
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>
<script>
var newScript = document.createElement('script');
newScript.src = 'https://cdn.rawgit.com/devote/HTML5-History-API/master/history.js';
document.head.appendChild(newScript);
console.log(window.location.href)
</script>
I realize that for the first time of loading https://localhost:3000/home will not change. But, if I refresh the browser, it can change to https://localhost:3000/#/home.
So appending the script is not exactly the same as a direct reference, does anyone know why?
I see your problem in a different perspective. You mentioned that you use the history.js to avoid # on the URL. But you do not need history.js to do that. I think you understood your problem in the wrong way. There is an inbuilt Angular functionality to get rid off # paths. Because # is used to keep track of the relative path on any route. If we want we can override that default functionality.
But if you use this approach the server should responsible to redirect the user to index or home page on any application route since Angular handle all the routing in the application.
First you should add
<base href="/" />
in your HTML file.
Then you should enable HTML5 Mode inside Angular application as follows.
$locationProvider.html5Mode(true);
By adding these two attributes you can get rid off the # path and this is the recommended way.
Following is a complete example.
var app = angular.module("app", ["ngRoute"]);
app.controller("MainController", function($scope){
});
//Add route handler
app.config(["$routeProvider", "$locationProvider", function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
template: '<h1>Home</h1>',
reloadOnSearch: true
})
.when('/about', {
template: '<h1>About</h1>',
reloadOnSearch: true
}).otherwise({
redirectTo: '/'
});
// This will remove hash bang from the routes
$locationProvider.html5Mode(true);
}]);
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular-route.js"></script>
<base href="/" />
</head>
<body>
<div>
Home
About
</div>
<div ng-app="app" ng-controller="MainController">
<ng-view></ng-view>
</div>
</body>
</html>
As you can see on the above example when you click on the about link the server responds with not found on /about. This means the # bang is removed.
This is one way to do it:
if(window.location.href !== 'https://url.com/path/to/trouble/page'){
var newScript = document.createElement('script');
newScript.src = 'https://url.com/path/to/script';
document.head.appendChild(newScript);
}
Add this to the <head> of the document. It will not load the trouble script on the page you specify in the if statement. Make sure not to load the trouble script anywhere else on the page as well.
you can do lazy loading of script in angular
<script type="text/javascript" ng-src="{{exUrl1}}"></script>
and somewhere in your code (based on whatever logic you want)
$rootScope.exUrl1 = $sce.trustAsResourceUrl(confserver.example.url);

Loading dynamic content based on hash or query string

I'm going to create a single page javascript application. It will load different page content based on the url being modified, either by the hash or the html history API depending on the browser.
My though was to use this plugin in order to have the hash fallback for older browsers.
var location = window.history.location || window.location;
handleUrlChange(location.href);
$(document).on('click', 'a.ajax', function(e) {
e.preventDefault();
history.pushState(null, null, this.href);
handleUrlChange(this.href);
});
$(window).on('popstate', function(e) {
handleUrlChange(location.href);
});
function handleUrlChange(url){
// example url: www.foo.com?page=details&id=1
var page = getQueryStringParam('page') || 'index';
$('#dynamic-content').load(page + '.html');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="header"></div>
<div id="dynamic-content"></div>
<div id="footer"></div>
</body>
</html>
My question is if there are any frameworks that already does this? I don't want to re-invent the wheel here.
There are plenty of solutions, like:
https://millermedeiros.github.io/crossroads.js/
http://stoodder.github.io/finchjs/
http://backbonejs.org/#Router
https://docs.angularjs.org/tutorial/step_07
You can choose what's fits you most. If you don't want to use backbone features like models or collections, or angular framework, and you need just routing, use crossroads.js or finch.js, or just type in google: "Javascript routing" to find other libraries.
Personally, I used only backbone routing.
http://backbonejs.org/#Router
It's easy to use, automatically checks if History API can be used, if not, it uses hash navigation.

Inject script for i18n in Angular app

I would like to use i18n and i10n in my Angular app.
If I understood correctly I can inject a script into my index.html and the changes regarding the language will change on the fly. I tested it and it works when I added manually the script and refresh the page.
Unfortunately, I am trying to inject the script for the right language on the fly.
I created a button and I want to add Portuguese language script on the click button.
app.controller('appController', ['$scope', '$route', 'UserTopBarWidget',
function($scope, $route, UserTopBarWidgetService){
$scope.topBarWidget = UserTopBarWidget;
$scope.topBarWidget.loadTopBarWidget();
}
}]);
In this file I just load the service I created called UserTopBarWidget.
The UserTopBarWidget:
app.service('UserTopBarWidgetService', function($http){
this.loadTopBarWidget = function(){
//loading something
};
this.loadPortugueseLanguage = function(){
var locale = "pt-pt";
$.getScript("https://code.angularjs.org/1.2.16/i18n/angular-locale_" + locale + ".js");
}
});
I have a page html called index.html and inject to it my html files:
index.html:
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="../common/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="../common/css/style.css" />
<title></title>
</head>
<body ng-controller="AppCtrl">
<div id="container" ng-view></div>
</body>
</html>
The injected html:
<button type="button" id="searchButton" class="btn btn-default" ng-click="topBarWidget.loadPortugueseLanguage()">Portugese</button>
<h2>{{date | date: 'fullDate' }}</h2>
<h2>{{money | currency}}</h2>
The answer I get :
Tuesday, June 10, 2014
$500.00
I would like to see it in Portuguese.
What am I doing wrong?
Question
There is no way in pure angular to dynamically change locale so far, you can only do it on bootstrap level but there is a few projects that implement this functionality. This one is particularly good IMHO
https://github.com/lgalfaso/angular-dynamic-locale
There are two possible solutions to your problem really.
One is to use angular-dynamic-locale as #maurycy already explained. It's not the cleanest solution I can think of, but it's better than nothing.
The other possible solution is to create your own using other specialized i18n library like iLib for example.
Why would you ever want to do that?
Well, built-in AngularJS i18n routines does not allow for handling other calendars, time zones and formatting percents. These are serious drawbacks. The fact, that you cannot override a Formatting Locale based on user profile (or you can, but forgot about web site caching) is another.
I recommend using custom iLib-based solution (I used to recommend Globalize but after recent changes it seems a bit useless) combined with angular-translate for User Interface translation and built-in angular-locale for handling plural forms (at the time of writing angular-translate does not handle it particularly well).

Categories

Resources