Injecting resolve into directive with dynamic controller - angularjs

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.

Related

How to access function of a parent controller inside the child directive

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'
}
}

Why when passing object inside the directive tag I get string

I don't have access to the object which I'm passing it inside my directive.
// inside dialogController
showAlert(ev) {
this.mdDialog.show({
template:"<loader my-master="+this.masterCtrl+"></loader>"
});
// when debugging, I saw this.masterCtrl is exist as Object
//inside loader Controller:
export function loader() {
'ngInject';
let directive = {
templateUrl: "app/components/excelLoader/loader.html",
controller: loaderController,
controllerAs: 'vm',
scope: {
words: '=',
master:'=myMaster'
},
replace: true,
bindToController: true,
link: linkFunc
};
function linkFunc(scope, element, attr, ctrl) {
let vm = scope.vm;
ctrl.master=attr.myMaster;
}
return directive;
}
class loaderController {
constructor() {
'ngInject';
console.log(this.master); //prints string "this.masterCtrl" instead of the Object!
}
}
What is the correct way to pass this.masterCtrl from dialogController into loader directive and how to use access it in the loader directive?
Is this what you want? - CodePen
Markup
<div ng-controller="MyController as vm" ng-cloak="" ng-app="app">
<md-button class="md-primary md-raised" ng-click="vm.openDialog($event)">
Dialog
</md-button>
</div>
JS
angular.module('app',['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('MyController', function($scope, $mdDialog) {
var vm = this;
vm.testObject = {test: "blah"};
vm.openDialog = function(ev) {
$mdDialog.show({
controller: 'DialogController',
controllerAs: 'DialogCtrl',
template: '<loader my-master="vm.testObject"></loader>',
parent: angular.element(document.body),
scope: $scope,
preserveScope: true,
targetEvent: ev,
clickOutsideToClose:true
});
};
})
.controller('DialogController', function($scope, $mdDialog) {
})
.directive("loader", loader);
function loader() {
return {
template: "<div>Loader directive - {{vm.master.test}}</div>",
controller: loaderController,
controllerAs: 'vm',
scope: {
words: '=',
master:'=myMaster'
},
replace: true,
bindToController: true,
};
function loaderController ($scope) {
console.log($scope.vm.master);
}
}
In your link function, assign ctrl.master = scope.master; attr.myMaster will read the attribute value from the html tag and will be a string. scope.master will be evaluated by angular.

How to watch controller asynchronous data in angular directive

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

Adding a Directive to a Controller using "Controller as" syntax

I have been learning about the kind of "new" "Controller as" syntax. While I find that the syntax is clearer for readability sometimes to do a relative simple thing it just gets more complicated, for example when adding a Directive to a Controller.
How would this simple sample be done with the "Controller As" syntax?
Plunk Sample
I tried something like this:
app.directive('myCustomer', myCustomer);
function myCustomer() {
return {
restrict: 'E',
scope:{ customer: '=info'},
//templateUrl: 'my-customer.html',
template:'Name: {{vm.customer.name}} Address: {{vm.customer.address}}',
controller: Controller,
controllerAs: 'vm',
bindToController: true
};
}
I don't quite get it to work just as the regular "$scope" syntax. Maybe I am missing something.
Note: The sample uses Angular 1.5.5
Check this fork of your plunk: https://plnkr.co/edit/7iA3JMhuUlvIQN9ORs81?p=preview
.directive('myCustomer', function() {
return {
restrict: 'E',
scope: {
customerInfo: '=info'
},
controllerAs: 'vm',
controller: ['$scope', function(scope){
console.log(scope.customerInfo);
}],
templateUrl: 'my-customer-iso.html'
};
});
UPD
code should be like so:
(function(angular) {
'use strict';
angular.module('docsIsolateScopeDirective', [])
.controller('Controller', ['$scope', function($scope) {
$scope.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
$scope.igor = { name: 'Igor', address: '123 Somewhere' };
}])
.directive('myCustomer', function() {
return {
restrict: 'E',
scope: {
customerInfo: '=info'
},
controllerAs: 'vm',
bindToController: true, //the missing line!!
controller: 'dirCtrl',
templateUrl: 'my-customer-iso.html'
};
})
.controller('dirCtrl', ['$scope', dirCtrl]);
function dirCtrl() {
//var vm = this; //no need in this!
}
})(window.angular);
and
Name: {{vm.customerInfo.name}} Address: {{vm.customerInfo.name}}
in the template
I din't manage to fully replicate the initial example from the official angular docs. Directives are quite tricky and I was missing something important about the Isolate Scope "=". I was not getting the value from the controller through the directive with the "=" as the original docs example. #shershen's answer is the right one.
(function() {
'use strict';
var app= angular.module('docsIsolateScopeDirective', []);
app.controller('Controller', [function() {
var vm=this;
vm.naomi = { name: 'Naomi', address: '1600 Amphitheatre' };
vm.igor = { name: 'Igor', address: 'Homeless' };
vm.name="John";
}]);
app.directive('myCustomer', function() {
return {
restrict: 'E',
scope: {
},
templateUrl: 'my-customer-iso.html',
controller: 'Controller',
link: function(scope, elem, attr, ctrl) {
var variableName=attr.info;
scope.customerInfo=ctrl[variableName];
}
};
});
})();
Here is the final plunk.

Accessing scope from parent directive angularjs

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

Resources