AngularJS - Close modal function not working - angularjs

I have made a simple pop up window by using ui.bootstrap but I can't seem to make the OK and CLOSE button to work. What am I missing in this sample codes?
Here is the sample code from plunkr
Thank you
**added exact code image

close and dismiss are methods of $modalInstance object returned by $modal.open:
$scope.open = function() {
$scope.$modalInstance = $modal.open({
scope: $scope,
templateUrl: "modalContent.html",
size: '',
})
};
$scope.ok = function() {
$scope.$modalInstance.close();
};
$scope.cancel = function() {
$scope.$modalInstance.dismiss('cancel');
};
One more problem with your code is that you need to specify scope: $scope in modal config. This is necessary if you want the scope inside modal template to be a child scope of the one, where you are defining ok/cancel methods.
Fixed demo: http://plnkr.co/edit/Y5s4yPm1TZB8S9nfO5CA?p=preview

I updated your code with a working version
http://plnkr.co/edit/iM5o0le3OioqxHBNF3d1?p=preview
There are a few things wrong with your code.
$modal is a factory, you can't call $modal.close()
You would need to do something like:
this.modal = $modal(....)
this.modal.close();
Still, even if you did this in your controller, your modal view does not have access to the scope.
The solution in the forked plunk I offer is to use
ng-click="$parent.$close()"

There are several ways as explained before and it depends in which context you need to use it.
For example if the modal is just a notification, there's no need to use functions for the buttons OK or CANCEL, just using $dismiss() or $close() in the ng-click of the buttons located in the modalContent.html file will be enough.
Here is also an updated plunker
http://plnkr.co/edit/OfCGJX?p=preview
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$close()">OK</button>
<button class="btn btn-warning" ng-click="$dismiss()">Cancel</button>
</div>

Related

how to make custom directive in angular?

I am trying to make custom directive in angular .I try to add input field in my view when I click on button .In other words I am trying to make one custom directive in which when user press the button it add one input field in the browser .I think it is too easy if I am not use custom directive Mean If I use only controller then I take one array and push item in array when user click on button and button click is present on controller.
But when need to make custom directive where I will write my button click event in controller or directive
here is my code
http://play.ionic.io/app/23ec466dac1d
angular.module('app', ['ionic']).controller('appcontrl',function($scope){
$scope.data=[]
}).directive('inputbutton',function(){
return {
restrict :'E',
scope:{
data:'='
},
template:'<button>Add input</button> <div ng-repeat="d in data"><input type="text"></div>',
link:function(s,e,a){
e.bind('click',function(){
s.data.push({})
})
}
}
})
I just need to add input field when user click on button using custom directive ..could you please tell me where i am doing wrong ?
can we make button template and click event inside the directive
The reason it doesn't work is because your registering your click handler with jQuery. So when the click handler fires it is out of the scope of angular so angular does not know it needs to update its bindings.
So you have two options, the first is to tell angular in the click handler, 'yo buddy, update your bindings'. this is done using $scope.$apply
$apply docs: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply
e.bind('click',function(){
s.$apply(function() {
s.data.push({});
});
});
However angular already has built in directive for handling things like mouse clicks you can just use that and let angular do the work for you. This would be the better option.
so first in your view register a click handler on your button
<button ng-click="add()">Add input</button> <div ng-repeat="d in data"><input type="text"></div>
Then in your link simply add the add() method of your scope
s.add = function () {
s.data.push({});
}
Heres a working fiddle showing both examples. http://jsfiddle.net/3dgdrvkq/
EDIT: Also noticed a slight bug in your initial click handler. You registering a click but not specifying the button to apply it to. So if you clicked anywhere in the directive, not just the button, the handler would fire. You should be more specific when registering events manually, using ids, class names attributes etc.
The e or element property of the link function is a jqlite or full jQuery object of the entire directive. If you have jQuery included before angular it will be a full jQuery object. If not it will a jqlite object. A thinned out version of jQuery.
Here is a basic example for your logic .
var TestApp = angular.module('App', []);
// controller
TestApp.controller('mainCtrl', function mainCtrl($scope) {
$scope.data = [];
$scope.addDataItem = function () {
$scope.data.push({
someFilield: 'some value'
});
console.log('pushing value ... ');
}
});
// view
<div ng-app="App" class="container" ng-controller="mainCtrl">
<button type="button" ng-click="addDataItem()">Add an input</button>
<div ng-repeat="d in data track by $index">
<custom-directive model="d"></custom-directive>
</div>
</div>
// directive
TestApp.directive('customDirective', function customDirective() {
return {
restrict: 'E',
scope: {
model: '='
},
template: 'item -> <input type = "text" />',
link: function (scope, elem, attrs) {
console.log('scope.model', scope.model);
},
controller: function ($scope) {
// do staff here
}
}
});

Pass variable to UI-bootstrap modal without using $scope

Since I am a beginner using AngularJS the $scope approach to pass data between different controllers and (in my case) a modal drives me crazy. Due to that reason, I googled around the web and found an interesting blogpost about passing data to a UI-bootstrap modal without using $scope.
I had a deeper look at this blogpost and the delivered plunk which works pretty nice and started to adopt this to my own needs.
What I want to achieve is to open a modal delivering an text input in which the user is able to change the description of a given product. Since this would provide more than a minimal working example I just broke everything down to a relatively small code snippet available in this plunk.
Passing data from the main controller into the modal seems to work as the default product description is displayed in the modal text input as desired. However, passing the data back from the modal to the main controller displaying the data in index.html does not seem to work, since the old description is shown there after it was edited in the modal.
To summarize my two questions are:
What am I doing wrong in oder to achieve a 'two-way-binding' from the main controller into the modal's text input and the whole way back since the same approach works in the mentioned blogpost (well, as the approach shown in the blogpost works there must be something wrong with my code, but I cannot find the mistakes)
How can I implement a proper Accept button in order to accept the changed description only if this button is clicked and discard any changes in any other case (clicking on Cancel button or closing the modal by clicking next to it)?
In your main controller, create two resolver functions: getDescription and setDescription.
In your modal controller, use them.
Your modal HTML
<div class="modal-header">
<h3 class="modal-title">Test Text Input in Modal</h3>
</div>
<div class="modal-body">
Product description:
<input type="text" ng-model="modal.description">
</div>
<div class="modal-footer">
<button ng-click="modal.acceptModal()">Accept</button>
<button ng-click="modal.$close()">Cancel</button>
</div>
Your main controller
function MainCtrl($modal) {
var self = this;
self.description = "Default product description";
self.DescriptionModal = function() {
$modal.open({
templateUrl: 'modal.html',
controller: ['$modalInstance',
'getDescription',
'setDescription',
ModalCtrl
],
controllerAs: 'modal',
resolve: {
getDescription: function() {
return function() { return self.description; };
},
setDescription: function() {
return function(value) { self.description = value; };
}
}
});
};
};
Your modal controller
function ModalCtrl($modalInstance, getDescription, setDescription) {
var self = this;
this.description = getDescription();
this.acceptModal = function() {
setDescription(self.description);
$modalInstance.close();
};
}

Create search modal directive from angularui modal

I have an application that uses angular-ui bootstrap modal (http://angular-ui.github.io/bootstrap/#/modal) for search from a list and select one of row.
In common using of angular-ui bootstrap modal, we must create two controller (for example ModalDemoCtrl for main modal and ModalInstanceCtrl for modal window).
In second controller, we have two method:
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
that repeat in several place (when I create several search modal).
How to I create a directive (or service), that contains these two controller and create these two methods inside it.
You are wrong - there is one controller for modal window. Second one is for main page and is not related to modals at all. So if u want to have 10 buttons on page to open 10 different modals, then u will have 11 controllers.
For modals that just displays message or ask to confirm actions it is good to have service, so u can write Myservice.showModal('Are you sure?', function callbackafterok() {...}).
If u just dont like repeating $modalInstance.close - make simple directive for buttons with ng-click binding, to write:
<button closeModalWithData="" >Ok</cancel>
or just
<modalOk/> with template <button ng-click="ok()">Ok</button>...
Petr Averyanov's answer was right. I created a directive and towards the end of the documentation for Angular UI modal directive, When we create a modal window, some property adds to $scope.
One of property is $close that we can use it to close modal.
Like this:
.directive('closeModal', function() {
return {
restrict: 'E',
template: '<button ng-click="$close()">Cancel</button>'
};
})

ng-click stops working after the first use of $compile when using nested directives

I have an Angular modal directive that uses a helper/wrapper directive. This way I can always use the same wrapper and just load a different template where needed for different modal content.
PROBLEM: This snippet works, but only for the first life cycle of the modal. So I can fire the modal, close the modal and fire it again. But once the modal is open the second time none of the ng-click directives work. Any tips would be just super.
Usage
<button my-modal="views/login.html">Launch Login-specific Modal</button>
Directive Module (app.js)
angular.module('myModal',[])
.directive('modalWrapper', function(){
return {
replace: true,
templateUrl: 'views/modal.html',
controller: function($scope, $element){
$scope.close = function(){
$element.remove();
};
// NOTE: I use this array to showcase that ng-repeat still works the second time although ng-click stops functioning properly.
$scope.others = ["One", "Two", "Three"];
}
}
})
.directive('myModal', function( $compile){
function link(scope, element, attr){
scope.partial = attr.myModal; // NOTE: Loads sub template via ng-include
var ngModal = $compile('<div modal-wrapper></div>')(scope);
element.on('click', function(){
angular.element('body').append(ngModal);
});
scope.yo = function(){
alert("Yo from inside template.");
};
}
return {
link: link,
scope: {}
}
});
Templates
modal.html
<div class="my-modal">
<p>Modal Wrapper</p>
<div ng-include="partial"></div>
<button ng-click="close()">Close</button>
<p>This just proves that other directives still work (ng-repeat), but ng-click does not.</p>
<div ng-repeat="stuff in others">
<p>{{stuff}}</p>
</div>
</div>
login.html
<h1>Well hey there, I'm the login template.</h1>
<button ng-click="yo()">Say Yo</button>
I think the problem is that you are destroying the scope on which the ng-click is compiled.
When scope.close() is called, an $element.remove() occurs. This both removes the element from the DOM, and destroys the scope to which it is attached. This will result in your ng-click being de-registered.
Unfortunately (as of last time I checked), element.detach() also destroys scope, so your best bet is to compile and append the element to body only once. After this you can use element.show() and element.hide() to show and hide the modal. Alternatively you can recompile the modal each time you want to show it.

Can I change a directive's controller for different instances of the directive?

I have created a directive called modalDialog, which is basically that, a modal dialog. It uses transclude, so I can later do this in my code:
<div modal-dialog id="dialog" dialog-title="This is my Dialog">
...
here goes the content of the dialog
</div>
I want to use this directive in different places of my application, and for different purposes. The content of the dialogs will vary, naturally, so it would be very nice to have a way to pass the Controller to the directive, in the same way that I pass the dialog-title or any other parameter.
I thought about wrapping the modal-dialog in a div, with a controller set on it. Like this:
<div ng-controller="ThisInstanceController">
<div modal-dialog id="dialog" dialog-title="This is my Dialog">
...
here goes the content of the dialog
</div>
</div>
But I don't quite like it. Is there a more elegant way to do it?
Take a look at Angular-UI modals. They have a pretty elegant way of using modals. In short you can pass which controller you'd like to initialize when the modal opens.
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log('Modal dismissed at: ' + new Date());
});
};
The nice part as well is you can pass data with the resolve between controllers.

Resources