Hello i am new to AngularJS, i have done my research and i know redirecting to a sub domain will cause the page to refresh. What i want to know is how to check what the sub domain is when a link is clicked and load the right view and controller.
I use wildcard sub domains but i basically have three of them right now:
administrator.example.com
manager.example.com
employee.example.com
Each sub-domain should redirect you to their respective dashboard view and controllers.
The main url however example.com shall direct you to the website itself.
I have set-up my states like this:
app
app.administrator
app.administrator.dashboard
app.manager
app.manager.dashboard
app.employee
app.employee.dashboard
Here i am going to give you standard solution to your problem. You should create a separate application for each subdomain. I have created a sample application to demonstrate the flow.
Index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script data-require="jquery#2.0.0" data-semver="2.0.0" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<link data-require="bootstrap#3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script data-require="bootstrap#3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.3/angular.js" data-semver="1.4.3"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<script src="app.js"></script>
<script src="app.manager.js"></script>
</head>
<body>
<load-application></load-application>
</body>
</html>
app.js
/**
* #name app
*
* Lets create angular application module
* if second parameter is passed with enpty array [] or with dependecies , is * called angular module setter
*
* angular.module('app', []); Setter
* angular.module('app'); Getter
*/
angular
.module('app', ['appLoader']);
/**
* app.administrator application for aministrator subdomain
*/
angular
.module('app.administrator', ['ui.router']);
/**
* app.employee application for employee subdomain
*/
angular
.module('app.employee', ['ui.router']);
/**
* Lets create a application loader
* This component is going to load sub domain specific application
*/
angular
.module('appLoader', ['app.administrator', 'app.manager', 'app.employee'])
.directive("loadApplication", ['$location', function($location) {
function getDomain() {
console.log($location.host());
//get domain name here
return 'manager';
}
return {
restrict: 'E',
controller: function($scope, $element, $attrs, $transclude) {},
template: function() {
var domainName = getDomain(),
templateName = '';
switch (domainName) {
case 'manager':
templateName = '<app-manager></app-manager>';
break;
case 'employee':
templateName = '<app-employee></app-employee>';
break;
case 'administrator':
templateName = '<app-administrator></app-administrator>';
break;
}
return templateName;
},
link: function($scope, element, attrs) {
console.info('loader application');
}
};
}]);
angular
.module('app.administrator')
.directive("appAdministrator", ['$location', function($location) {
return {
restrict: 'E',
template: '<h2>{{applicationName}}</h2>',
link: function($scope, element, attrs) {
$scope.applicationName = 'Application Administrator';
}
};
}]);
angular
.module('app.employee')
.directive("appEmployee", ['$location', function($location) {
return {
restrict: 'E',
template: '<h2>{{applicationName}}</h2>',
link: function($scope, element, attrs) {
$scope.applicationName = 'Application Employee';
}
};
}]);
app.manager.js
angular
.module('app.manager', ['ui.router']);
angular
.module('app.manager')
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider
.state('index', {
url: '/',
template: '<ul><li><a ng-href="#" ui-sref="demopage1">Demo page 1</a></li><li><a ng-href="#" ui-sref="demopage2">Demo page 2</a></li></ul>'
})
.state('demopage1', {
url: '/demopage1',
template: '<ul><li><a ng-href="#" ui-sref="demopage1">Demo page 1</a></li></ul>'
})
.state('demopage2', {
url: '/demopage2',
template: '<ul><li><a ng-href="#" ui-sref="demopage1">Demo page 1</a></li></ul>'
})
});
angular
.module('app.manager')
.directive("appManager", ['$location', function($location) {
return {
restrict: 'E',
template: '<h2>{{applicationName}}</h2><div ui-view></div>',
link: function($scope, element, attrs) {
$scope.applicationName = 'Application Manager';
}
};
}]);
Working plunker is here
I have created 3 applications for three domains , each application works independently. I have implemented the UI routes in app.manager application. You can implement the same in rest applications.
Lets me know if you have any concern ?
If you haven't started using the routing module called ui.router in your angular-based app, I suggest you read it here. I believe it is much more powerful than the ngRoute module native in Angular 1.x.
From my understanding your subdomain, I think you can arrange them as nested domains (or to be more precise, states) under 'app'. If the root url of your 'app' is something like '/main/', then the subdomains will inherit that root url and take the form such as '/main/administrator' and '/main/administrator/dashboard'
Each state (including nested states) can have its own controller, in which you can use the $state service in ui.router to get the state name (or subdomain name as you said) by calling: $state.$current.name
I hope this helps
As an example from my previous work. Here the main app has the url '/webapp', and the rest of the states are nested states that have their url started with '/webapp', e.g. for the state 'home.blogs', its url is '/webapp/blogs'. If it's still confusing, I suggest you spend some time reading the documentation on ui.router at Github.
angular
.module('blogFrontendApp', [
'ui.router'
])
config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/webapp/blogs');
$stateProvider.state('home', {
// abstract: true,
url: '/webapp',
views: {
'' : {
templateUrl: 'views/main.html'
},
'rightPanel#home' : {
templateUrl: 'views/rightPanel.html'
},
'mainContent#home' : {
templateUrl: 'views/mainContent.html'
}
}
})
.state('home.blogs', {
//to be shown in mainContent#home
url: '/blogs',
templateUrl: 'views/home_blogs.html'
})
.state('home.singleBlog', {
url: '/blog/:blogId/:blogTitle',
templateUrl: 'views/single_blog.html',
controller: 'blogArticleController as currentBlogView',
resolve: {
BlogService : 'BlogService',
blogObj : function(BlogService, $stateParams) {
return BlogService.getBlogById($stateParams.blogId);
}
}
})
.state('home.blogListInCategory', {
url: '/blogs/category/:categoryId',
templateUrl: 'views/blog_list_in_category.html',
controller: 'blogListController as blogListView'
})
.state('home.publishBlog', {
url: '/blogs/:categoryId/new',
templateUrl: 'views/publish_blog.html',
controller: 'blogListController as writeBlogView'
})
}
Related
I'm very new to Angular.js.
I've taken the necessary elements from this tutorial on modal windows within Angular.js: http://jasonwatmore.com/post/2016/07/13/angularjs-custom-modal-example-tutorial
Isolated, I can get this code to work, but after porting it to my website, I just can't get it to work.
In Jason's code, he has a file called index.controller.js, and although I've ported this file to my own page, I don't believe it's firing. Here's index.controller.js:
(function () {
angular
.module('app')
.controller('Home.IndexController', Controller);
function Controller(ModalService) {
var vm = this;
vm.openModal = openModal;
vm.closeModal = closeModal;
function openModal(id){
ModalService.Open(id);
}
function closeModal(id){
ModalService.Close(id);
}
}
})();
On my own page, I have all the controllers contained within app.js. Here's how it's laid out:
var app = angular.module('app', ['ngRoute', 'ui.router']);
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.hashPrefix('');
$urlRouterProvider.otherwise("/");
$stateProvider
.state('home', {
url: '/',
templateUrl: 'pages/main.html',
controller: 'mainController',
controllerAs: 'vm'
})
.state('screenings', {
url: '/screenings',
templateUrl: 'pages/screenings.php',
controller: 'Home.IndexController',
controllerAs: 'vm'
})
...
});
You can see that, in the second .state, I'm attempting to call on the index.controller.js file for this particular partial. For some reason, though, the code under screeningsController (down below) is the code that's firing.
Further down in the same app.js file, I have my controllers:
...
app.controller('screeningsController', ['$scope', '$log', function($scope, $log){
$scope.popup = function() {
// assign a message to the $scope
$scope.message = 'Hello World!';
// use the $log service to output the message in a console
$log.log($scope.message);
};
}]);
...
Is there any way I can somehow integrate what's in the index.controller.js file into my screeningsController in the app.js? I've been trying to get a modal window working on my site for about a week now. Any help is much appreciated.
Start by creating a controller with identifier Home.IndexController. Based on the route configuration this will instantiate when you navigate to "/screenings". Call the popup() function attached to $scope of Home.IndexController via a directive us ng-click for testing. As you have specified controllerAs make sure to reference controller properties and methods prefixed with vm..
You do not need both index.controller.js and app.js both loaded. It looks everything you'd need is defined in app.js, so just make sure that is being loaded in your application. Eventually you'd want to separate these into different files and/or modules as necessary.
Try the following:
Configuration:
var app = angular.module('app', ['ngRoute', 'ui.router']);
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.hashPrefix('');
$urlRouterProvider.otherwise("/");
$stateProvider
.state('home', {
url: '/',
templateUrl: 'pages/main.html',
controller: 'mainController',
controllerAs: 'vm'
})
.state('screenings', {
url: '/screenings',
templateUrl: 'pages/screenings.php',
controller: 'Home.IndexController',
controllerAs: 'vm'
});
...
});
Home.IndexController:
app.controller('Home.IndexController', ['$log', function($log){
var vm = this;
vm.message = '';
vm.popup = function() {
vm.message = 'foobar';
$log.log(vm.message);
}
}]);
Screenings Template:
<!-- Home.IndexController /screenings template -->
<div>
<button type="button" ng-click="vm.popup()"></button>
</div>
This also assumes you have ui-view specified somewhere in your main template like index.html or equivalent:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
</head>
<body ng-app="app">
<div ui-view></div>
<!-- Vendor and Custom scripts added here -->
</body>
</html>
I am using angular ui-router for an application, but for some reason the nested views are loaded only for desktop browsers and Chrome for android but not for other mobile browsers such as chrome for iPhone, Samsung Browser for android, Safari for iPhone.I have been searching but I could not find any reasons why it behaves like that, I don't know if maybe the configuration of my "states" and templates are not correct.
and this is my code:
$urlRouterProvider.otherwise(function ($injector) {
var $state = $injector.get('$state');
var $rootScope = $injector.get('$rootScope');
var $stateParams = $injector.get('$stateParams');
if (typeof $stateParams.token == 'undefined') {
$rootScope.errorList = [];
$rootScope.errorList.push("Token is invalid");
$state.go('error');
}
});
$stateProvider
.state('index',
{
url: '/:token/',
views: {
'': {
templateUrl: 'AngularJS/Templates/indexView.html',
controller: 'candidateController as candCtrl'
},
'sectioncandidate#index': {
templateUrl: 'AngularJS/Templates/candidatesView.html'
}
}
})
.state('error',
{
url: '/error',
templateUrl: 'AngularJS/Templates/errorView.html',
controller: 'errorController as errorCtrl'
})
.state('index.details', {
url: 'details',
views: {
'sectioncandidate#index': {
templateUrl: 'AngularJS/Templates/candidateView.html'
}
}
});
The templates have the following hierarchy:
index.cshtml
<div class="main-container" ui-view></div>
indexView.html
<h3 class="header-title">This is the header from the parent view</h3>
<div class="body-content">
<div ui-view="sectioncandidate"></div>
</div>
candidatesView.html
<h1>This is the nested view!!!!</h1>
And i am loading the following libraries
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular-route.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular-aria.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular-animate.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular-messages.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.9/angular-material.js"></script>
<script src="~/AngularJS/Modules/app.js"></script>
<script src="~/AngularJS/Services/applicationService.js"></script>
<script src="~/AngularJS/Controllers/candidateContoller.js"></script>
<script src="~/AngularJS/Controllers/errorController.js"></script>
I would really appreciate any help.
You Can Try On When Method
var app = angular.module('Appname',['ngRoute']);
app.config(function($routeProvider){
$routeProvider.when('/',{
templateUrl :"1st Path Of File",
controller :"FirstController"
})
.when('/AnchortagIdHere',{
templateUrl :"2nd Path Of File",
controller :"2ndController"
})
.otherwise('/',{
templateUrl :"1st Path Of File",
controller :"FirstController"
});
});
Well, after the application was dissected line by line I could realize that the issue with the nested views were not exactly because of the ui-router component, the problem was that the controller used by the nested views was using an angular material dialog. The way these angular material dialog link a controller and a template, was creating a conflict for some mobile browsers, therefore the nested, named views were not displayed.
This fixed the problem:
Before I was using a code like this to pen a dialog: (it is supposed to work with es6)
this.$mdDialog.show({
targetEvent: event,
templateUrl: 'path/mytemplate.html',
controller: () => this,
controllerAs: 'ctrl'
});
I changed for something like this: (the way to link a controller Without es6)
var self = this;
this.showTabDialog = function(ev) {
$mdDialog.show({
controller: function () {
return self;
},
controllerAs: 'ctrl',
templateUrl: 'tabDialog.tmpl.html',
});
};
hope it could be useful for someone.
I have page with ng-view. This page is generated by php following URL: www.sbt.com/profile
What url I need to set in href attribute, that will work Angular JS by url:
www.sbt.com/profile/privacy/1
I tried:
.when('/profile/:page/:type', {}
And link like as:
Go
But it does reload page at url when I click to link in page /profle:
www.sbt.com/#/profile/personal/1
Full code is:
.config(function ($locationProvider, $routeProvider) {
$routeProvider
.when('/profile/:page/:account', {
templateUrl: function(params) {
return '/public/html/personal.html';
},
controller: 'EditProfileController'
})
/* Chat */
.when('/chat/dialog/:id', {
controller: 'ChatController'
});
})
If your angular application is served from the page with base URL like /profile then links should look like:
Go
and route configuration should be
.when('/:page/:account', {
templateUrl: function(params) {
return '/public/html/personal.html';
},
controller: 'EditProfileController'
});
Also make sure you define base href (although it should work without it too in your case). Put this script in the <head> of the page:
<script>
document.write('<base href="' + document.location + '" />');
</script>
Any ideas how to build solution, that helps generate url in view in more convenient way, instead of hard-coding like that:
<a ng-href="#/Book/{{item.bookId}}/ch/{{item.id}}">Chapter {{item.id}}</a>
I want to use:
<a chapters="[item.bookId, item.id]">Chapter {{item.id}}</a>
So it checks routes and generates for each route specific directive.
I'm interested in the most generic solution as possible.
I would highly recommend you make use of ui-router, and its $stateProvider.
var app = angular.module('yourModuleName', ['ui.router']);
app.config(function ($stateProvider) {
$stateProvider
.state('book', {
url: '/Book/:bookId'
})
.state('book.chapter', {
url: '/ch/:id'
});
});
<a ui-sref="book.chapter({bookId: item.bookId, id: item.id})">Chapter {{item.id}}</a>
Something along those lines should do the trick. I'm not at all familiar with the other parameters of your application, but building dynamic URL's with passed in parameters to match up with a $state is a breeze.
ui-router: https://github.com/angular-ui/ui-router
ui-sref (directive): https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
First of all you can use Angular-UI
Angular-UI/UI-Router
The main idea in there is to have states because you have single page app and everything are just state who renders in single place. No refresh nothing.
When integrating it you can create
$stateProvider
.state("bookPreview", {
url: "/book/:id/:itemId",
controller: "BookPreviewCtrl",
templateUrl: 'sb/add-cpe-template.tpl.html'
});
In your html you can do the following thing:
<button ng-click="view(item.bookId, item.id)">Chapter {{item.id}}</button>
or something like that, you can assign ng-click on hyperlinks as well.
The java script view function is:(but before you must inject $
controller("BookSelectionCtrl",function($scope,$state){
//this will rewrite the url , go to the state and load the template(view).
$scope.view=function(bookId,itemId){
$state.go("bookPreview",{id:bookId,itemId:itemId}) //there is a third object representing options, which are optional and you can check them on doc site
}
})
controller("BookPreviewCtrl",function($scope,$stateParams){
//in this new ctrl of the new view you can now do what ever you want with these params
$scope.bookId = $stateParams.id;
$scope.itemId = $stateParams.itemId;
})
You need to loop over all routes and build directives dynamically, here is a start http://plnkr.co/edit/d592a58CMan5BVKQYSAy?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$route) {
var keys = [];
for(var k in $route.routes) keys.push(k);
$scope.name = keys;
for (var i=0; i<keys.length; ++i) {
app.directive('SomethingDynamic', function() {
return {
restrict: 'A',
replace: true,
template: '....',
};
});
}
});
app.config(function ($routeProvider) {
$routeProvider.
when('/complex/:name/:color/:number/extra', {
templateUrl: "404.html",
name:'complex'
}).
when('/objects', {
templateUrl: "404.html",
name:'list'
}).
when('/object/detail/:id', {
templateUrl: "404.html",
name:'detail'
});
});
Or you can create directive (jsbin):
View:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-app="app">
<div ng-controller="mainCtrl">
<book-link book="book" ng-repeat="book in books"></book-link>
</div>
</body>
</html>
JS:
var app = angular.module("app",[])
.controller("mainCtrl", function($scope){
var books = [
{bookId : "book1", id:"1" },
{bookId : "book1", id:"2" },
{bookId : "book1", id:"3" }
];
$scope.books = books;
})
.directive("bookLink",function(){
return {
restrict:"E",
scope:{book:'='},
template:"<a href='/book/{{book.bookId}}/ch/{{book.id}}'>Chapter {{book.id}}</a><br/>"
};
});
Does angular support dynamic routing at all?
Maybe some trick like this:
$routeProvider.when('/:ctrl/:action',
getRoute($routeParams.ctrl,$routeParams.action))
function getRoute(ctrl, action){
return {
templateUrl: ctrl+"-"+action+".html"
controller: 'myCtrl'
}
}
Please help me, I need to get templateUrl based out of routeParams
This is a late answer but I came across this problem myself, but it turns out that the solution by Dan conflicts with ngAnimate classes on the ngView directive, and the view is shown but the ng-leave animation will immediately be applied and hide the view opened with his dynamic routing.
I found the perfect solution here, and it's available in 1.1.5 +
In the $routeProvider, the templateUrl value can be a function, and is passed the route parameters:
app.config(function ($routeProvider) {
$routeProvider
.when('/:page', {
templateUrl: function(routeParams){
return '/partials/'+routeParams.page+'.html';
}
})
});
Though the controller can't be given as a function so my solution is to give it in the template html as per usual with ng-controller="HomeCtrl".
Using this solution we can route by convention in Angular.
I hope this helps others who weren't keen on manually adding every route to the routeProvider.
You want to bring it down to the controller level.
In this example, I am overriding entire pages as well as partials by subdomain:
app.js
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/', {
template: 'home'
});
$routeProvider.when('/contact', {
template: 'contact'
});
$routeProvider.otherwise({redirectTo: '/'});
}])
controllers.js
controller('AppController', ['$scope','Views', function($scope, Views) {
$scope.$on("$routeChangeSuccess",function( $currentRoute, $previousRoute ){
$scope.page = Views.returnView();
});
$scope.returnView = function(partial){
return Views.returnView(partial);
}
}])
services.js
factory('Views', function($location,$route,$routeParams,objExistsFilter) {
var viewsService = {};
var views = {
subdomain1:{
'home':'/views/subdomain1/home.html'
},
subdomain2:{
},
'global.header':'/views/global.header.html',
'global.footer':'/views/global.footer.html',
'home':'/views/home.html',
'home.carousel':'/views/home.carousel.html',
'contact':'/views/contact.html',
};
viewsService.returnView = function(partial) {
var y = (typeof partial === 'undefined')?$route.current.template:partial;
var x = $location.host().split(".");
return (x.length>2)?(objExistsFilter(views[x[0]][y]))?views[x[0]][y]:views[y]:views[y];
};
viewsService.returnViews = function() {
return views;
};
return viewsService;
}).
filters.js
filter('objExists', function () {
return function (property) {
try {
return property;
} catch (err) {
return null
}
};
});
index.html
<!doctype html>
<html lang="en" ng-controller="AppController">
<body>
<ng-include src="returnView('global.header')"></ng-include>
<ng-include src="page"></ng-include>
<ng-include src="returnView('global.footer')"></ng-include>
</body>
</html>