I have
<div id="content"><div>
I want to insert my directive. I did
html = $compile('<test></test>')($scope);
$("#content").html(html);
My directive:
app.directive("test", function ($compile, $route) {
return {
restrict: "E",
templateUrl: "/Templates/test.html",
controller: function ($scope, $location) {},
controllerAs: "page"
};
});
"/Templates/test.html":
... some code ...
<category></category>
directives test and category upload some data from server.
For some reasons category works, but test doesn't.
Anybody knows why?
Thanks
You could be required to recompile your directive. Add following code at the end of link function:
$compile(element.contents())(scope);
Some useful info here: $complie
Related
In my Angular template I use an attributive directive as follows:
HTML:
<div id="my-template-one" my-template-directive></div>
JS:
// ...
.directive('myTemplateDirective', ['myconfig', function (myconfig) {
return {
templateUrl: myconfig.TEMPLATE_PATH + 'my-template-one.html',
controller: function ($scope, $rootScope) {
// code
},
controllerAs: 'dir'
}
}]);
For including another template, my-template-two.html, on another page, I would like to use the same directive. I do not want to duplicate the directive. How can I pass the template as an variable?
HTML on another page:
<div id="my-template-two" my-template-directive></div>
My goal is that somehow I can tell my directive to render my-template-two.html when this HTML is called.
The templateUrl property value may be a function which takes two arguments tElement and tAttrs and returns a string value:
app.directive('myTemplateDirective', ['myconfig', function (myconfig) {
return {
templateUrl: function (tElem, tAttrs) {
var template = "my-template-one.html";
if (tAttrs.use) {
template = tAttrs.use;
};
return myconfig.TEMPLATE_PATH + template;
},
controller: function ($scope, $rootScope) {
// code
},
controllerAs: 'dir'
}
}]);
Usage
<div my-template-directive use="my-template-two.html"> </div>
For more information, see AngularJS Comprehensive Directive API -- template
I created angularjs directives:
'use strict';
angular.module('frontend')
.directive('overall', function() {
return {
restrict: 'E',
scope: {
data: '=data'
},
templateUrl: 'app/components/overall/overall.html',
controller: function($scope) {
alert($scope.data)
}
};
});
and template for him:
<div id="inner-overall">
Taras
</div>
After it in other page I use my directive like this:
<overall data></overall>
and js code:
$scope.data = 'daadad';
But it is not working, and I catch empty $scope.data value.
I don't know why it happens and how to fix it, help me please with this issue. Thanks a lot!
You didn't bind model that's why it's empty
Try like this
<overall data="data"></overall>
When I wrote a custom directive, a strange error blocks me.
angular.module('app.directives', [])
.directive('cyMenu', ['RecursionHelper', function(RecursionHelper) {
function postLink(){};
return {
restrict: 'E',
templateUrl: 'views/component/cy-menu.html',
replace: true,
transclude: false,
require: '?^cyMenu',
controller: function ($scope) { // when set this argument($scope) to scope, error occurs.
this.getList = function() {
return $scope.list;
}
},
scope: {
list: '=',
isSubmenu: '#'
},
compile: function(tElement) {
return RecursionHelper.compile(tElement, postLink);
}
}
}
As I pointed out(see comment), when I set controller attribute to controller: function (scope) {}, the error occurs:
Error: [$injector:unpr] Unknown provider: scopeProvider <- scope
http://errors.angularjs.org/1.3.6/$injector/unpr?p0=scopeProvider%20%3C-%20scope
...
I don't know why. Any help will be appreciated.
update
Here is angular's official demo, it looks similar to my directivehttps://code.angularjs.org/1.3.6/docs/guide/directive:
angular.module('docsTabsExample', [])
.directive('myTabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope) {
...
},
templateUrl: 'my-tabs.html'
};
})
A very good practice is to separate every component in a separate file, so I would start by putting your controller in a file like that :
//File recursionHelperController.js
(function() {
'use strict';
angular
.module('app.controllers')
.controller('RecursionHelperController', RecursionHelperController);
RecursionHelperController.$inject = ['$scope'];
function RecursionHelperController($scope) {
//do your stuff
}
})();
Note that I gave you the most correct format I know for a controller or any angular element in general, but you can do something simpler like:
angular.module('app.controllers')
.controller('RecursionHelperController', ['$scope', function($scope) {
//do your stuff
}])
You can then call this controller in your main file :
controller: 'RecursionHelperController'
Hope it helps
Update :
Sometimes the automatic injection has some troubles that's why I recommend doing it this way with an explicit injection. The angular doc only shows the simplest way for clarity and tutorial purposes
Update 2
If you don't want to separate the controller, try using the injection safe notation
controller : ['$scope', function($scope) {
//do your stuff
}])
I have a set of tabs which all have a directive in them:
<div class="col-md-9 maincols" id="formEditor">
<tabset>
<tab heading="New subscriber" select="isSelected('newSub')">
<new-subscriber></new-subscriber>
</tab>
<tab heading="Existing subscriber" select="isSelected('existingSub')">
<existing-subscriber></existing-subscriber>
</tab>
<tab heading="Landing page" select="isSelected('landing')">
<landing-page></landing-page>
</tab>
</tabset>
</div>
All these 3 directives have been defined similarly like this:
angular.module('myApp')
.directive('newSubscriber', function () {
return {
restrict: 'E',
scope: {},
replace: true,
templateUrl: 'scripts/newsubscriber/newsubscriber.html',
controller: 'newsubscriberCtrl'
};
}); //... and so on
I am (probably wrongly) under the impression that because I have set scope: {} for all the directives, they should now have completely isolated scopes and leave each other alone.
But that is not the case and bindings from the first directive's controller manage to stop values in the second or third controller from being binded
for example in newsubscriberCtrl I have:
app.controller('newsubscriberCtrl', ["$scope", "$routeParams", "UserMessages", "FormProvider", function ($scope, $routeParams, UserMessages, FormProvider) {
$scope.formId = $routeParams.formId;
var newSubscriberForm = new FormProvider.Form($scope);
angular.extend($scope, newSubscriberForm);
$scope.title = UserMessages.exampleText.genericPageTitle;
$scope.description = UserMessages.exampleText.genericPageDescription;
$scope.validationMessages = {
contactNotSaved: UserMessages.validationMessages.contactNotSaved,
contactCreatedOk: UserMessages.validationMessages.contactCreatedOk,
contactNotCreated: UserMessages.validationMessages.contactNotCreated,
requiredField: UserMessages.validationMessages.requiredField,
passwordMismatch: UserMessages.validationMessages.passwordMismatch,
isOpen: false
}
}]);
which is overriding the similar object in existingSubscriber controller:
app.controller('existingsubscriberCtrl', ["$scope", "$routeParams", "UserMessages", "FormProvider", function ($scope, $routeParams, UserMessages, FormProvider) {
$scope.formId = $routeParams.formId;
var existingSubscriberForm = new FormProvider.Form($scope);
angular.extend($scope, existingSubscriberForm);
$scope.title = UserMessages.exampleText.genericPageTitle;
$scope.description = UserMessages.exampleText.genericPageDescription;
$scope.validationMessages = {
contactNotSaved: UserMessages.validationMessages.contactNotSaved,
contactSavedOk: UserMessages.validationMessages.contactSavedOk,
requiredField: UserMessages.validationMessages.requiredField,
passwordMismatch: UserMessages.validationMessages.passwordMismatch,
isOpen: false
}
}]);
So in the view of both directives <pre>{{validationMessages | json }}</pre> the validationMessages object has the props of the first controller.
Why is this happening? Am I missing to understand a concept here? How Can I isolate these controllers from each other and comfortably have similar props in the controllers without them affecting each other?
Side note: I strongly want to avoid having to prefix everything on all scopes with their controller name, e.g $scope.newSubscriber.validationMessages and so on... as that would defeat the whole point pretty much as I will effectively one big controller for the whole tab section and directives would also be pointless.
Angular is on v.1.3.0-beta.11
angular-ui-bootstrap is on v.0.10.0
You have reuse the same controller newsubscriberCtrl in /app/scripts/formbanner/formbanner.js:
.directive('formBanner', function () {
return {
restrict: 'E',
replace: 'true',
templateUrl: 'scripts/formbanner/formbanner.html',
controller: 'newsubscriberCtrl'
};
});
The existingSubscriber directive have the formBanner as a child directive, plus the formBanner directive doesn't have an isolated scope.
Therefore, the $scope that get injected into the newsubscriberCtrl of formBanner is the same as the scope of the existingSubscriber!!
I've tried removing the controller property in the formBanner directive and I saw it works as expected.
Have you tried this?
angular.module('myApp')
.directive('newSubscriber', function () {
return {
restrict: 'E',
scope: { someValue = "&validationMessages" },
replace: true,
templateUrl: 'scripts/newsubscriber/newsubscriber.html',
controller: 'newsubscriberCtrl',
link: function (scope, iElm, iAttrs) {
var x = scope.someValue();
// x = your messages
}
};
});
In your controller
$scope.someValue
EDIT Disclaimer: this is sort of from memory. When I was facing something similar I felt this to be rather enlightning:
http://umur.io/angularjs-directives-using-isolated-scope-with-attributes/
Can anyone tell me how to include a controller from one directive in another angularJS directive.
for example I have the following code
var app = angular.module('shop', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
templateUrl: '/js/partials/home.html'
})
.when('/products', {
controller: 'ProductsController',
templateUrl: '/js/partials/products.html'
})
.when('/products/:productId', {
controller: 'ProductController',
templateUrl: '/js/partials/product.html'
});
}]);
app.directive('mainCtrl', function () {
return {
controller: function ($scope) {}
};
});
app.directive('addProduct', function () {
return {
restrict: 'C',
require: '^mainCtrl',
link: function (scope, lElement, attrs, mainCtrl) {
//console.log(cartController);
}
};
});
By all account I should be able to access the controller in the addProduct directive but I am not. Is there a better way of doing this?
I got lucky and answered this in a comment to the question, but I'm posting a full answer for the sake of completeness and so we can mark this question as "Answered".
It depends on what you want to accomplish by sharing a controller; you can either share the same controller (though have different instances), or you can share the same controller instance.
Share a Controller
Two directives can use the same controller by passing the same method to two directives, like so:
app.controller( 'MyCtrl', function ( $scope ) {
// do stuff...
});
app.directive( 'directiveOne', function () {
return {
controller: 'MyCtrl'
};
});
app.directive( 'directiveTwo', function () {
return {
controller: 'MyCtrl'
};
});
Each directive will get its own instance of the controller, but this allows you to share the logic between as many components as you want.
Require a Controller
If you want to share the same instance of a controller, then you use require.
require ensures the presence of another directive and then includes its controller as a parameter to the link function. So if you have two directives on one element, your directive can require the presence of the other directive and gain access to its controller methods. A common use case for this is to require ngModel.
^require, with the addition of the caret, checks elements above directive in addition to the current element to try to find the other directive. This allows you to create complex components where "sub-components" can communicate with the parent component through its controller to great effect. Examples could include tabs, where each pane can communicate with the overall tabs to handle switching; an accordion set could ensure only one is open at a time; etc.
In either event, you have to use the two directives together for this to work. require is a way of communicating between components.
Check out the Guide page of directives for more info: http://docs.angularjs.org/guide/directive
There is a good stackoverflow answer here by Mark Rajcok:
AngularJS directive controllers requiring parent directive controllers?
with a link to this very clear jsFiddle: http://jsfiddle.net/mrajcok/StXFK/
<div ng-controller="MyCtrl">
<div screen>
<div component>
<div widget>
<button ng-click="widgetIt()">Woo Hoo</button>
</div>
</div>
</div>
</div>
JavaScript
var myApp = angular.module('myApp',[])
.directive('screen', function() {
return {
scope: true,
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('component', function() {
return {
scope: true,
require: '^screen',
controller: function($scope) {
this.componentFunction = function() {
$scope.screenCtrl.doSomethingScreeny();
}
},
link: function(scope, element, attrs, screenCtrl) {
scope.screenCtrl = screenCtrl
}
}
})
.directive('widget', function() {
return {
scope: true,
require: "^component",
link: function(scope, element, attrs, componentCtrl) {
scope.widgetIt = function() {
componentCtrl.componentFunction();
};
}
}
})
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
}