I have two directives and I wanted it to use it like so:
<m-list m-searchable></m-list>
So the two directives were m-list and m-searchable, now I want to access and manipulate the scope of the m-list when I attach the m-searchable directive.
I have this:
'use strict';
angular.module('app')
.directive('mList', function () {
return {
restrict: 'E',
scope: {},
controller: function($rootScope) {
var vm = this;
vm.name = 'joey';
},
controllerAs: 'ctrl',
bindToController: true,
templateUrl: '...'
};
});
And my m-searchable looks like this:
angular.module('app')
.directive('mSearchable', function () {
return {
restrict: 'A',
scope: {},
controllerAs: 'ctrl',
bindToController: true,
replace: true,
controller: function($rootScope, $scope) {
// I want console.log the scope of the directive where I attached the `m-searchable`
}
};
});
I want to console.log the scope of the directive where I attached the m-searchable. How do I access vm.name?
Firstly i think you will encounter $compile error due to both directive try to have their own isolated scope on the same element.
https://docs.angularjs.org/error/$compile/multidir?p0=mList&p1=mSearchable&p2=new%2Fisolated%20scope&p3=%3Cm-list%20m-searchable%3D%22%22%3E
Updated : better approach as suggested at http://juristr.com/blog/2015/01/learning-ng-directives-access-scope-controller/
is to pass the object between controller & directive
<m-list m-searchable name="name"></m-list>
app.directive('mList', function () {
return {
restrict: 'E',
scope: { name: "="},
controller: function($rootScope, $scope) {
var vm = this ;
vm.name = 'joey';
},
controllerAs: 'ctrl',
bindToController: true
};
});
http://plnkr.co/edit/OKVicRzjuH6L0xedF2qB?p=preview
Related
How can I call a function from parent controller inside the child directive?
my controller looks something like this.
angular.module('myVillage')
.controller('myVillageController', myVillageController);
function myVillageController($scope, $q, $element, $timeout) {
function moveHome() {
console.log("moved home")
}
}
my directive looks something like this.
angular
.module('myVillage')
.directive('myVillagModal', myVillagModal);
var vm = this,
cachedKeys = {},
limitInit = 500;
function myVillagModal(myVillage, $filter) {
return {
restrict: 'E',
templateUrl: myVillagelTemplateUrl,
bindToController: true,
scope: {
items: '=',
selectedItems:'=',
selectedItemsChanged: '&'
},
transclude: true,
controller: myVillageController,
controllerAs: 'vm'
};
function myVillageController() {
//....
}
}
I want to call the moveHOme function inside the move-village directive.
<div ng-controller="myVillageController">
<move-village></move-village>
</div>
You can try
$scope.$parent.moveHome();
from the child controller.
Thank you, people, for trying to answer.
I was missing to pass $scope inside the myVillagecontroller due to that I was not able to access parent controller scope.
here is my answer.
angular
.module('myVillage')
.directive('myVillagModal', myVillagModal);
var vm = this,
cachedKeys = {},
limitInit = 500;
function myVillagModal(myVillage, $filter) {
return {
restrict: 'E',
templateUrl: myVillagelTemplateUrl,
bindToController: true,
scope: {
items: '=',
selectedItems:'=',
selectedItemsChanged: '&'
},
transclude: true,
controller: myVillageController,
controllerAs: 'vm'
};
function myVillageController($scope) {
//$scope.$parent now gives the scope of parent controller
//....
$scope.$parent.moveHome(); //this gives 'moved home'
}
}
I have following directive structure.
<test-widget-body>
<test-task-list-filter>
</test-task-list-filter>
<test-task-list>
<test-datatable config="dtConfig" columns="dtColumns" api="dtApi"></test-datatable>
</test-task-list>
</test-widget-body>
Here are respective directives:
test-datatable
angular.module('testDatatable').directive('testDatatable', function () {
var directive = {
controller: 'testDatatableController',
restrict: 'E',
replace: true,
scope: {
config: '=',
columns: '=',
api: '=',
},
link: lnkFunction,
template: '<table class="table"></table>',
};
return directive;
}
testTaskList
angular.module('testTask').directive('testTaskList', function () {
return {
transclude: true,
restrict: 'E',
controller: 'testListController',
controllerAs: 'vm',
templateUrl: '/app/test/directives/test-list/test-list.html',
link: {
pre: preLink
}
};
function preLink(){
var dtColumns = [{
----
}];
var dtConfig =[];
var dtApi =[];
}
}
testTaskListFilter
angular.module('testTask').directive('testTaskListFilter', function () {
return {
restrict: 'E',
controller: 'testListFilterController',
templateUrl: '/app/test/directives/test-list/test-list-filter.html'
};
});
testWidgetBody
angular.module('testWidgetGrid').directive('testWidgetBody', function () {
return {
templateUrl: 'test.html',
link: function ($scope, element) {
}
}
Here I'm able to access dtConfig dtColumns dtApi objects inside testListFilterController controller.
How is this possible as <test-task-list-filter> and <test-task-list> are siblings.
Can anyone explain what is happening in this scenario.
Note: I'm able to access that object when I perform some click action not while directive rendering.
If you look at the declarations for testTaskListFilter directive and the testTaskList directive, neither of them have isolate scopes. You can declare isolate scopes by doing one of the following in the directive: scope: true or scope: {} (like in your testDatatable) directive.
Thus, any directive that does not declare its own scope inherits its parent's. So, testTaskListFilter and testTaskList are both using the same scope. This means that you're then able to
access dtConfig dtColumns dtApi objects inside testListFilterController controller
Here's the Angular wiki post for understanding scopes and scope inheritance
I define a directive in angular 1.4,which receives a scope parameter “b”:
(function() {
'use strict';
angular
.module('m')
.directive('mydirective', mydirective);
/** #ngInject */
function mydirective() {
var directive = {
restrict: 'E',
templateUrl: 'app/components/mydirective/mydirective.html',
scope: {
b: '='
},
controller: MydirectiveController,
controllerAs: 'vm',
bindToController: true
};
return directive;
/** #ngInject */
function MydirectiveController($scope, $state) {
var vm = this;
//here How to watch the parameter b to refresh the directive html result?
}
in html page:
<mydirective b="ctrl.b"></myupl>
in the business controller, b is got from an angular resource
PayService.getBusinessNumber().then(function(results){
vm.b = {business_id: results.no};
});
in index.route.js which define the route and the business controller,
$stateProvider
.state('payShowInfo', {
url: '/payShowInfo',
templateUrl: 'app/pay_show_info.html',
controller: 'PayShowController',
controllerAs: 'ctrl'
});
my problem is , When the directive loaded, the parameter “b” is undefined, How to watch controller asynchronous data in angular directive? and then use the new value of “b” to refresh the html page?
If you define the directive parameter as "=", you mean that you will have two way data binding. So if you change the value in the controller, you will have the change reflected in the view.
angular.module('nib', [])
.directive('mydirective', function ($timeout) {
return {
restrict: 'E',
scope: {
b: '='
},
link: function ($scope, element, attrs) {
},
template: '<div>Test: {{b}}</div>'
};
})
.controller('ctrl',function($scope){
$scope.click = function(){ // emulating asynchronous request
$scope.test = 'testing';
}
})
See in the plnkr below:
http://plnkr.co/3qs1NpU1aIhKzxyCMXjh?p=preview
This is a followed up question from this.
How can I access a property defined in MyController from MyDirectiveController to change its value or just read it and use it for something else? (commented line in the code).
angular
.module("app",[])
.controller('MyController', MyController)
.controller('MyDirectiveController', MyController)
.directive('myDirective', myDirective);
function MyController() {
var vm = this;
vm.foo = 'fooController';
}
function myDirective() {
return {
restrict: 'E',
scope: true,
controller: MyDirectiveController,
controllerAs: 'vm',
template: '{{vmMy.foo}} - {{vm.foo}}'
}
}
function MyDirectiveController() {
var vm = this;
vm.foo = 'fooDirective';
// vmMyfoo = 'fooDirective';
}
Here is the jsfiddle.
You can use bindToController (available from v1.3.x) setting of directive to bind values to controller instance instead of scope object.
function myDirective() {
return {
restrict: 'E',
scope: {
value: '='
},
controller: MyDirectiveController,
controllerAs: 'vm',
bindToController: true,
template: '{{vm.value}} - {{vm.foo}}'
}
}
and in HTML you pass value to directive like this:
<div ng-controller="MyController as vmMy">
<my-directive value="vmMy.foo"></my-directive>
</div>
I have a directive with dynamic controller which is passed via controller-name property.
Directive:
angular
.module('directives.panel', [])
.directive('panel', panel);
panel.$inject = ['$timeout', '$parse'];
function panel($timeout, $parse) {
var directive = {
restrict: 'EA',
transclude: true,
replace: true,
template: '<div class="panel panel-solid panel-table" ng-transclude></div>',
controller: '#',
name: 'controllerName',
controllerAs: 'panel',
link: linkFunc
};
return directive;
}
}
Is it possible to inject resolve 'taskbook' object into dynamic controller?
When I try to do that I get unknown provider. However injecting Resource service (GroupResource) works fine.
Is it possible to inject resolve in directive controller?
State
angular
.module('taskbooks.taskbook', [
'deployment.group',
'resource.deployment',
'resource.taskbook'
])
.config(TaskbookConfig)
.controller('TaskbookController', TaskbookController);
TaskbookConfig.$inject = ['$stateProvider', '$provide'];
function TaskbookConfig($stateProvider) {
$stateProvider
.state('taskbooks.taskbook', {
url: 'taskbooks/:taskbookId',
parent: 'taskbooks',
views: {
"mainContent#taskbooks": {
controller: 'TaskbookController as taskbook',
templateUrl: 'taskbook/taskbook.tpl.html'
}
},
resolve: {
taskbook: TaskbookPrepare
}
});
}
TaskbookPrepare.$inject = ['$stateParams', 'TaskbookResource'];
function TaskbookPrepare($stateParams, TaskbookResource) {
return TaskbookResource.get({
taskbookId: $stateParams.taskbookId
}).$promise;
}
Directive Controller
angular
.module('deployment.groups', ['resource.group'])
.controller('DeploymentGroupController',DeploymentGroupController);
DeploymentGroupController.$inject = ['$scope', '$element', '$attrs', 'GroupResource', 'taskbook'];
function DeploymentGroupController($scope, $element, $attrs, GroupResource, taskbook) {
}
Sort of... If this directive requires the resolve that is associated with this state, then it's safe to assume it will only ever be used in this state, correct?
Going on that idea, the directive can reference the controller set in the state and you can add the resolve to the controller scope.
Here's a very simplified version of what I'm saying...
angular
.module('taskbooks.taskbook')
.config([ $stateProvider, function ($stateProvider) {
$stateProvider
.state('taskbook', {
url: '/:id',
parent: 'taskbooks',
resolve: {
taskbook: [ '$stateParams', 'TaskbookResource', function ($stateParams, TaskbookResource) {
return TaskbookResource.get({
taskbookId: $stateParams.taskbookId
}).$promise;
}]
},
controller: ['taskbook', function (taskbook) {
this.taskbook = taskbook;
}],
controllerAs: 'taskController'
});
}])
.directive('someDirective', function() {
return {
restrict: 'EAC',
controller: 'taskController',
link: function (scope, el, attr, ctrl) {
var taskbook = ctrl.taskbook;
}
}
});
Do note, I removed a lot of the non-relevant code from yours just to get the point across quicker. Obviously this can be reworked into the structure you've written.