I have this directive definition and want to pass currentScriptPath to the TestController.
How do I do that?
(function(currentScriptPath){
angular.module('app', [])
.directive('test', function () {
return {
restrict: 'E',
scope: {},
templateUrl: currentScriptPath.replace('.js', '.html'),
replace: true,
controller: TestController,
controllerAs: 'vm',
bindToController: true
};
});
})(
(function () {
var scripts = document.getElementsByTagName("script");
var currentScriptPath = scripts[scripts.length - 1].src;
return currentScriptPath;
})()
);
TestController.$inject = ['$scope'];
function TestController($scope) {
// try to access $scope.currentScriptPath here
}
As you want to access currentScriptPath in your directive controller. You need to only attach that variable into your current scope inside link function of directive & that scope would be make currentScriptPath available to you controller TestController scope because you have used bindToController: true, in your directive.
Markup
<div ng-controller="Ctrl">
<test></test>
</div>
Directive
(function(currentScriptPath) {
angular.module('app', [])
.directive('test', function() {
return {
restrict: 'E',
scope: {},
templateUrl: currentScriptPath.replace('.js', '.html'),
replace: true,
controller: TestController,
controllerAs: 'vm',
bindToController: true,
link: function(scope, element, attrs) {
scope.currentScriptPath = currentScriptPath; //will update the value of parent controller.
}
};
});
})(
(function() {
var scripts = document.getElementsByTagName("script");
var currentScriptPath = scripts[scripts.length - 1].src;
return currentScriptPath;
})()
);
Controller
function TestController($scope, $timeout) {
var vm = this;
$timeout(function() {
alert($scope.currentScriptPath) //gets called after link function is initialized
})
}
Demo Plunkr
Related
When opening a bootstrap ui modal, if you prefer to use a directive, rather than separately a templateUrl and controller, how can you then in the controller of the directive for the modal, access $uibModalInstance in order to close the modal or whatever you need to do? Also, how can we pass items without having to add it as an attribute on the template?
angular.module('myModule', ['ui.bootstrap'])
.directive('myDirective', ['$timeout', function ($timeout) {
var controllerFn = ['$scope', '$uibModal', function ($scope, $uibModal) {
$scope.names = ['Mario','Wario','Luigi'];
$scope.openModal = function () {
var modalInstance = $uibModal.open({
animation: true,
template: '<my-modal>',
size: 'lg',
resolve: {
items: function () {
return $scope.names;
}
}
});
};
}];
return {
restrict: 'E',
templateUrl: '/Folder/my-directive.html',
controller: controllerFn,
scope: {
}
};
}])
.directive('myModal', ['$timeout', function ($timeout) {
var controllerFn = ['$scope', function ($scope) {
}];
return {
restrict: 'E',
templateUrl: '/Folder/my-modal.html',
controller: controllerFn,
scope: {
}
};
}]);
I use something like that to send parameter to modal, add an element to array and give it back to directive.
// Directive who open modal
.directive('myDirective', ['$timeout', function ($timeout) {
var controllerFn = ['$scope', '$uibModal', function ($scope, $uibModal) {
// Base array
$scope.names = ['Mario','Wario','Luigi'];
$scope.openModal = function () {
// Modal instance
var modalInstance = $uibModal.open({
animation: true,
template: '<my-modal>',
size: 'lg',
controller: 'myDirectiveModalCtrl',
controllerAs: '$modalController',
resolve: {
// Provide namesInModal as service to modal controller
namesInModal: function () {
return $scope.names;
}
}
});
// When modal close, fetch parameter given
modalInstance.result.then(function (namesFromModal) {
$scope.names = namesFromModal;
}, function () {
// $log.info('Modal dismissed at: ' + new Date());
});
};
}];
return {
restrict: 'E',
templateUrl: '/Folder/my-directive.html',
controller: controllerFn,
scope: {
}
};
}])
// Modal controller
.controller('myDirectiveModalCtrl', ['$uibModalInstance','namesInModal',
function ($uibModalInstance, namesInModal) {
// Use same name set in myDirective.controllerAs
var $modalController = this;
// Get provided parameter as service
$modalController.names = namesInModal;
// Add new element
$modalController.names.push('peach');
// Return modal variable when close
$modalController.ok = function () {
$uibModalInstance.close($modalController.names);
};
$modalController.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}
]);
In the directive's link function, $uibModalInstance is available on the scope object.
ShowPopover doesn't work when you click on the directive. Could you please help me identify the cause of the problem?
Directive:
angular.module('landingBuilder').directive('popoverDirective', popoverDirective);
function popoverDirective() {
return {
restrict: 'E',
templateUrl: '/libs/landing-builder/directive/popover-directive/popover-directive.html',
controller: controller,
controllerAs: 'vm',
transclude: true,
bindToController: true
};
function controller($element, $document){
var vm = this;
vm.showPopover = showPopover();
function showPopover() {
console.log('show popover');
};
}
}
Template:
<div class="input-layover popup-target" ng-click="vm.showPopover"</div>
Use showPopover() instead of showPopover here.
myApp.directive('myDirective', function() {
return {
restrict: 'E',
template: '<button ng-click=vm.showPopover()>hello</button>',
controller: controller,
controllerAs: 'vm',
transclude: true,
bindToController: true
};
function controller($element, $document) {
var vm = this;
vm.showPopover = showPopover;
function showPopover() {
console.log('show popover');
};
}
});
Working Fiddle
Look at this fiddle: https://jsfiddle.net/ns0pe1ur/
You made some mistakes in your code:
it is not proper html
you need to call function on ng-click, not inside you controller
Your template should look like this:
<div class="input-layover popup-target" ng-click="vm.showPopover()"></div>
And you controller like this:
function controller($element, $document) {
var vm = this;
vm.showPopover = showPopover;
function showPopover() {
console.log('show popover');
};
}
I need some help on how to pass controllers definitions to inner directive nested in outer directive. Please see http://plnkr.co/edit/Om2vKdvEty9euGXJ5qan for a (not)working example.
Is there any way to make angular interpolate what is passed on script.js#46 as item.ctrlName?
How to use controllerAs syntax in inner directive?
1) if you need the inner directive to have the parent controller you can use the require params on the inner directive. Something like this
angular.module('docsTabsExample', [])
.directive('outer', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: '...', // or template
controllerAs: 'outer',
bindToController: true, // This bind the scope with the controller object
controller: function(scope, element, attrs) {
}
}
})
.directive('inner', function() {
return {
require: '^outer',
restrict: 'E',
transclude: true,
scope: {
title: '#'
},
controllerAs: 'inner',
bindToController: true, // This bind the scope with the controller object
templateUrl: '...', // or template
controller: function(scope, element, attrs, tabsCtrl) {
// tabsCtrl and all the methods on the outer directive
},
};
});
2) You have set controller: controller and controller is a empty function, but you can set there a function like i did before and make sure of put the bindToController: true
I found the solution going step down (up ?) with the abstraction. I'm dynamically constructing the whole directive configuration object and then lazy registering it.
See http://plnkr.co/edit/pMsgop6u51zPLqkfWaWT
angular.module('app', ['moduleLazyLoader'])
.controller('mainCtrl', ['$log', function ($log) {
this.list = [
{
name: 'asd',
ctrl: [
'ItemAsdCtrl',
function () {
$log.debug('ItemAsdCtrl');
}
]
},
{
name: 'xyz',
ctrl: [
'ItemXyzCtrl',
function () {
$log.debug('ItemXyzCtrl');
}
]
}
];
}])
.directive('outer', ['factoryLazyLoader', '$log', '$compile', function (factoryLazyLoader, $log, $compile) {
function controller () {}
return {
restrict: 'E',
controller: controller,
controllerAs: 'outer',
bindToController: true,
scope: {
list: '=list'
},
link: function (scope, element, attributes) {
var directives = [];
scope.outer.list = scope.outer.list.map(function (ele, idx) {
var directiveSuffix = ele.ctrl[0];
directiveSuffix[0].toUpperCase();
var directiveName = 'item' + directiveSuffix,
directiveAttrName = directiveName.split(/(?=[A-Z])/).join("-").toLowerCase();
directives.push(directiveAttrName);
factoryLazyLoader.registerDirective([
directiveName,
function () {
return {
restrict: 'E',
replace: true,
controller: ele.ctrl[1],
controllerAs: ele.ctrl[0],
bindToController: true,
template: '<div>{{' + ele.ctrl[0] + ' | json}}</div>',
scope: {
item: '=item'
}
}
}
])
return ele;
});
var tpl = '<div>';
angular.forEach(directives, function (val, idx) {
tpl += '<' + val +' item="outer.list[' + idx + ']">' + '</' + val + '>';
});
tpl += '</div>'
// debugger;
element.replaceWith($compile(tpl)(scope))
}
};
}])
I'm trying to build a directive with a controller, which updates a ViewModel-variable and calls a callback-function. In the callback-function the updated variable should be used, but it still got the old value.
HTML:
<div ng-app="app" ng-controller="AppCtrl">
Var: {{vm.var}}
<ng-element var="vm.var" func="vm.func()"></ng-element>
</div>
JavaScript:
var app = angular.module('app', []);
app.controller('AppCtrl', function($scope) {
$scope.vm = {
var: 'One',
func: function() {
alert($scope.vm.var);
}
};
});
app.directive('ngElement', function(){
return {
restrict: 'E',
scope: true,
bindToController: {
var: '=',
func: '&'
},
controllerAs: 'ctrl',
replace: true,
template: '<button ng-click="ctrl.doIt()">Do it</button>',
controller: function() {
this.doIt = function() {
this.var = 'Two';
this.func();
};
}
};
});
So when clicking the button, doIt() ist called, updates var and calls func(). But when func() is executed, var still got the old value "One". Right after the execution the ViewModel gets updated and the value is "Two".
Is there any way to update the ViewModel before executing the function?
JSFiddle
Not sure exactly what your directive is doing, as I've never used bindToController, but this seemed to work:
directive('ngElement', function () {
return {
restrict: 'E',
scope: {
var: '=',
func: '&'
},
replace: true,
template: '<button ng-click="doIt()">Do it</button>',
controller: ['$scope', '$timeout', function($scope, $timeout) {
$scope.doIt = function() {
$scope.var = 'Two';
$timeout(function () {
$scope.func();
});
};
}]
};
});
I want to use the Controller As syntax in my Angular directives for two reasons. It's more plain JS and there's no dependency on the $scope service which will not be available in Angular 2.0.
It works great for a single directive but I cannot figure out how to print a property from the controller of a parent directive in a child directive.
function parentCtrl () {
this.greeting = { hello: 'world' };
}
function childCtrl () {}
angular.module('app', [])
.controller('parentCtrl', parentCtrl)
.controller('childCtrl', childCtrl)
.directive('myParent', function () {
return {
scope: {},
bindToController: true,
controller: 'parentCtrl',
controllerAs: 'parent',
template: '<my-child></my-child>'
}
})
.directive('myChild', function () {
return {
scope: {
greeting: '='
},
bindToController: true,
controller: 'childCtrl',
controllerAs: 'child',
template: '<p>{{ greeting.hello }}</p>'
}
});
You have to require the parent controller, the use the link function to inject the parent to the child. The myChild directive would become:
.directive('myChild', function () {
return {
scope: {
// greeting: '=' // NO NEED FOR THIS; USED FROM PARENT
},
bindToController: true, // UNNECESSARY HERE, THERE ARE NO SCOPE PROPS
controller: 'childCtrl',
controllerAs: 'child',
template: '<p>{{ child.greeting.hello }}</p>', // PREFIX WITH VALUE
// OF `controllerAs`
require: ['myChild', '^myParent'],
link: function(scope, elem, attrs, ctrls) {
var myChild = ctrls[0], myParent = ctrls[1];
myChild.greeting = myParent.greeting;
}
}
});
I found that you can use element attributes to pass properties from the parent directive controller's scope to a child.
function parentCtrl () {
this.greeting = 'Hello world!';
}
function myParentDirective () {
return {
scope: {},
controller: 'parentCtrl',
controllerAs: 'ctrl',
template: '<my-child greeting="ctrl.greeting"></my-child>'
}
}
function childCtrl () {}
function myChildDirective () {
return {
scope: {
greeting: '='
},
bindToController: true,
controller: 'childCtrl',
controllerAs: 'ctrl',
template: '<p>{{ ctrl.greeting }}</p><input ng-model="ctrl.greeting" />'
}
}
angular.module('parent', [])
.controller('parentCtrl', parentCtrl)
.directive('myParent', myParentDirective);
angular.module('child', [])
.controller('childCtrl', childCtrl)
.directive('myChild', myChildDirective);
angular.module('app', ['parent', 'child']);