I need to create a web app that can handle different template (same class but with addition field/functions). I use AngularJS.
For all the css side, I use SASS.
For the HTML part, I use ng-include of AngularJS.
But I don't know what to use for the JS part. I could have the same js file for each template with all the changes but if there a change I would need to change all the files. What I look for is a framework/tool that allow me to have a base js file and load inside extra content from other file (like ng-include in AngularJS).
Thanks in advance
I think that you a looking for ngRoute or ui-router. They are components that let you create routes in you application. It means that you can define one route that contains a HTML file and a Controller associated.
Take a look at the documentation of the two.
This is an example using ngRoute: https://jsfiddle.net/relferreira/t36xa01c/
HTML:
<div data-ng-app="app">
<ul class="nav navbar-nav" id="subject">
<li>Main</li>
<li>Detail</li>
</ul>
<div ng-view></div>
</div>
JS:
angular.module('app', ['ngRoute']);
angular.module('app')
.config(config)
.controller('MainController', mainController)
.controller('DetailController', detailController);
config.$inject = ['$routeProvider'];
function config($routeProvider){
$routeProvider.when('/',{
template:'<h1>{{mainVm.title}}</h1>',
controller: 'MainController as mainVm'
})
.when('/detail',{
template:'<h1>{{detailVm.title}}</h1>',
controller: 'DetailController as detailVm'
})
.otherwise({
redirectTo:"/"
});
}
mainController.$inject = ['$scope'];
function mainController($scope){
var vm = this;
vm.title = 'Main'
}
detailController.$inject = ['$scope'];
function detailController($scope){
var vm = this;
vm.title = 'Detail'
}
How to load content on page by clicking on menu links?
For example, there is menu:
Personal
Contacts
Question is in how change template HTML in page for each link?
Basically what you are trying to achieve will be accomplish by creating SPA. For that you need to use ngRoute module in your application(by adding angular-route.js)
For setting up angular router you need to register routes with there template & controller, etc. inside app.config.$routeProvider would take a URL by .when method.
Code
var app= angular.module('app', ['ngRoute']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/tab/:id', {
templateUrl: 'template.html',
controller: 'templateController'
}).
otherwise({
redirectTo: '/tab/1'
});
}]);
& then there would be one section on UI which is nothing but ng-view directive that watches of $routeProvider configuration with url in browser bar
<ng-view></ng-view>
For more details look at this answer
Working Example Plunkr
Additional to #pankaj, You have to use $location services in your controller. So that you can change view accordingly from controller.
ex. You have link
<a ng-click="saveData">Save</a>
Now in controller:
$scope.saveData = function(){
$location.href('viewName');
}
ref : https://docs.angularjs.org/api/ng/service/$location
Is it possible to css animate a div (background-color) that is outside the ng-view, using a directive on a $state inside the ng-view?
The ng-view has css animations for the routing.
If I do not animate the div then the ng-view anims work fine, but..
If I add animation classes to the div(bgId) then the routing anims do not fire.
Here is a sample of html: (Button added as example - would normally be in the template pages eg. home.html / login.html )
<body ng-app="app" ng-controller="MainCtrl">
<div id="bgId" class="{{colorVal}}">
<ion-nav-view animation="slide-left-right">
</ion-nav-view>
</div>
<button swapcolour="changeColour()" data-nxtpage="1">change colour</button>
</body>
This is controlled by a directive(swapcolour) that gets the nxtpage value from the button attr and updates the colorVal in MainCtrl.
//MainCtrl.js
.controller('MainCtrl', ['$scope', '$state', function($scope, $state) {
$scope.colorVal = 'redBg';
}])
//Directive.js
.directive('swapcolour', function ($rootScope, $state) {
var pageArr = [{home:'redBg'},{login:'blueBg'}];
return function (scope, element, attrs) {
var nextPageNum = attrs.nxtpage;
var obj = pageArr[nextPageNum];
var item = Object.keys(obj);
var objItem = obj[item];
element.bind('click', function () {
$state.transitionTo(item[0]);
$rootScope.$$childHead.colorVal = objItem;
});
}
}])
I do not know why it fails. Any ideas?? I am new to directives. (Trying to setup a plunker, but having issues getting ionic working with it)
I fixed it! - I think.
Basically after totally stripping the application to its bones I managed to build a plunker and got it working.
There was nothing wrong with my code after all.
<body ng-app="app" ng-controller="MainCtrl">
<div id="bgId" class="{{colorVal}}">
<ion-nav-view animation="slide-left-right">
</ion-nav-view>
</div>
</body>
http://plnkr.co/edit/Oug8zD?p=preview
Then I tried this code on my app - and it still did not work! So I tried replacing my ionic.bundle.js and ionic.css files (orig installed using npm) with the files used in the plunker (1.0.0-rc.1) and my app worked :)
Hope this helps others in trouble in the future.
I'm using Angular JS to dynamically load content like so:
HTML
...
<div ng-controller="MainController">
<div ng-view></div>
</div>
</html>
Angular
(function(){
var app = angular.module('app', ['ngRoute', 'ngAnimate']);
app.config(function($routeProvider) {
$routeProvider.when('/test', {
templateUrl : 'views/test.html',
controller : 'MainController'
});
});
app.controller('MainController', function($scope){ });
})();
This works as expected. However, inside the file test.html I have some links with the href="#" that need to be handled with javascript to do various things. At the moment, Angular is interpreting them with it's routing method and treats them as links to the homepage. How do I stop this and treat the links the way I want?
Example test.html content:
Left
Right
<p>Test content</p>
In a JS file separate from Angular I tried:
$('.slideLeft').on('click',function(){
return false;
});
But it doesn't do the return false, it uses the Angular routing.
You should be using Angular for all your bindings including event bindings. Don't use .on('click'), use ng-click (or .bind if you really need it, but you probably don't).
You can also see from the docs that the <a> directive does nothing if href is empty. Use href="" rather than href="#"
Use href="javascript:void(0)" in anchor attribute and also you should use ngClick instead of binding element using jQuery.
My question involves how to go about dealing with complex nesting of templates (also called partials) in an AngularJS application.
The best way to describe my situation is with an image I created:
As you can see this has the potential to be a fairly complex application with lots of nested models.
The application is single-page, so it loads an index.html that contains a div element in the DOM with the ng-view attribute.
For circle 1, You see that there is a Primary navigation that loads the appropriate templates into the ng-view. I'm doing this by passing $routeParams to the main app module. Here is an example of what's in my app:
angular.module('myApp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when("/job/:jobId/zones/:zoneId", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/zone_edit.html' }).
when("/job/:jobId/initial_inspection", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/initial_inspection.html' }).
when("/job/:jobId/zones/:zoneId/rooms/:roomId", { controller: JobDetailController, templateUrl: 'assets/job_list_app/templates/room_edit.html' })
}]);
In circle 2, the template that is loaded into the ng-view has an additional sub-navigation. This sub-nav then needs to load templates into the area below it - but since ng-view is already being used, I'm not sure how to go about doing this.
I know that I can include additional templates within the 1st template, but these templates are all going to be pretty complex. I would like to keep all the templates separate in order to make the application easier to update and not have a dependency on the parent template having to be loaded in order to access its children.
In circle 3, you can see things get even more complex. There is the potential that the sub-navigation templates will have a 2nd sub-navigation that will need to load its own templates as well into the area in circle 4
How does one go about structuring an AngularJS app to deal with such complex nesting of templates while keeping them all separate from one another?
UPDATE: Check out AngularUI's new project to address this problem
For subsections it's as easy as leveraging strings in ng-include:
<ul id="subNav">
<li><a ng-click="subPage='section1/subpage1.htm'">Sub Page 1</a></li>
<li><a ng-click="subPage='section1/subpage2.htm'">Sub Page 2</a></li>
<li><a ng-click="subPage='section1/subpage3.htm'">Sub Page 3</a></li>
</ul>
<ng-include src="subPage"></ng-include>
Or you can create an object in case you have links to sub pages all over the place:
$scope.pages = { page1: 'section1/subpage1.htm', ... };
<ul id="subNav">
<li><a ng-click="subPage='page1'">Sub Page 1</a></li>
<li><a ng-click="subPage='page2'">Sub Page 2</a></li>
<li><a ng-click="subPage='page3'">Sub Page 3</a></li>
</ul>
<ng-include src="pages[subPage]"></ng-include>
Or you can even use $routeParams
$routeProvider.when('/home', ...);
$routeProvider.when('/home/:tab', ...);
$scope.params = $routeParams;
<ul id="subNav">
<li>Sub Page 1</li>
<li>Sub Page 2</li>
<li>Sub Page 3</li>
</ul>
<ng-include src=" '/home/' + tab + '.html' "></ng-include>
You can also put an ng-controller at the top-most level of each partial
Well, since you can currently only have one ngView directive... I use nested directive controls. This allows you to set up templating and inherit (or isolate) scopes among them. Outside of that I use ng-switch or even just ng-show to choose which controls I'm displaying based on what's coming in from $routeParams.
EDIT Here's some example pseudo-code to give you an idea of what I'm talking about. With a nested sub navigation.
Here's the main app page
<!-- primary nav -->
Page 1
Page 2
Page 3
<!-- display the view -->
<div ng-view>
</div>
Directive for the sub navigation
app.directive('mySubNav', function(){
return {
restrict: 'E',
scope: {
current: '=current'
},
templateUrl: 'mySubNav.html',
controller: function($scope) {
}
};
});
template for the sub navigation
Sub Item 1
Sub Item 2
Sub Item 3
template for a main page (from primary nav)
<my-sub-nav current="sub"></my-sub-nav>
<ng-switch on="sub">
<div ng-switch-when="1">
<my-sub-area1></my-sub-area>
</div>
<div ng-switch-when="2">
<my-sub-area2></my-sub-area>
</div>
<div ng-switch-when="3">
<my-sub-area3></my-sub-area>
</div>
</ng-switch>
Controller for a main page. (from the primary nav)
app.controller('page1Ctrl', function($scope, $routeParams) {
$scope.sub = $routeParams.sub;
});
Directive for a Sub Area
app.directive('mySubArea1', function(){
return {
restrict: 'E',
templateUrl: 'mySubArea1.html',
controller: function($scope) {
//controller for your sub area.
}
};
});
You may checkout this library for the same purpose also:
http://angular-route-segment.com
It looks like what you are looking for, and it is much simpler to use than ui-router. From the demo site:
JS:
$routeSegmentProvider.
when('/section1', 's1.home').
when('/section1/:id', 's1.itemInfo.overview').
when('/section2', 's2').
segment('s1', {
templateUrl: 'templates/section1.html',
controller: MainCtrl}).
within().
segment('home', {
templateUrl: 'templates/section1/home.html'}).
segment('itemInfo', {
templateUrl: 'templates/section1/item.html',
controller: Section1ItemCtrl,
dependencies: ['id']}).
within().
segment('overview', {
templateUrl: 'templates/section1/item/overview.html'}).
Top-level HTML:
<ul>
<li ng-class="{active: $routeSegment.startsWith('s1')}">
Section 1
</li>
<li ng-class="{active: $routeSegment.startsWith('s2')}">
Section 2
</li>
</ul>
<div id="contents" app-view-segment="0"></div>
Nested HTML:
<h4>Section 1</h4>
Section 1 contents.
<div app-view-segment="1"></div>
I too was struggling with nested views in Angular.
Once I got a hold of ui-router I knew I was never going back to angular default routing functionality.
Here is an example application that uses multiple levels of views nesting
app.config(function ($stateProvider, $urlRouterProvider,$httpProvider) {
// navigate to view1 view by default
$urlRouterProvider.otherwise("/view1");
$stateProvider
.state('view1', {
url: '/view1',
templateUrl: 'partials/view1.html',
controller: 'view1.MainController'
})
.state('view1.nestedViews', {
url: '/view1',
views: {
'childView1': { templateUrl: 'partials/view1.childView1.html' , controller: 'childView1Ctrl'},
'childView2': { templateUrl: 'partials/view1.childView2.html', controller: 'childView2Ctrl' },
'childView3': { templateUrl: 'partials/view1.childView3.html', controller: 'childView3Ctrl' }
}
})
.state('view2', {
url: '/view2',
})
.state('view3', {
url: '/view3',
})
.state('view4', {
url: '/view4',
});
});
As it can be seen there are 4 main views (view1,view2,view3,view4) and view1 has 3 child views.
You may use ng-include to avoid using nested ng-views.
http://docs.angularjs.org/api/ng/directive/ngInclude
http://plnkr.co/edit/ngdoc:example-example39#snapshot?p=preview
My index page I use ng-view. Then on my sub pages which I need to have nested frames. I use ng-include.
The demo shows a dropdown. I replaced mine with a link ng-click.
In the function I would put $scope.template = $scope.templates[0]; or $scope.template = $scope.templates[1];
$scope.clickToSomePage= function(){
$scope.template = $scope.templates[0];
};
Angular ui-router supports nested views. I haven't used it yet but looks very promising.
http://angular-ui.github.io/ui-router/