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';
}
Related
I'm so confused about my situation. Let me briefly introduce my situation.
HTML structure. (It's just structure, full HTML is more than that but there is no any other controller except "pageController")
<body ng-app="app">
<div id="wrapper" ng-controller="pageController">
<div id="menu">
<a>.........</a>
</div>
<div id="mainView">
<ng-view></ng-view>
</div>
</div>
</body>
Of course, I properly set router.
var app = angular.module("app", ["ngRoute"])
.config(function($routeProvider){
$routeProvider
.when("/about", {
templateUrl: "about.html"
})
.when("/summary", {
templateUrl: "summary.html"
})
.when("/company", {
templateUrl: "company.html"
})
.when("/remote", {
templateUrl: "remote.html"
})
.when("/personal", {
templateUrl: "personal.html"
})
.when("/academic", {
templateUrl: "academic.html"
})
.otherwise({
redirectTo : "/about"
});
});
I didn't set any controller now. I put each controller as "pageController" before but I removed now because I think pageController will be automatically inherited as long as pageController is in parent element.
And I made custom directive.
app.directive('imageLoader', function(){
return{
restrict:'A',
link:function(scope, elem, attrs){
elem.bind('click', function(){
var fileName = "img/portfolioImages/" + attrs.ori;
scope.$parent.$parent.modalImgSrc = fileName;
scope.$parent.$parent.isModalOpen = true;
scope.$parent.$parent.$digest();
});
}
};
});
In injected html in ng-view, there is no any other controller, but it dynamically generate <img> tag like below
<div class="project-image-div">
<img image-loader ng-repeat="aImgSrc in remoteImageFiles[0]"
data-ori='{{aImgSrc}}' class='project-img-s'
ng-src='img/portfolioImages/{{aImgSrc.substring(0,aImgSrc.lastIndexOf(".")) + "_s" + aImgSrc.substr(aImgSrc.lastIndexOf("."), 4)}}'>
</div>
remoteImageFiles[0] is json object saved in pageController scope. And these dynamically added img tags are completely fine.
THE PROBLEM
As you can see in <img> tag, I am using custom directive image-loader. In directive code, I expected "scope" is same scope as pageController as long as there is no any other controller inside ng-view and I didn't give any option for scope in the custom directive.
But I printed scope object in console, I can access pageController scope object as parent of parent... WHY?????
scope.$parent.$parent.modalImgSrc = fileName;
scope.$parent.$parent.isModalOpen = true;
scope.$parent.$parent.$digest();
Thank you for reading my long post... please help... I am spending 2 days for this..
You can see full code in my personal web site. I am noob to angularJS. I am converting JQuery version of site to pure angularJS version to learn AngularJS.. It's in progress.
AngularJS version..(converting now)
http://bear-mj.com/MJKim
JQuery version..(all working)
http://bear-mj.com/MJKimJQuery/
You have 3 levels of scope created. Remember, both ng-repeat and ng-view create a new scope. In this area of your app - inside the directive:
scope is the ng-repeat scope
scope.$parent is the ng-view scope
scope.$parent.$parent is the pageController scope
so I have a component with a template containing a form.
mycomponent.html:
<div>
<form name="myForm">
<!-- more html code -->
</form>
</div>
How can I access myForm inside the component controller?
Currently I'm injecting $scope to get it from that.
Or is that the only way to get the form?
Edit: Added some code to better illustrate in javascript
angular.module('example')
.component('myComponent', {
templateUrl: 'mycomponent.html',
controller: function($scope) {
$scope.myForm // This works
this.myForm // undefined, can I access it through the component scope instead of $scope somehow?
}
});
The name attribute of a form is what angular uses to decide what to bind to. So, if you're using the controllerAs syntax, you have to use that in the form name:
<body ng-controller="MainCtrl as vm">
<form name='vm.myForm'>
</form>
</body>
This will allow you to refer to it in your controller without using $scope, but only after the controller has been successfully created:
app.controller('MainCtrl', function($scope, $timeout) {
var vm = this;
console.log(vm.myForm); // undefined
$timeout(function() {
console.log(vm.myForm); // FormController object
}, 100);
});
Here is a working plunk.
Use the name syntax but also a components postLink lifecycle hook, that function is called once a template and controller have been connected see https://docs.angularjs.org/guide/component
I need that code will be called in controller ChatController, not in global application:
.config(function($routeProvider){
$routeProvider.when("/chat/dialog/:id",
{
templateUrl: "/template/chat/active_dialog.html",
controller: "ChatController"
}
);
})
How I can do it?
I tried (template is not loaded in div):
Angular JS:
$scope.selectDialog = function (id, event){
$scope.template = '/template/chat/active_dialog.html';
});
HTML:
<div ng-include src="{{template}}"></div>
I agree with #Nano,all the providers that are used angular are injected and used in
.config,you directly cannot use it in your controller.
I have one html file and a controller assigned via $routeProvider
.when('/page/:pageId', {
templateUrl: 'xxxx.html',
controller: 'PageCtrl'
})
and in the controller.js file i am accessing the value of pageId using $routeParams in 'PageCtrl' function.
pageId = $routeParams.pageId;
and in view the html is
<div ng-controller="headerController">
{{page.pageId}}
</div>
so in html i want to display the pageId, if pageId is passed in the url.
so here my question is once the pageId is passed its going correctly to the pageCtrl in Js and pageId scope value assigned, and am also able to assign the same scope value to the second controller 'headerController' by $controller('headerController', {$scope: $scope});
able to see that scope value is getting updated from one controller to another controller but my problem is that scope value which is updated, unable to view in html ({{page.pageId}})
The problem is that your controller is getting instantiated twice: once from your $controller call and another time from the ng-controller directive in your view, each time with a difference scope, where the latter "wins" as far as what shows up in your view goes.
Consider this small demo:
JS
.controller('FirstController', function($scope, $controller){
console.log('FirstController', $scope.$id); // logs 003
$scope.pageId = '12345';
$controller('SecondController', {$scope: $scope});
})
.controller('SecondController', function($scope){
console.log('SecondController', $scope.$id); // logs 003 & 004
$scope.scopeId = $scope.$id; // second scope "wins", appears in view
});
HTML
<div ng-controller="FirstController"></div>
<!-- {{scopeId}} outputs a value while {{pageId}} does not -->
<div ng-controller="SecondController">Scope: {{scopeId}} Page: {{pageId}}</div>
A better solution is to use a service to share data between controllers.
I call a my controller with $routeProvider like this:
$routeProvider
.when('/home', {
templateUrl: "partials/main.html",
controller: "AppCtrl"
});
So the focus of $scope in the controller will change only the content of partials/main.html.
I would need to change {{status}} in index.html, but it won't change if I do $scope.status = 'ready'; in the controller, it will change only if it was in main.html.
How can I make this work ?
Thank you very much.
The scope associated with AppCtrl should prototypically inherit from the scope associated with the controller you have defined in index.html. Define a method on that controller, and then you can call it from your child controller/scope (because of the way JavaScript prototypal inheritance works):
function MainCtrl($scope) {
$scope.updateStatus = function(newStatus) {
$scope.status = newStatus;
}
}
function AppCtrl($scope) {
...
$scope.updateStatus(....);
}
Fiddle. In the fiddle, I don't use ng-view, but it still shows the concept.