AngularJS - How to Use Service in Template - angularjs

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

Angular - ng-class based on state

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'}">

how to inject $attrs into a controller through $routeProvider

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!

Can't access value of scope in AngularJS. Console log returns undefined

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

Access angular controller from directive

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).

communicate between angular controller and route controller

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).

Resources