Closing Angular 1.5 Material mdDialog from controller - angularjs

In an Angular 1.5 component I'm showing a Material mdDialog, which itself has an embedded component:
$mdDialog.show({
controller: function($scope, $log) {
$scope.notify=function() {
$log.debug("need to cancel");
$mdDialog.hide();
}
},
template: "<md-dialog aria-label='Add Foobar'><new-foobar-panel on-cancel='notify()'></new-foobar-panel></md-dialog>",
targetEvent: ev,
clickOutsideToClose: true,
fullscreen: true
});
When the embedded component invokes the onCancel() callback, the dialog's controller closes the dialog by using $mdDialog.hide().
But that seems sort of messy. The documentation for $mdDialog says that it will close the last opened dialog, but that seems sort of lazy and wishy-washy. I'm sure there is some case with many components and dialogs that would cause this to fail. I'm inside the controller of the dialog after all --- shouldn't there be a reference to the dialog instance I can use to close it directly?
I tried this:
var dialog = $mdDialog.show({
controller: function($scope, $log) {
$scope.notify=function() {
$log.debug("need to cancel");
dialog.hide();
}
But that doesn't work; perhaps a promise is returned instead of a dialog.
So am I stuck with calling $mdDialog.hide() (the global service!!) and hoping that refers to the dialog I'm working with? (That's not very good modularization.)

Actually the documentation says
// Close the specified dialog instance and resolve with 'finished' flag
// Normally this is not needed, just use '$mdDialog.hide()' to close
// the most recent dialog popup.
function closeAlert() {
$mdDialog.hide( alert, "finished" );
alert = undefined;
}
where alert is the dialog instance previously build. So if you actually need to refer to a specific instance of dialog and not the last one, you can use the above method to close it.

Related

Unable to dismiss $modalInstance angular bootstrap $modal

I've opened a modal using $modal.open and taking the return value which is a modal instance to a variable. When I try to close the $modal using that modal instance's either dismiss() or close() methods it is not closing. When I tried to check the $$state.value for the modal instance that I've taken in to variable I don't see it present and $$state.state is also coming as 0. I couldn't understand why is it happening so, could this be reason why I'm not able to close the modal. I could clearly see the modal is opened. Does anyone know why is it so? Has anyone faced the similar issue?
var modalOpened = $modal.open({
templateUrl: modalOptions.template,
controller: modalOptions.cntrlr,
windowClass: modalOptions.winClass,
backdrop: modalOptions.backdrop,
resolve: {
modalParams: function () {
return params;
}
}
});
modalOpened.dismiss('cancel');

ui-router modal window with parent state

There's a lot of documentation about opening modal windows when going to a specific state, some people use 'onEnter', others' use the '$stateChangeStart' event.
But the issue I'm having with both of those is that when going to that url directly, there isn't any content loaded underneath the modal window.
For example:
1. Users goes to www.mysite.com
2. User click the link that opens a model: www.mysite.com/#/signup
3. User sees the signup modal window with the original content underneath
But when a user goes directly to www.mysite.com/#/signup, this doesn't happen.
Currently I have a parent route that handles all my modal windows, as following:
$stateProvider
.state('modal', {
parent: 'home',
abstract: true,
url: '',
data: {
modal: true
},
onEnter: ['$state', '$modal', function($state, $modal) {
console.log('open modal');
$modal.open({
template: '<div ui-view="modal"></div>',
backdrop: true
}).result.then(function() {
$state.go('home');
}, function(reason) {
if(!reason || reason == 'backdrop click') $state.go('home');
});
}]
});
While this works, I want to be able to dynamically set the parent route, as this will be the content that is underneath my modal window.
Is there any way to do this? Or is there any other method that allows me to open the modal window with whatever content is underneath?
Using UI-Router Extra - Sticky States has helped me solve my problem, there's a few issues that there's no underlaying state when you open a modal directly, but those are issues that can be solved.
http://christopherthielen.github.io/ui-router-extras/#/sticky

Getting data from Modal in Bootstrap UI

I've been aggressively working on an app that uses AngularJS and Bootstrap. To help, I've included the Bootstrap UI framework. I am successfully opening a dialog and closing the dialog. However, I'm not sure how to actually "get" the data when a user clicks "Save Item".
My Plunker is Here
As shown in the Plunker above, I have my controller defined like this:
var modalInstance = $modal.open({
templateUrl: 'item-dialog.html',
size: 'sm',
controller: function($scope, $modalInstance) {
$scope.saveItem = function () {
alert('Saving...');
alert('ID: ' + $scope.newItem.typeId);
alert('Data: ' + $scope.newItem.data);
};
$scope.cancelItem = function() {
$modalInstance.close(false);
};
}
});
When I go to show the id of the item the user selected, and the text the user entered, it doesn't work. newItem is undefined. However, in the markup, you can see ng-model="newItem.data"
How do I get the information that the user entered in my controller?
Thank you!
You are not passing the result back to the controller opening the modal when you close it, you just need to add this in the modal's controller:
$modalInstance.close($scope.newItem);
See plunk.
Another thing: I've found that if you do not manually initialize objects on the $scope of the modal controllers of angular ui, they do not get bound properly, hence the $scope.newItem={} in the controller of the modal.

How to use the same controller for modal and non-modal form in Angular UI Bootstrap?

I've got a modal with a registration form. The same form should be displayed at the bottom of the landing page not in a modal.
Currently my controller that handles registration modal takes $modalInstance as one of its parameters along $scope etc. If I add ng-controller="SignUpCtrl" to an element in the landing page, it doesn't work, because the controller wasn't created via $modal.open method and so Angular complains about Unknown provider: $modalInstanceProvider <- $modalInstance.
I've got a service for registering users (authService.signUp(data).then/catch...), but the controller itself does a bit more - handles input, emits events (e.g. with translated error messages), sets cookies etc.
What's the best way to handle such case without duplicating almost whole controller code? Should I move the code from controller into yet another, higher-level service?
After struggling for a long while I found a easier trick to reuse our Controller for both modal and normal case.
I found that we can pass caller's scope to modal controller, so I pushed modalInstance into $scope and passed it to the modal controller.
Now you don't have unknown provider problem because $scope is a well known one.
Below is an example:
CallerController = function($rootScope, ...) {
var modalScope = $rootScope.$new();
modalScope.modalInstance = $modal.open({
templateUrl: tempUrl,
controller: ReusableModalController,
scope: modalScope // <- This is it!
});
modalScope.modalInstance.result.then(function (result) {
// Closed
}, function () {
// Dismissed
});
};
ReusableModalController = function($scope, ...){
var dataToSendBack = 'Hello World';
$scope.modalInstance.close(dataToSendBack);
};
Cheers!
If you are using ui-router you can easily use the resolve from ui-router to provide a $uibModalInstance (was $modalInstance before):
$stateProvider
.state('conductReview', {
url: '/review',
templateUrl: '/js/templates/review.html',
controller: 'yourController',
resolve: {
$uibModalInstance: function () { return null; } // <- workaround if you want to use $uibModalInstance in your controller.
}
})
That way you can use your modal controller like a normal controller. If you inject $uibModalInstance in your controller it will be null.
If you want to use same controller for both modal form as well as landing page form, make use of
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
You can get all the data from modal form in selectedItem and use this in landing page form.
Also, how do you open the modal. If it is through a button, bind that ng-model to open modal using $modal.open.Don't create separate controller for your modal.Use the same one as your landing page. This way you can use 1 controller to open modal as well as other function after the modal is closed.
PS: Code snippet given here is from angular ui's page. Check that page's documentation for selectedItem

Pass data to angular's nested controller

The problem
I'm using UI Bootstrap's dialog service in my application, this service creates modal dialog and I do that using the following method on my outer $scope:
$scope.showRouteEditDialog = function (template, route) {
// argument `route` is not currently used
var dialog = $dialog.dialog({
backdrop: true,
keyboard: false,
backdropClick: true,
templateUrl: template,
controller: 'RouteController'
});
dialog.open().then(function(result) {
alert(result); // This line is called when dialog is closed
});
}
This method is later called from partial view with the following markup
<i class="halflings-icon edit"></i>
My dialog handles editing of a route (route is a sub-model within main model) and therefore I would like to pass that route to the dialog so that it treats it like it's own model without knowing anything about the outer model.
My initial guess on this problem was to assign the route argument to dialog variable, something like dialog.route = route and have it later used within controller with the following code:
Application.controller('RouteController', ['$scope', 'dialog', function ($scope, dialog) {
// `dialog` is our dialog and it is injected with injector
doSomethingWith(dialog.route)
}]);
Though this approach creates a dependency and doesn't look like an angular's way of doing things
I have also found this post saying that I should be using service for that purpose, but it seems like this solution is an overkill for such minor problem.
Question
What is the angular way of passing a value from outer controller to an inner one with scenario described above.
Thank you
You can use "resolve" -
var dialog = $dialog.dialog({
resolve: {route: function(){return "route"}}
});
and later you can inject the "route" value inside of your controller
.controller("SomeCtrl",function(route){
})

Resources