I am a first time angularjs user and I am trying to create a directive but I cannot get around this error:
Error: Unknown provider: $scopeProvider <- $scope <- someDirectiveDirective createInjector/providerInjector<#http://localhost:4242/js/lib/angular/angular.js:2734 getService#http://localhost:4242/js/lib/angular/angular.js:2862 createInjector/instanceCache.$injector<#http://localhost:4242/js/lib/angular/angular.js:2739 getService#http://localhost:4242/js/lib/angular/angular.js:2862 ... ... ...
I create my angular app as follows:
var app = angular.module(
"myApp",
...
I then try and create my directive in another file:
app.directive('someDirective', function($http, $scope, $element, $attrs) {
return {
restrict: "A",
Then I use the directive:
I am sure that I am doing something really dumb but I have no idea.
Try this:
app.directive('someDirective', function($http) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
}
};
});
The reason for your error is that Angular does not allow you to inject $scope into a directive.
If you want to access $scope from inside a directive then you refer to it as the first argument in the link function (see Epokk's answer).
Related
I have a confirm box which I want to attach another directive to called confirmBoxToggle, but I'm unable to share the same controller instance in order for it to work. I've looked at multiple examples and also read the docs to see if I'm doing something crazy, but the only thing I can see is that I don't declare my controller inside the directive but rather giving a reference to it. But I can't see this being the issue.
I get this error when doing this:
Controller 'confirmBox', required by directive 'confirmBoxToggle', can't be found!
What am I doing wrong?
The box directive:
core.directive('confirmBox', [function() {
return {
scope: {},
controller: 'ConfirmBoxCtrl',
controllerAs: 'confirmBox',
templateUrl: 'app/views/components/core/confirmation-box.html',
link: function(scope, element, attrs, ctrl) {
}
};
}]);
The toggle directive:
core.directive('confirmBoxToggle', [function() {
return {
scope: {},
require: '^confirmBox',
link: function(scope, element, attrs, ctrl) {
element.on('click', function() {
ctrl.toggleBox();
});
}
};
}]);
The controller for both directives:
core.controller('ConfirmBoxCtrl', [function() {
var confirmBox = this;
confirmBox.toggleBox = function() {
confirmBox.isActive = !confirmBox.isActive;
};
}]);
I use the directives like this:
<confirm-box></confirm-box>
<span confirm-box-toggle>Delete</span>
Controller confirm or confirmBox can't be found?
Do you use that controller elsewhere, and does it work on it's own?
Basically you used require: '^confirmBox' that means while using confirmBoxToggle directive, it must be wrap with confirmBoxdirective(should be there in parent element as ^) so that you could access to the confirmBox link function 4th parameter.
HTML
<confirm-box>
<span confirm-box-toggle>Delete</span>
</confirm-box>
Also you can't have templateUrl inside your confirmBox directive, which will replace your <span confirm-box-toggle>Delete</span> html by the template loaded form templateUrl.
Demo Plunkr
I saw the following question (among other similar questions) and it solves the problem of trying to inject a factory into a directive's link function:
Injecting service to Directive
The solutions I've seen keep the link function within the scope of the directive:
angular.module('myapp')
.directive('myDir', function(myService){
return {
restrict: 'E',
scope: {
frame: '='
},
link: function postLinkFn(scope, elem, attr) {
myService.doSomething();
}
};
});
However, I want to be able to separate the postLinkFn outside of the .directive scope for organization, just like I can do with controllers.
Is it possible to separate this function while also injecting a service into it?
.directive('myDir', function(myService){
var deps = { myService: myService };
return {
...
// myService is available as this.myService inside postLinkFn
link: angular.bind(deps, postLinkFn)
};
});
link function doesn't make use of dependency injection and doesn't have lexical this, binding injected dependencies to this is a reasonable move.
Sure you can put your code in a factory and then refer it globally across the app.
angular.module('myapp').factory('myfactory', myService, function(){
return{
var myfac;
my fac = function (myService){
var myItem = myService.doSomething;
return myItem;
};
};
}).
.directive('myDir', function(myService){
return {
restrict: 'E',
scope: {
frame: '='
},
link: myfactory.myItem;
};
});'
Just a little care you need to take is binding your factory with an angular promise $q if your service deals with asynchronous calls.
Hi I am trying to learn AngularJS Directives and I came really close but would like to extend my learning by cleaning and de-coupling my directive code.
Directive:
app.directive('ngSparkline', function () {
var url = "http://api.openweathermap.org/data/2.5/forecast/daily?mode=json&units=imperial&cnt=14&callback=JSON_CALLBACK&q=";
return {
restrict: 'A',
require: '^ngCity',
transclude: true,
scope: {
ngCity: '#'
},
templateUrl: 'app/partials/weatherTemplate.html',
controller: ['$scope', '$http', function($scope, $http) {
$scope.getTemp = function(city) {}
}],
link: function (scope, iElement, iAttrs) {
scope.getTemp(iAttrs.ngCity);
scope.$watch('weather', function (newVal) {
if (newVal) {
var highs = [];
angular.forEach(scope.weather, function (value) {
highs.push(value.temp.max);
});
chartGraph(iElement, highs, iAttrs);
}
});
}
};
});
As you can see I am not trying to write inline template rather use templateUrl. Now the problem is for the controller when I try using a .js controller instead of writing the controller code inline, I receive an error. How do I achieve this.
I tried:
I tried passing
controller: '#',
name: 'ctrl'
and I pass the 'ctrl' as:
<div ng-sparkline ng-city="San Francisco" ctrl="weatherController"></div>
it gives me controller not found. My project structure is something like below.
What am I doing wrong?
Is there a better/correct way of doing this?
Please suggest.
Note: I am learning this exercise from "http://www.ng-newsletter.com/posts/directives.html"
Why not just specify ng-controller on your element? If WeatherController is defined somewhere else then it doesn’t affect your directive definition, just leave the controller out of there.
<div ng-sparkline ng-city="San Francisco" ng-controller="WeatherController"></div>
Provided somewhere you do have the controller defined like
app.controller('WeatherController', ['$scope', '$http', function ($scope, $http) {
$scope.getTemp = // …
}]);
(BTW, if you noticed, the AngularJS convention is to name controllers in UpperCase fashion.)
I try to "require" a parent controller (not directive) but AngularJS returns an exception. The code is like this:
JS
app.controller("myController", function ($scole) {
...
});
app.directive("myDirective", function ($q) {
return {
require: "^myController",
template: "",
link: function (scope, element, attrs, myCtrl) {
...
}
};
});
HTML
<div ng-controller="myController as myCtrl">
...
<div my-directive>...</div>
...
</div>
Error
Error: [$compile:ctreq] Controller 'myController', required by
directive 'myDirective', can't be found!
Why?
Maybe, require property must be reference to a controller of directive?
Thanks
Require is of using other directives controllers in another directive , please refer the below example
var App = angular.module('myApp',[]);
//one directive
App.directive('oneDirective',function(){
return {
restrict: 'E',
controller:function($scope){
$scope.myName= function(){
console.log('myname');
}
}
}
});
//two directive
App.directive('twoDirective',function(){
return {
require:'oneDirective' //one directive used,
link : function(scope,ele,attrs,oneCtrl){
console.log(oneCtrl.myName())
}
}
})
Notation require: "^myController" means that your directive will try to access another directive called myController and defined on some of the ancestor tags as my-controller attribute or <my-controller> tag. In your case you don't have such directive, hence the exception.
This is not very conventional what you are trying to do, but if you really want to require outer controller in your directive you can require ngController:
app.directive("myDirective", function($q) {
return {
require: "^ngController",
template: "",
link: function(scope, element, attrs, myCtrl) {
// ...
console.log(myCtrl);
}
};
});
However, this is not very good idea. I can't imagine why you might need it like this. I would recommend to look into scope configuration properties and how you can pass executable function references into your directive from outer controller.
<div my-directive some-callback="test()"></div>
and in directive define scope:
scope: {
someCallback: '&'
}
where in controller you would have $scope.test = function() {};. Then you would not need to require controller explicitly in directive.
Get response
<section ng-controller="BookingController"></section>
Directive
MyApp.directive "loadThing", ($rootScope, $compile) ->
return {
restrict: "AE",
link: (scope, element, attrs) ->
$.get BASE_URL + '/load/template/' + attrs.loadThing, (response) ->
element.html(response)
$compile(element)
}
I'm loading a template with ajax that has an ng-controller declared in it, but the controller is not being initialized.
What am I doing wrong here?
Link is generally used for event based behavior, I'm not sure why you're using Ajax but you might try declaring your controller and template in the controller. It would look something like this:
MyApp.directive('loadThing', function($rootScope, $compile) {
return {
restrict: "AE",
templateUrl: 'yourPathHere.js',
controller: 'MyController'
}
});
Sigh, was a silly mistake.
Needed to be:
template = $(response)
$compile(template)(scope)
element.append(template)
Key flaw was not calling the function $compile returns.