I can access a service such as $routeParams from the controller like so.
angular.module('myModule', []).
controller('myCtrl', ['$routeParams',
'$scope', function($routeParams,
$scope) {
console.log($routeParams['my-route-param']);
}])
But how would I do the same from a template. I tried the following code to no avail.
<h1 ng-hide="$routeParams['my-route-param']">No route param!</h1>
I know you could always save the value to $scope, but I am looking for a cleaner solution.
You can assign routeParams to a property of $scope:
controller('myCtrl', ['$routeParams',
'$scope', function($routeParams,
$scope) {
...
$scope.$routeParams = $routeParams
...
}
and then this would work:
<h1 ng-hide="$routeParams['my-route-param']">No route param!</h1>
Reason for that is every property you are accessing from template should be defined in current scope, which of course is not the case for parameter of controller constructor.
NB: in case of controller as syntax used you would do the same with controller, not scope:
controller('myCtrl', ['$routeParams',
'$scope', function($routeParams,
$scope) {
...
this.$routeParams = $routeParams
...
}
and markup:
<div ng-controller="myCtrl as ctrl">
<h1 ng-hide="ctrl.$routeParams['my-route-param']">No route param!</h1>
It's a bit late, but I had enough of copying $routeParams into my $scope only to be able to use them in my views, so I created a directive to do so.
Let's say you have this routing config:
...
angular.module( 'myApp' ).config( [ '$routeProvider', function( $routeProvider ) {
$routeProvider.when( '/view1/:param1/:param2', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])
...
And in your view1.html:
<h1 isteven-rr>$routeParams says: [[param1]] [[param2]]</h1>
If you have this in your URL bar: http://localhost/#/view1/Hello/World!
Then you'll see:
$routeParams says: Hello World!
Fork & learn more: https://github.com/isteven/angular-route-rage
Hope it can help shorten development time! Cheers!
Related
Any specific reason why my code is not working?
<li ng-class="{active : $state.includes('products')}">
router code:
.state('products', {
url: '/products',
templateUrl: 'app/components/views/products/products.html',
controller: 'productsController',
controllerAs: 'products'
})
You are forgetting to set the $state and $stateParams on your $rootScope, if you do so, you can keep using your first approach on html:
angular.module("myApp").run(function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
});
This way you don't need to inject them on every single controller.
Here is the reference:
https://github.com/angular-ui/ui-router/wiki/quick-reference#note-about-using-state-within-a-template
PS: I personally don't recommend this kind of global approach, but it has its merits
you will need to get the $state provider via the $injector in your controller (as you would inject yourself $scope or a service.
EDIT:
Include it as such:
angular.module('yourModule', []).controller('YourController',['$injector',
funciton($injector){}
]);
Then:
$scope.$state = $injector.get('$state');
You now have access to $state. To get the name of your current state, simply use:
$state.current.name
Example:
<li ng-class="{active : $state.current.name === 'products'}">
I have a mini app with a controller that looks like that:
app.controller("MyController", [ '$scope', '$attrs', 'ServiceA', 'ServiceB', function($scope, $attrs, svc1, svc2) {
...
}])
When I tried to add angular-routing to my app, I added the following route.js file:
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/main.html',
controller: 'MyController',
controllerAs: 'appCtrl',
resolve: {
attrs: $attrs
}
})
}
]);
It seems that I can't inject $attrs like before. I've tried playing with resolve inside when() but it didn't seem to help.
I must say it looks a bit weird to inject $attrs into the controller anyway, and since that's my first app I think I'm doing something wrong here.. I need $attrs to read a data attribute from the div and initialize some array according to it. Any ideas to how I should do it or why I couldn't do it with my approach? (which worked without the routes)
Thanks!
I'm using ui-router for my application and nesting controllers within ui-view. My parent controller looks like this:
'use strict';
angular.module("discussoramaApp").controller("mainController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", function(RestFullResponse, Restangular, localStorageService, $scope){
var currentId = localStorageService.get("***");
var user = Restangular.one("users", currentId);
var Profile = user.get({}, {"Authorization" : localStorageService.get('***')}).then(function(profile) {
$scope.profile = profile;
});
}]);
And my child controller:
'use strict';
angular.module("discussoramaApp").controller("getTopicsController", ["RestFullResponse", "Restangular", "localStorageService", "$scope", function(RestFullResponse, Restangular, localStorageService, $scope){
var topics = Restangular.all('topics');
var allTopics = topics.getList({},{"Authorization" : localStorageService.get('***')}).then(function(topics){
$scope.topics = topics;
});
console.log($scope); // this works
console.log($scope.profile); // this returns undefined
}]);
The problem I'm having is getting the inherited $scope value for profile in the child controller. When I log $scope, profile is clearly visible in the console.
But when I try to log $scope.profile the console returns undefined. Any ideas?
Edit: Adding my ui-router config.
angular.module("discussoramaApp").config(
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$urlRouterProvider.when('', '/home');
$stateProvider
.state('main',{
url: '',
templateUrl: 'partials/main.html',
requireLogin: true
})
.state('main.home',{
url: '/home',
templateUrl: 'partials/main.home.html',
requireLogin: true,
title: 'Home'
});
}
);
And the corresponding html files:
// main.html
<div ng-controller="mainController">
<div class="container">
<div ui-view></div>
</div>
</div>
and the child html partial:
// main.home.html
<div ng-controller="getTopicsController">
<div ng-repeat="topic in topics | filter:search">
<a ui-sref="main.topic({id: topic.id})">{{ topic.topic_title }}</a>
</div>
</div>
UPDATE: Solved this with a watcher set up like this in the child controller. Thanks #jonathanpglick and #Nix for the help.
$scope.$watch('profile', function(profile) {
if(profile) {
$window.document.title = "Discussorama | " + profile.user.name;
}
});
$scope.profile is being set after an asynchronous request so I suspect that the second controller is being instantiated before user.get() returns and assigns a value to $scope.profile.
I think you'll want to set up a watcher (like $scope.$watch('profile', function(profile) {});) in the child controller so you can do things when the profile becomes available or changes.
Also, the reason you can see the profile key on $scope when you console log $scope can be explained here: https://stackoverflow.com/a/7389177/325018. You'll want to use console.dir() to get the current state of the object when it's called.
UPDATE:
I just realized you're using the ui-router and so there's an even easier way to do this. The ui-router has a resolve object that you can use to dependency inject things like this into your controller. Each resolve function just needs to return a value or a promise and it will be available for injection into the controller with resolve key name. It would look like this for you:
angular.module("discussoramaApp").config(
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$urlRouterProvider.when('', '/home');
$stateProvider
.state('main',{
url: '',
templateUrl: 'partials/main.html',
requireLogin: true,
resolve: {
profile: ['Restangular', 'localStorageService', function(Restangular , localStorageService) {
var currentId = localStorageService.get("***");
var user = Restangular.one("users", currentId);
return user.get({}, {"Authorization" : localStorageService.get('***')});
}
}
})
.state('main.home',{
url: '/home',
templateUrl: 'partials/main.home.html',
requireLogin: true,
title: 'Home'
});
}
);
angular.module("discussoramaApp").controller("mainController", ["profile", "$scope", function(profile, $scope){
$scope.profile = profile;
}]);
Just because you have nested scope, doesn't mean it will wait for user.get() to return before instantiating your nested getTopicsController.
Your issue is:
mainController controller initializes and calls user.get()
getTopicsController initializes and logs console.log($scope.profile)
The call to user.get() returns and then sets on scope.
This is a common issue, if you need to gaurantee that $scope.profile is set, use resolve or watch the variable.
I actually gave an example of how to do this earlier today: AngularJS $rootScope.$broadcast not working in app.run
When I have a controller inside my html
<div ng-controller="myController" id="myCtrl">...</div>
I can access it via:
angular.element(myCtrl).controller()
But how can I access the controller from a directive?
directive('myDirective', function () {
return {
...
templateUrl: '/Views/myview.html',
controller: myController
}
})
This controller should be defined the same module module where your directive is defined:
E.g
angular.module('myModule', [])
.controller('myController',['$scope', function($scope){
$scope.myData = {'someData':1337};
}])
.directive('myDirective', [function(){
return {
...
templateUrl: '/Views/myview.html',
controller: 'myController'
}
}])
Here is a plunkr, demonstrating that way:
http://plnkr.co/edit/UDCWUI5EMlfoXb9u3GYh?p=preview
And here is a plunkr, demonstrating having a directive in a module using a controller that is defined in another module:
http://plnkr.co/edit/Gg0BzKPOqO2NnTgf3Hkr?p=preview
angular.module('myApp',[
])
.controller('MyController', ['$scope', function($scope){
$scope.someValue = 'someValueFromController';
}])
angular.module('otherModule', ['myApp'])
.directive('myDirective', [function(){
return {
restrict: 'E',
templateUrl: 'someTemplate.html',
controller: 'MyController'
}
}])
Alternatively, you can use the $controller service to instantiate your controller with the appropriate stuffs and use it everywhere (from every module that imports the module where your controller is defined).
index.html
<body>
<div data-form-modal >
<form>
<input type='text' name='test'/>
<input type='submit' value='submit' ng-click='submit()'/>
//this submit() function is in mainCtrl
</form>
</div>
</body>
this is my route:
app.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainCtrl',
templateUrl: 'index.html'
})
.otherwise({
redirectTo: '/'
});
});
mainCtrl:
controller.mainCtrl = function(){
...
$scope.submit = function(){
alert(1)
}
}
form modal directive:
directive.formModal=function(){
return {
...
}
}
when I click the submit button, I try to call the submit() function in mainCtrl, but nothing heppend, I think its because the mainCtrl is a route controller and dosen't belong to any scope, and the formModal directive can't access the submit method.
I want the mainCtrl to handle the restful service and the formModal directive handle the form validation, but I dont know how to call method in mainCtrl from the formModal, and what is the relationship between the mainCtrl and the formModalCtrl?
edited:
I try to move the restful method to a service, and call the service method in formModal directive controller , it works fine, but I still need to access the mainCtrl in order to update the model so that the view can change accordingly.
What I've done is:
var app = angular.module('myApp', ['controllers'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/', {
controller: 'mainCtrl',
templateUrl: 'index.html'
}).
otherwise({
redirectTo: '/'
});
}]);
var controllers = angular.module('controllers', []);
Then:
// separate file
controllers.controller('mainCtrl', ['$scope'
function ($scope) {
// do stuff with $scope
}
]);
You can probably do app.controller('mainCtrl' ... instead and save a controllers variable. I just happened to get this working on my site this way.
Also, make sure you have an ng-app of myApp enclosing an element with ng-view (for routing to work).