Why does my directive lose $event? - javascript

I have a custom directive to confirm if a user that clicks an element really wants to perform an action:
.directive('ngReallyClick', ['$modal',
function ($modal) {
return {
restrict: 'A',
scope: {
ngReallyClick: "&",
},
link: function (scope, element, attrs) {
var isDeleteDisabled = scope.ngReallyDisabled;
element.bind('click', function () {
if (isDeleteDisabled != true) {
var message = attrs.ngReallyMessage || "Are you sure ?";
...
var modalInstance = $modal.open({
template: modalHtml,
controller: ModalInstanceCtrl
});
modalInstance.result.then(function () {
scope.ngReallyClick({ ngReallyItem: scope.ngReallyItem }); //raise an error : $digest already in progress
}, function () {
//Modal dismissed
return false;
});
};
});
}
}
}]);
It is used e.g:
<a ng-really-message="Are you sure you want to save and close?" ng-really-click="saveAndCloseGlobal(456)"
where saveAndCloseGlobal is called when the user confirms their choice. But, if I try and pass $event to this function, to get the original click event, it ends up undefined. If I use a plain ng-click=saveAndCloseGlobal($event) then I get the correct event object in saveAndCloseGlobal.

Related

bootstrap modal not close angular js

I am using UI bootstrap modal dialog box with angular js. Modal is successfully loaded. But when I click YES/NO Button, issued occurred & modal did not close.
Error said, ' $uibModal.close is not a function'.
.directive('confirm', function(ConfirmService) {
return {
restrict: 'A',
scope: {
eventHandler: '&ngClick'
},
link: function(scope, element, attrs){
element.unbind("click");
element.bind("click", function(e) {
ConfirmService.open(attrs.confirm, scope.eventHandler);
});
}
}
})
This is my service
.service('ConfirmService', function($uibModal) {
var service = {};
service.open = function (text, onOk) {
var modalInstance = $uibModal.open({
templateUrl: 'modules/confirmation-box/confirmation-box.html',
controller: 'userListCtrl',
resolve: {
text: function () {
return text;
}
}
});
modalInstance.result.then(function (selectedItem) {
onOk();
}, function () {
});
};
return service;
})
This is my controller file. I am trying to yes/no button inside the controller
.controller('userListCtrl',
['$scope','$http','appConfig','$uibModalInstance', '$uibModal','$log','alertService',
function ($scope,$http, appConfig,$uibModalInstance, $uibModal,$log,alertService) {
$scope.ok = function () {
$uibModalInstance.close();
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
}]);
You're attempting to use two usage methods at once time. There are two (probably more) that you can use the $uibModal, but here are the two that I believe you're intermixing:
1) Service controls the modal and returns a promise, I believe this is what I think you're doing. You do not need to call close/dismiss manually in this instance. You can make the following changes:
service.open = function(text, onOK) {
var modalInstance = $uibModal.open({
templateUrl: 'modules/confirmation-box/confirmation-box.html',
controller: 'userListCtrl',
resolve: {
text: function () {
return text;
}
}
});
// Return so you can chain .then just in case. Generally we don't even
// do this, we just return the instance itself and allow the controller to
// decide how to handle results/rejections
return modalInstance.result;
}
In your template file you'd have something like:
<button type="button" ng-click="$close(selectedItem)"></button>
<button type="button" ng-click="$dismiss(readon)"></button>
2) If you want to use the close method directly, then you only need to change the service to:
...
return $uibModal.open({});
then in your controller:
var modal = service.open('confirm');
modal.result.then(...)
modal.close()
Edit - updated with change to op to remove the antipattern as per georgeawg suggestion.

Disable/re-enable button within isolate scope directive in Angular

I need to enable/disable a button after click with Angular. When a user clicks "Submit form", it makes an http request. If an error occurs (inside the catch), I want to re-enable the directive button so that a user can try again. I have a directive with controllerAs syntax and isolateScope. Below is the code I have (simplified for here);
myCtrl parent controller (controllerAs is myCtrl)
vm.submit = function() {
MyService
.update()
.then(function(res) {
// success
})
.catch(function(err) {
vm.error = true;
// error
});
};
Parent view with my-form directive
<my-form form-submit='myCtrl.submit()'></my-form>
myForm Directive
function myForm() {
return {
restrict: 'E',
replace: true,
templateUrl: 'myform.html',
scope: {
formSubmit: '&',
},
require: ['form', 'myForm'],
link: function(scope, element, attrs, ctrls) {
var formCtrl = ctrls[0];
var directiveCtrl = ctrls[1];
scope.isButtonDisabled = false;
scope.submit = function() {
scope.submitted = true;
directiveCtrl.submit();
};
},
controller: function($scope, $element, $attrs) {
var vm = this;
// Submit parent function
vm.submit = function() {
vm.formSubmit();
};
},
controllerAs: 'myFormCtrl',
bindToController: true
};
}
angular.module('mymodule')
.directive('myForm', [ myForm ]);
myForm directive template
<form name='myForm' novalidate>
// form fields
<button ng-click='submit()' ng-disabled='isButtonDisabled'>Submit Form</button>
</form>
Instead of having the promise resolved in the parent controller, you could just pass the promise back to the child controller and handle the logic there. Something like this should work:
parent:
vm.submit = function() {
return MyService.update().$promise;
};
child:
vm.submit = function() {
vm.formSubmit().then(function(res) {
// success
})
.catch(function(err) {
vm.error = true;
// error
scope.isButtonDisabled = false;
});
}

pass parameter to angular directive on click

I am trying to get parameter on click using directive.I want to get child data in the click event for checking has child or not.
.....
html
div ng-app="treeApp">
<ul>
<treeparent></treeparent>
</ul>
js
(function () {
var treeApp = angular.module('treeApp', []);
treeApp.directive('treeparent', function () {
return {
restrict: 'E',
template: "<button addchild child='m'>ajith</button><div id='new'></div>"
}
});
treeApp.directive('addchild', function ($compile) {
return {
scope: {
'child':'='
},
link: function (scope, element, attrs) {
debugger;
element.bind("click", function (scope,attrs) {
debugger;
//here i want to get hild ie 'm'
angular.element(document.getElementById('new')).append("<div><button button class='btn btn-default'>new one</button></div>");
});
}
}
});
})();
plz help me
So, i think scope.child is undefined becouse it is overlaps in declaring event.
You can define variable before event binding
link: function (scope, element, attrs) {
var child = scope.child;
element.bind("click", function (scope,attrs) {
// here you can use child
console.log('child', child);
});
}
or declare different argument names
link: function ($scope, $element, attrs) {
element.bind("click", function (scope,attrs) {
// here you can use $scope.child
console.log('$scope.child', $scope.child);
});
}
Is a callback has scope and attrs argument? May be it has only one $event argument?
link: function (scope, element, attrs) {
element.bind("click", function ($event) {
// here you can use child
console.log('child', scope.child);
});
}
Example for call method from directive in parent scope
parent template
<test-dir data-method="myFunc"></test-dir>
<button ng-click="myFunc('world')">click me</button>
or
<button test-dir data-method="myFunc" ng-click="myFunc('world')">click me</button>
directive
.directive('testDir', function() {
return {
scope: {
method: '=',
},
controller : function($scope) {
$scope.method = function(text) {
alert('hello '+text);
};
},
};
})

how to send an object to angular directive on a check-box

i am trying to consume iCheck check box using a directive. my directive is setup like this.
.module('app').directive('bootstrapCheck', ['$timeout', '$parse', function ($timeout, $parse) {
return {
compile: function (element, $attrs) {
var icheckOptions = {
checkboxClass: 'icheckbox_minimal',
radioClass: 'iradio_minimal'
};
var modelAccessor = $parse($attrs['ngModel']);
return function ($scope, element, $attrs, controller) {
var modelChanged = function (event) {
$scope.$apply(function () {
modelAccessor.assign($scope, event.target.checked);
});
};
$scope.$watch(modelAccessor, function (val) {
var action = val ? 'check' : 'uncheck';
element.iCheck(icheckOptions, action).on('ifChanged', modelChanged);
});
};
}
};
}]);
my check-boxes are in ng-repeat. i want to send the current object to function to process it further. my html is setup like this.
<input type="checkbox" ng-model="item.isSelected" ng-change="onChangeEvent(item)" bootstrap-check>
modelChanged gets triggered each time i change any check-box. but i am trying to access item inside modelChanged function to process it further. please guide.
You can pass the item to directive scope and access it inside the link function. Along with item you can also pass the onChangeEvent handler to the directive. Try this.
JS
angular.module('app').directive('bootstrapCheck', ['$timeout', '$parse', function ($timeout, $parse) {
return {
scope: {
item: '=',
onChangeEvent: '&'
},
compile: function (element, $attrs) {
var icheckOptions = {
checkboxClass: 'icheckbox_minimal',
radioClass: 'iradio_minimal'
};
var modelAccessor = $parse($attrs['ngModel']);
return function ($scope, element, $attrs, controller) {
var modelChanged = function (event) {
//Here $scope.item will give you the item
//This will trigger the parent controller's onChangeEvent set in the directive markup
$scope.onChangeEvent({ item: $scope.item });
$scope.$apply(function () {
modelAccessor.assign($scope, event.target.checked);
});
};
$scope.$watch(modelAccessor, function (val) {
var action = val ? 'check' : 'uncheck';
element.iCheck(icheckOptions, action).on('ifChanged', modelChanged);
});
};
}
};
}]);
HTML
<input type="checkbox"
ng-model="item.isSelected"
item="item"
on-change-event="onChangeEvent(item)" bootstrap-check>

angular.js directive two-way-binding scope updating

I wanted to use a directive to have some click-to-edit functionality in my front end.
This is the directive I am using for that: http://icelab.com.au/articles/levelling-up-with-angularjs-building-a-reusable-click-to-edit-directive/
'use strict';
angular.module('jayMapApp')
.directive('clickToEdit', function () {
return {
templateUrl: 'directives/clickToEdit/clickToEdit.html',
restrict: 'A',
replace: true,
scope: {
value: '=clickToEdit',
method: '&onSave'
},
controller: function($scope, $attrs) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
$scope.method();
};
}
};
});
I added a second attribute to the directive to call a method after when the user changed the value and then update the database etc. The method (´$onSave´ here) is called fine, but it seems the parent scope is not yet updated when I call the method at the end of the directive.
Is there a way to call the method but have the parent scope updated for sure?
Thanks in advance,
Michael
I believe you are supposed to create the functions to attach inside the linking function:
Take a look at this code:
http://plnkr.co/edit/ZTx0xrOoQF3i93buJ279?p=preview
app.directive('clickToEdit', function () {
return {
templateUrl: 'clickToEdit.html',
restrict: 'A',
replace: true,
scope: {
value: '=clickToEdit',
method: '&onSave'
},
link: function(scope, element, attrs){
scope.save = function(){
console.log('save in link fired');
}
},
controller: function($scope, $attrs) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
console.log('save in controller fired');
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
$scope.method();
};
}
};
});
I haven't declared the functions inside the controller before, but I don't see why it wouldn't work.
Though this question/answer explain it Link vs compile vs controller
From my understanding:
The controller is used to share data between directive instances, not to "link" functions which would be run as callbacks.
The method is being called but angular doesn't realise it needs to run the digest cycle to update the controller scope. Luckily you can still trigger the digest from inside your isolate scope just wrap the call to the method:
$scope.$apply($scope.method());

Categories

Resources