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();
});
};
}]
};
});
Related
I have a button and when I click on that function I need to call a directive.
For this I have writern the following code.before creating directive there is a ng-change function.I have removed ng-change and kept directive as follows,
<button upload-file="selectedDocumentName,loanFolderNumber" ><!-- ng-click="uploadFile(selectedDocumentName,FolderNumber)" -->
How can I take that arguments selectedDocumentName,FolderNumber in my directive.I have tried in the following way,but I am not getting the values.
Directive:-
app.directive('uploadFile',['documentService',function(documentService){
return {
restrict: 'AE',
scope: {
selectedDocumentName: '=',
FolderNumber: '=',
},controller: function($scope){
$scope.selectedDocumentName;
},
link : function($scope,element,attrs){
element.on('click',function(e){
})
}
}
}]);
Try this
<button upload-file obj="obj">A</button>
var myApp = angular.module('myApp',[]);
myApp.directive('uploadFile', function() {
return {
restrict: 'AE',
scope: {
obj1: '='
},controller: function($scope){
$scope.obj2 = JSON.parse(JSON.stringify($scope.obj1))
console.log($scope.obj2.selectedDocumentName);
$scope.obj2.selectedDocumentName = "DEF";
console.log($scope.obj2.selectedDocumentName);
},
link : function($scope,element,attrs){
element.on('click',function(e){
})
}
}
});
myApp.controller('MyCtrl', function ($scope) {
$scope.obj = {selectedDocumentName : "ABC",loanFolderNumber : "DEDF"};
});
Check this fiddle
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 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
How we can get particular isolated scope of the directive while calling link function from controller(parent)?
I am having a directive and repeating it using ng-repeat. Whenever a button in the directive template is clicked it will call a function- Stop() in directive controller which in-turn calls function test() in parent controller, inside test() it will call a method dirSample () in directive's link function.
When I print the scope inside dirSample(), it prints the scope of the last created directive not the one which called it.
How can I get the scope of the directive which called it?
Find the pluker here
.directive('stopwatch', function() {
return {
restrict: 'AE',
scope: {
meri : '&',
control: '='
},
templateUrl: 'text.html',
link: function(scope, element, attrs, ctrl) {
scope.internalControl = scope.control || {};
scope.internalControl.dirSample = function(){
console.log(scope)
console.log(element)
console.log(attrs)
console.log(ctrl)
}
},
controllerAs: 'swctrl',
controller: function($scope, $interval)
{
var self = this;
self.stop = function()
{
console.log($scope)
$scope.meri(1)
};
}
}});
full code in plunker
I've changed the binding of your function from & to = since you need to pass a parameter. This means some syntax changes are in order, and also you need to pass the scope along the chain if you want to have it all the way at the end:
HTML:
<div stopwatch control="dashControl" meri="test"></div>
Controller:
$scope.test = function(scope)
{
console.log(scope);
$scope.dashControl.dirSample(scope);
}
Directive:
.directive('stopwatch', function() {
return {
restrict: 'AE',
scope: {
meri : '=',
control: '='
},
templateUrl: 'text.html',
link: function(scope, element, attrs, ctrl) {
scope.internalControl = scope.control || {};
scope.internalControl.dirSample = function(_scope){
console.log(_scope);
}
},
controllerAs: 'swctrl',
controller: function($scope, $interval)
{
var self = this;
self.stop = function()
{
console.log($scope);
$scope.meri($scope);
};
}
}});
Plunker