I am developing demo application to learn AngularJS. Few things troubling me.
1 - What is the difference between
<div ng-controller="Page2Ctrl">
</div>
and
when('/page2', {templateUrl: 'views/flow1/page2.html', controller: 'Page2Ctrl'}).
Asking this because either is working fine. Is it necessary to define ng-controller in Html even if controller is defined in Routes?
2 - What is the difference between
function Page4Ctrl($scope){
$scope.pageName = "Page 4 loaded."
}
And
app.controller('Page4Ctrl', function ($scope) {
$scope.pageName = "Page 4 loaded."
});
second is verbose and need extra typing. Any suggestion on using them?
3 - Suppose I am developing a CRUD application for Customer. I make a CustomerController.js file where I want to put all the methods related to Customer (Create, Read, Update, Delete, FindById, FindAll etc). like below. Is this the right approach or controller should be one CustomerController which contains all the methods of CRUD?
app.controller('CustomerCreateController', function ($scope) {});
app.controller('CustomerEditController', function ($scope) {});
app.controller('CustomerDeleteController', function ($scope) {});
1) When typing the ng-controller directly to your view that view has a direct tie to that controller. Defining the controller in the route allows you to reuse the view for other needs.
For example, you have a view that displays a list of names.
<ul ng-controller="ListCtrl">
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
Now someplace else in your application you have the same exact structure that displays a list of names you would need to do the same thing again.
<ul ng-controller="MyOtherListCtrl">
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
If you remove the ng-controller attribute you can reuse this <ul/>
<ul>
<li ng-repeat="item in items">{{item.name}}</li>
</ul>
and
.when('/list1', {templateUrl: 'list.html', controller: 'ListCtrl'})
.when('/list2', {templateUrl: 'list.html', controller: 'MyOtherListCtrl'})
2) app.controller scopes the controller to your module while the other creates the controller on the global scope.
3) I depends how you have your application is structured, but Simply creating a CustomerController that has $scope methods for edit, delete, and create. This controller can take a dependency of a Service or $resoruce
app.controller('CustomerController', function ($scope, customerService) {
$scope.add = function(customer){
//add customer with customerService
};
$scope.edit = function(customer){
//edit customer with customerService
}
$scope.delete = function(customer){
//delete customer with customerService
}
});
If you want separate pages you could still reuse the same controller.
.when('/add', {templateUrl: 'add.html', controller: 'CustomerController'})
.when('/edit', {templateUrl: 'edit.html', controller: 'CustomerController'})
.when('/delete', {templateUrl: 'delete.html', controller: 'CustomerController'})
Related
I'm using AngularUI Router with Bootstrap. I have two views within the same state, and want to scroll to the second view when a button is clicked. I don't need to do any scrolling when the initial state and views load. I want the page to scroll to #start when the "Add More" button is clicked. I've attempted to use $anchorScroll to accomplish this, but am not having any luck.
Any suggestions on a good way to accomplish this?
HTML:
<!-- index.html -->
<div ui-view="list"></div>
<div ui-view="selectionlist"></div>
<!-- list.html -->
<div id="scrollArea"><a ng-click="gotoBottom()" class="btn btn-danger btn-lg" role="button">Add More</a>
<!-- selectionlist.html -->
<div class="row" id="start"></div>
Javascript for Controller:
myApp.controller('SelectionListCtrl', function (Selections, $location, $anchorScroll) {
var selectionList = this;
selectionList.selections = Selections;
this.selectedServices = Selections;
selectionList.gotoBottom = function() {
$location.hash('start');
$anchorScroll();
};
});
Javascript for Routes:
myApp.config(function ($stateProvider, $urlRouterProvider, $uiViewScrollProvider) {
$uiViewScrollProvider.useAnchorScroll();
$urlRouterProvider.otherwise('/');
$stateProvider
.state('selection', {
url: '/selection',
views: {
'list': {
templateUrl: 'views/list.html',
controller: 'ProjectListCtrl as projectList'
},
'selectionlist': {
templateUrl: 'views/selectionlist.html',
controller: 'SelectionListCtrl as selectionList'
}
}
})
Yes, it is possible to autoscroll in AngularUI Router without changing states.
As mentionned previously in my comment, you need to call the scrolling function with an ng-click="gotoBottom()" instead of an ng-click="gotoSection()"
Also, the function definition gotoBottom() must be in the ProjectListCtrl, not in the SelectionListCtrl. This is because the call gotoBottom() happens in the list view:
'list': {
templateUrl: 'list.html',
controller: 'ProjectListCtrl as projectList'
}
As gotoBottom() is called from the list.html view, the corresponding controller in $stateProvider must be the one where you define gotoBottom().
Here are two working ways of accomplishing your goal:
1. You inject $scope inside the controller ProjectListCtrl. You then define the $scope.gotoBottom function in the same controller.
The scope is the glue between the controller and the view. If you want to call a controller function from your view, you need to define the controller function with $scope
app.controller('ProjectListCtrl', function ($location, $anchorScroll,$scope) {
var selectionList = this;
//selectionList.selections = Selections;
//this.selectedServices = Selections;
$scope.gotoBottom = function() {
console.log("go to bottom");
$location.hash('start');
$anchorScroll();
};
});
In the list.html view, you can then call the $scope.gotoBottom function just with gotoBottom(): ng-click="gotoBottom()"
2. Or you use the controller as notation, as when you wrote ProjectListCtrl as projectList.
this.gotoBottomWithoutScope = function(){
$location.hash('start');
$anchorScroll();
};
With this notation, you write this.gotoBottomWithoutScope in the ProjectListCtrl. But in the view, you must refer to it as projectList.gotoBottomWithoutScope().
Please find a working plunker
To learn more about the this and $scope notations, please read this:
Angular: Should I use this or $scope
this: AngularJS: "Controller as" or "$scope"?
and this: Digging into Angular’s “Controller as” syntax
I have a simple view representing a simple menu which should be using anchor behavior. On the same page there's a bunch of H2 tags with id that the links should scroll to.
I'm using the $anchorScroll and $location.
THE ISSUE: The first time I click a link, I can see that the route is updated, e.g.:
http://localhost:60002/#!/docs/view/somedoc#someResourceId
But it triggers a route, the SECOND time I click it, it behaves as expected.
UPDATE: It's not the anchorScroll() did it manually using element.scrollIntoView(true) same behavior. If I don't use $location.hash it works, but then I loose the possibility of linking to anchors.
Any ideas?
VIEW:
<div ng-controller="DocsMenuCtrl">
<ul ng-repeat="menuItem in menuItems">
<li><a ng-click="foo(menuItem.resourceId)">{{menuItem.title}}</a></li>
</ul>
</div>
...
...
<h2 id="...">Test</h2>
...
CONTROLLER:
module.controller('DocsMenuCtrl', ['$scope', '$http', '$location', '$anchorScroll', 'session', function ($scope, $http, $location, $anchorScroll, session) {
$scope.foo = function (resourceId) {
$location.hash(resourceId);
$anchorScroll();
};
$http.get('/api/menu/').success(function (d) {
$scope.menuItems = d;
}).error(function () {
session.logger.log(arguments);
});
}]);
ROUTEPROVIDER CONFIG etc
$locationProvider.hashPrefix('!');
$routeProvider
.when('/default', {
templateUrl: 'clientviews/default',
controller: 'DefaultCtrl'
})
.when('/docs/view/:id', {
templateUrl: 'clientviews/docs',
controller: 'DocsCtrl'
})
.otherwise({
redirectTo: '/default'
});
$location does not reload the page even if it is used to change the url. See the "What does it not do?" section of this page: $location ngDoc.
As Ganonside said, the location service does not reload the url. Once you are certain that the url changes you can use the route service, specifically $route.reload() to trigger your routing.
The best solution I've found is here: https://github.com/angular/angular.js/issues/1699#issuecomment-22509845
Another option, if you don't use search params, is to tell the route provider not to reload on hash or search changes (unfortunately, it is one option for both).
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/group/:groupName', {
templateUrl: '/templates/groupView.html',
reloadOnSearch: false
}).otherwise({redirectTo: '/'});
}]);
sorry for my English is not good !
I have followed this example phoneCat app
this is one category ( phone list and detail patial templates).
for example , i have many category, all in one category.html file (car, phone,fashion) throught url ( localhost/myApp/#/car .. localhost/myApp/#/phone..)
mainLayout
<div ng-view></div>
js file
.config(['$routeProvider',
function($routeProvider) {
$routeProvider
// route for fashion
.when('/fashion', {
templateUrl: 'partials/category.html',
controller: 'fashionCtrl'
})
// route for car
.when('/car', {
templateUrl: 'partials/category.html',
controller: 'carCtrl'
})
.. controller for fashionCtrl and carCtrl
partial template html (category.html)
template for car
...................
template for fashion
...................
template for phone
when i called the path /#/fashion it display both , but i want only one fashion or car
_So where is the solutions?
thanks for help !
It sounds like what you are looking for is to share both controller and template (common scenario)...
So instead of configuring multiple routes, you just need a single route:
.config(['$routeProvider',
function($routeProvider) {
$routeProvider
// route for fashion
.when('/:category', {
templateUrl: 'partials/category.html',
controller: 'categoryController'
})
In your controller then use $routeParams to get the currently selected category and populate your template with that common data.
.controller('categoryController', ['$scope', '$routeProvider', function($scope, $routeParams) {
$scope.category = $routeParams.category;
$scope.items = fetchFromService($routeParams.category);
}])
Sample: http://plnkr.co/edit/dtrZMAcbsbzpWsd9e7Uy?p=preview
I am new to angular js and currently stuck with very wired kind of a bug. function in a controllers runs twice when its called by view loaded against a route.
http://jsfiddle.net/4gwG3/5/
you will see alert twice!!
my view is simple
and my app code is following
var IB = angular.module('IB', []);
//channel controller
IB.controller('channelsController', function ($scope, $routeParams) {
$scope.greet = function () {
alert('hi');
};
});
IB.config(function ($routeProvider) {
$routeProvider
.when('/channels', {
controller: 'channelsController',
template: '{{greet()}}'
})
.otherwise({ redirectTo: '/channels' });
});
First check that you're not initializing your Angular app twice (by having it initialized automatically with ng-app).
One time I had 2 html pages with ng-app (one for login.html and
another for main.html) and this was a problem I realized later.
Second and for me the most important, check if you have attached your controller to multiple elements. This is a common case if you are using routing.
In my case I was navigating to DashboardController like so:
app.config(function($routeProvider){
$routeProvider
.when('/', {
controller: 'DashboardController',
templateUrl: 'pages/dashboard.html'
})
});
But I also had this in dashboard.html:
<section class="content" ng-controller="DashboardController">
Which was instructing AngularJS to digest my controller twice.
To solve it you have two ways:
removing ng-controller from your html file like this:
<section class="content">
or removing controller from routing (that is normally situated in app.js):
app.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'pages/dashboard.html'
})
});
I think by creating an interpolation {{greet()}}, you create a watch on function greet. This function can get call as many time as digest cycle runs, so it is not a question about it running 1 or 2 times. So you should not depend upon the times the function is called.
I dont know what you are trying to achieve here. There are two alerts
1. When the controller is called.
2. When the template is get evaluated.
template is to provide the view part, however, in this case template is just evaluating function which is not creating any view.
I had the same problem, so I did:
$scope.init=function()
{
if ($rootScope.shopInit==true) return;
$rootScope.shopInit=true;
...
}
$scope.init();
Like if it were a singleton ! (I had many ajax calls each time I display, it was boring)
The new ngAnimate works with a hard coded class:
<div ng-view class="forward"></div>
.forward.ng-enter {
-webkit-animation: from_right 10s ease;
}
but not a dynamic class:
<div ng-view ng-class="{'forward': true}"></div>
How can I dynamically switch between animations for enter and exit (e.g. forward and back in a phone wizard)?
I literally spent five hours trying to figure out this exact same issue, since I'm trying to do the exact same thing. Turns out, it was a bug in rc1. Here's the pull request, which is now in rc2.
Basically, ngAnimate was running before the class could be interpreted, but now it's fixed. Your example should work now:
<div ng-view ng-class="{ 'foo': bar }"></div>
Alternatively, you could just use the regular class attribute, and bind it to a certain string in the models of your different controllers (if you have separate controllers for each view, e.g. when routing), like so:
<div ng-view class="foo"></div>
Then, in your javascript, do something like:
angular.module('app', []);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/one', { templateUrl: '/one.html', controller: 'viewOneCtrl' })
.when('/two', { templateUrl: '/two.html', controller: 'viewTwoCtrl' });
}]);
app.controller('viewOneCtrl', ['$scope', function($scope) {
$scope.foo = 'view-one';
}]);
app.controller('viewTwoCtrl', ['$scope', function($scope) {
$scope.foo = 'view-two';
}]);