Please see this fiddle
I want to inject resolver into the AngularJS controller but not working. The error message is Unknown provider: urlParasProvider <- urlParas <- MyController
Any suggestions, thanks!
function config($routeProvider){
$routeProvider
.when('/abc',{
controller: 'MyController',
resolve: {
urlParas : function(){
// return $location.absUrl();
return 'abc';
}
}
})
.otherwise({
controller: 'MyController',
resolve: {
urlParas : function(){
// return $location.absUrl();
return 'abc';
}
}
});
}
myApp.$inject = ['$scope','urlParas'];
You are getting the error because the controller is being instantiated by theng-controller directive:
ERRONEOUS
<body ng-controller="MyController">
<h1>Hello Plunker!</h1>
<h3>{{text}}</h3>
</body>
The ng-controller directive does not have access to resolver locals.
The $compile service instantiates the ng-controller directive and its controller without regard to the routing tables.
From the Docs:
$compile DDO property - controller
Controller constructor function. The controller is instantiated before the pre-linking phase and can be accessed by other directives (see require attribute). This allows the directives to communicate with each other and augment each other's behavior.
The controller is injectable (and supports bracket notation) with the following locals:
$scope - Current scope associated with the element
$element - Current element
$attrs - Current attributes object for the element
$transclude - A transclude linking function pre-bound to the correct transclusion scope
— AngularJS $compile Service Comprehensive Directive API - controller
Thanks! I tried to remove ng-controller="MyController" but not working,
Put the template in the route definition:
$routeProvider
.when('/abc',{
controller: 'MyController',
template: `
<h1>Hello Plunker!</h1>
<h3>{{text}}</h3>
`,
resolve: {
urlParas : function(){
// return $location.absUrl();
return 'abc';
}
}
})
And instantiate it with the ng-view directive:
<body ̶n̶g̶-̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶=̶"̶M̶y̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶"̶ >
<ng-view>
</ng-view>
</body>
The ng-view directive uses the routing tables to instantaiate the proper template and proper controller. It invokes the resolver functions and injects them as locals into the specified controller.
From the Docs:
$route.current.locals:
A map of locals which is used by $controller service for controller instantiation. The locals contain the resolved values of the resolve map. Additionally the locals also contain:
$scope - The current route scope.
$template - The current route template HTML.
The locals will be assigned to the route scope's $resolve property. You can override the property name, using resolveAs in the route definition.
— AngularJS ngRoute $route API Reference - current property
The Controller
app.controller('MyController', MyController);
MyController.$inject = ['$scope','urlParas'];
function MyController($scope,urlParas){
$scope.text = 'Sophia';
}
I trying to create a search application using angularJS.I am facing the issue in binding $scope values to view when router Url changes.
I have a search field in /main.When I write the query and click on search button, the function does the data fetch and assign to a scope variable.The router URL will change to '/Result' and the respective view is displayed.But the view doesn't have the scope values bound. /main and /Result uses the same controller.
router code in main module :
$routeProvider.
when('/main', {
templateUrl: '/views/search.html',
controller: 'searchCtrl'
}).when('/Result',{
templateUrl:'/views/Result.html',
controller: 'searchCtrl' ,
reloadOnSearch: false
}).otherwise({
redirectTo: '/main'
});
Controller :
On button click from /main
$scope.fetchResult=function(searchWord){
shService.fetchResultDocumentsList(searchWord).data.then(function(response){
//service call here-data fetch is successfull.
$scope.docResultList=response[0];
$scope.docResultList=response[0];
$scope.documents = $scope.docResultList.data.documentEntities;
$location.path('/Result');
}
When the respective view is changing, the binding is not done.But when i replace the $scope.documents with $rootScope.documents binding is successful.
I have read the use of $scope is encouraged over $rootScope.
The controller and $scope gets re initialized when you move from one page to another page. if you want to use $scope , you should consider using service to share the data across controllers.
Create a service, that will hold your variable.
angular.service("dataService", function() {
this.value1 = ""
});
reference that service in your controllers,
angular.controller("myCntrl1", function($scope, dataService) {
$scope.val= dataService.value1 ;
});
angular.controller("myCntrl2", function($scope, dataService) {
$scope.val= dataService.value1 ;
});
As Sajeetharan said, $scope get reinitialized when you update location.
Using angularJs, you don't need to change location. You simply update $scope in the same view you used for searching.
But if you really need to use another view, and assuming your search returns only strings, you could try to pass data through url, and grab it from your controller.
Something like this (not tested):
Solution 1 (Angular way)
Controller
$scope.documents = ""; // init your results to empty/null, as you need
$scope.fetchResult=function(searchWord){
shService.fetchResultDocumentsList(searchWord).data.then(function(response){
//service call here-data fetch is successfull.
$scope.docResultList=response[0];
$scope.docResultList=response[0];
$scope.documents = $scope.docResultList.data.documentEntities;
$location.path('/Result');
}
View
<!-- search div is over here -->
<!-- results goes here -->
<div ng-if="$scope.documents">
{{$scope.documents}}
</div>
Solution 2 (your way)
Router
$routeProvider.
when('/main', {
templateUrl: '/views/search.html',
controller: 'searchCtrl'})
.when('/Result/{data:[a-z]{1,}}',{ //here we specify that data expected format is only lowercase letters
templateUrl:'/views/Result.html',
controller: 'searchCtrl' ,
reloadOnSearch: false
})
.otherwise({
redirectTo: '/main'
});
Controller
// dont forget to inject $stateParams service in your controller
if( !$stateParams.data){
$scope.data = $stateParams.data;
}
How to initialise value inside controller function with AngularJS tried multiple time but not getting proper answer??
You can inject $scope in your controller function. Then you can define any variable inside $scope.
Example
.controller('TestController', ['$scope', function($scope) {
$scope.message = 'Hello';
}])
As you can see in the above example I have injected $scope to TestController and defined message variable inside it.
Note that all the variables defined in a controller scope are accessable by the view belonging to that controller. So you can access the value of $scope.message in your DOM as
<div ng-controller="TestController">
{{message}}
</div>
On the screen you will see the text Hello
I have one situation where I have to pass the directive, functions and variables declared in the controller. I can easily do this with $scope. But I read one article which states that we should not populate the scope instead use this. The article had the following example -
//Don't do this
app.controller('MyCtrl', function($scope){
$scope.name = 'Techno Fattie';
});
//Do this
var MyCtrl = function(){
this.name = 'Techno Fattie';
};
app.controller('MyCtrl', MyCtrl);
I liked the idea and I tried implementing the same in my situation which is as follows -
I have a CountryController - which I modified to use this instead of $scope.
I have a countryList.tpl.html - which has only a directive in it and no other code.
Now I have a parent controller which has a stateProvider where I have configuration for country. something like this -
.state('app.country', {
url: "/country",
templateUrl: "countryList.tpl.html",
controller: CountryController
})
I converted the controller's $scope to this but then I observed that I the directive is not receiving the function and variables and the page is not loading properly.
Is it that if the tpl file has a directive then this approach is not useful? If that is not true, then how can we do this? Can anyone help?
I have this piece of layout html:
<body ng-controller="MainController">
<div id="terminal"></div>
<div ng-view></div>
<!-- including scripts -->
</body>
Now apparently, when I try to use $routeParams in MainController, it's always empty. It's important to note that MainController is supposed to be in effect in every possible route; therefore I'm not defining it in my app.js. I mean, I'm not defining it here:
$routeProvider.when("/view1", {
templateUrl: "partials/partial1.html"
controller: "MyCtrl1"
})
$routeProvider.when("/view2", {
templateUrl: "partials/partial2.html"
controller: "MyCtrl2"
})
// I'm not defining MainController here!!
In fact, I think my problem is perfectly the same as this one: https://groups.google.com/forum/#!topic/angular/ib2wHQozeNE
However, I still don't get how to get route parameters in my main controller...
EDIT:
What I meant was that I'm not associating my MainController with any specific route. It's defined; and it's the parent controller of all other controllers. What I'm trying to know is that when you go to a URL like /whatever, which is matched by a route like /:whatever, why is it that only the sub-controller is able to access the route parameter, whereas the main controller is not? How do I get the :whatever route parameter in my main controller?
The $routeParams service is populated asynchronously. This means it will typically appear empty when first used in a controller.
To be notified when $routeParams has been populated, subscribe to the $routeChangeSuccess event on the $scope. (If you're in a component that doesn't have access to a child $scope, e.g., a service or a factory, you can inject and use $rootScope instead.)
module.controller('FooCtrl', function($scope, $routeParams) {
$scope.$on('$routeChangeSuccess', function() {
// $routeParams should be populated here
});
);
Controllers used by a route, or within a template included by a route, will have immediate access to the fully-populated $routeParams because ng-view waits for the $routeChangeSuccess event before continuing. (It has to wait, since it needs the route information in order to decide which template/controller to even load.)
If you know your controller will be used inside of ng-view, you won't need to wait for the routing event. If you know your controller will not, you will. If you're not sure, you'll have to explicitly allow for both possibilities. Subscribing to $routeChangeSuccess will not be enough; you will only see the event if $routeParams wasn't already populated:
module.controller('FooCtrl', function($scope, $routeParams) {
// $routeParams will already be populated
// here if this controller is used within ng-view
$scope.$on('$routeChangeSuccess', function() {
// $routeParams will be populated here if
// this controller is used outside ng-view
});
);
As an alternate to the $timeout that plong0 mentioned...
You can also inject the $route service which will show your params immediately.
angular.module('MyModule')
.controller('MainCtrl', function ($scope, $route) {
console.log('routeParams:'+JSON.stringify($route.current.params));
});
I have the same problem.
What I discovered is that, $routeParams take some time to load in the Main Controller, it probably initiate the Main Controller first and then set $routeParams at the Child Controller. I did a workaround for it creating a method in the Main Controller $scope and pass $routeParams through it in the Child Controllers:
angular.module('MyModule')
.controller('MainController', ["$scope", function ($scope) {
$scope.parentMethod = function($routeParams) {
//do stuff
}
}]);
angular.module('MyModule')
.controller('MyCtrl1', ["$scope", function ($scope) {
$scope.parentMethod($routeParams);
}]);
angular.module('MyModule')
.controller('MyCtrl2', ["$scope", function ($scope) {
$scope.parentMethod($routeParams);
}]);
had the same problem, and building off what Andre mentioned in his answer about $routeParams taking a moment to load in the main controller, I just put it in a timeout inside my MainCtrl.
angular.module('MyModule')
.controller('MainCtrl', function ($scope, $routeParams, $timeout) {
$timeout(function(){
// do stuff with $routeParams
console.log('routeParams:'+JSON.stringify($routeParams));
}, 20);
});
20ms delay to use $routeParams is not even noticeable, and less than that seems to have inconsistent results.
More specifically about my problem, I was confused because I had the exact same setup working with a different project structure (yo cg-angular) and when I rebuilt my project (yo angular-fullstack) I started experiencing the problem.
You have at least two problems here:
with $routeParams you get the route parameters, which you didn't define
the file where you define a main controller doesn't really matter. the important thing is in which module/function
The parameters have to be defined with the $routeProvider with the syntax :paramName:
$routeProvider.when("/view2/name1/:a/name2/:b"
and then you can retrieve them with $routeParams.paramName.
You can also use the query parameters, like index.html?k1=v1&k2=v2.
app.js is the file where you'd normally define dependencies and configuration (that's why you'd have there the app module .config block) and it contains the application module:
var myapp = angular.module(...);
This module can have other modules as dependencies, like directives or services, or a module per feature.
A simple approach is to have a module to encapsulate controllers. An approach closer to your original code is putting at least one controller in the main module:
myapp.controller('MainCtrl', function ($scope) {...}
Maybe you defined the controller as a global function? function MainCtrl() {...}? This pollutes the global namespace. avoid it.
Defining your controller in the main module will not make it "to take effect in all routes". This has to be defined with $routeProvider or make the controller of each route "inherit" from the main controller. This way, the controller of each route is instantiated after the route has changed, whereas the main controller is instantiated only once, when the line ng-controller="MainCtrl" is reached (which happens only once, during application startup)
You can simply pass values of $routeParams defined into your controller into the $rootScope
.controller('MainCtrl', function ($scope, $routeParams, MainFactory, $rootScope) {
$scope.contents = MainFactory.getThing($routeParams.id);
$rootScope.total = MainFactory.getMax(); // Send total to the rootScope
}
and inject $rootScope in your IndexCtrl (related to the index.html)
.controller('IndexCtrl', function($scope, $rootScope){
// Some code
});