AngularJS modal async close doesn't work - javascript

I am creating a modal and closing it once data comes in the background.
var modal = modal.open({..some params..});
//after data loads
modal.close();
So my problem is, since everything is asynchronous if my data comes instantaneously then my modal.close() executes before modal opens fully and then my screen remains stuck with the modal screen.
One solution I found is adding a timeout to the modal.close
$timeout(function() {
modal.close();
}, 1)
This works but is it the right way to do it? Or there is some other better solution?

The modal instance has an opened promise on it that you should use to guarantee the modal has finished opening before you try to close it. From the docs:
opened - a promise that is resolved when a modal gets opened after downloading content's template and resolving all variables
rendered - a promise that is resolved when a modal is rendered.
Mixing it with your HTTP request might look like
modal = $modal.open({...})
$http.get(...).then(function(response) {
modal.opened.then(modal.close)
})
Here's a demo of both the way you're currently doing it and doing it using opened.
$scope.open = ->
modalInstance = $modal.open(
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl'
)
if $scope.work
modalInstance.opened.then(->
modalInstance.close()
)
else
modalInstance.close()

Related

How is browser's debugger different from Angular's setTimeout()?

I am working on an angular app which is embedded in an application I don't have access to. I am using a router to move from page to page once a pop-up modal has been OK'd (checkbox & button). I have to ensure that the modal has been destroyed before moving to the next page or the outer page causes problems. I have tried using *ngif="destroyModal". It works, but it's not happening in-time.
When I set the browser's debugger to stop the action on line with this.myRequestService.update... it seems to stop the action in such a way that my modal destroy works. If I use a debugger break-point on the next line (in the called-method) it doesn't work.
public goToPageTwo(): void {
this.myObject = {};
this.myRequestService.updateNextPg(this.myObject).subscribe((nextPageResponse) => {
this.nextPageService.setData(nextPageResponse);
this.router.navigateByUrl(NEXT_PAGE);
}
}
I have tried several approaches with setTimeout(() => this.router.navigateByUrl(NEXT_PAGE), 2000) but this doesn't seem to have any effect. The only stop that allows the modal destroy to happen is one delivered by a debugger break-point.
I can't ask the user to do this :(
You should be using the page navigation in the ngOnDestroy() life cycle event.
myClass {
...
ngOnDestroy(){
//do it here
}
}
This would be where you would want to cause the page navigation when the component is closed and cleaned up.

Angular-modal-service does not show modal

Trying to set up a (I think) relatively simple modal to show the sites cookie policy.
The policy is on /cookiepolicy. Checked and that link works nicely.
I then created a button (that does call the code)
<a class="btn btn-default" href ng-click="showCookie()">Read More</a>
As I just want to call the modal for the url, nothing more is added to the html.
The function that calls the modal (which also is called and reports success as per the last line.)
app.controller('IndexController', function($scope, ModalService) {
$scope.showCookie = function (data) {
ModalService.showModal({
templateUrl: "/cookie-policy",
controller: "ModalController"
}).then(function (modal) {
//it's a bootstrap element, use 'modal' to show it
modal.element.modal;
modal.close.then(function (result) {
console.log(result);
});
});
}
});
The modal also have its own controller
betchaHttp.controller('ModalController', function($scope, close) {
// when you need to close the modal, call close
close("Success!");
});
The thing is that when I press it, nothing comes up on the page, neither is there a error message. Am I missing something rather obvious (or not so obvious)
Fortunately, this is just a small syntax typo on your end. Observe your .then() block and change...
modal.element.modal; // -- nothing
to
modal.element.modal(); // -- fn call
JSFiddle Link - demo

Hide Angular Bootstrap modal instead of close

I am using Angular Bootstrap Modal to open a bunch of modals including video player inside
http://angular-ui.github.io/bootstrap/#/modal
I want to be able to keep where the video is at even if the modal is closed. It's just so next time I open the same modal again, I can see where I left off in the video.
In order to do that, I need to do:
Create each modal a separate instance
Instead of close(), I need to hide() the modal instead. Therefore the DOMs are still in there and the video player don't get re-created
What's the elegant way to do this as the Bootstrap modal has no hide feature. Should I just use jQuery to show/hide the .modal-backdrop and .modal classes?
From Don't destroy an Angular Bootstrap modal on close:
Why don't you abstract the modal state into its own service? That way, whenever the modal controller is created, it uses the service to setup the view state on initialisation.
Eg. create a service
.factory('ModalStateService', function(){
var state = {
someValue: 'something'
};
return {
getState: function() { return state; }
};
});
Then in your controller:
.controller('ModalCtrl', function($scope, ModalStateService){
$scope.viewState = ModalStateService.getState();
});
Then in your modal content view for example:
<span>{{viewState.someValue}}</span>
If you were then to set someValue inside your modal, say through an input, the service state would be updated. Then when you create and destroy your modal, the state will persist.

Don't destroy an Angular Bootstrap modal on close

I am using Angular Bootstrap to display a Modal (the one presented here), which works perfectly. However, default behavior of this Angular extension is that the modal is reconstructed (and a new instance of its controller will be creatred) whenever it is closed and then opened again.
Since I have some pretty advanced stuff going on inside the Modal, I would like the modal to just be hidden when it is closed, so that its state remains. I have searched around a bit, but unfortunately could not find a simple and effective answer.
Just hiding it would be an option, but this then has to happen whenever the modal is closed, so also when it closes because the backdrop is clicked. And I want the same animation as when the modal is opened in the normal way.
Why don't you abstract the modal state into its own service? That way, whenever the modal controller is created, it uses the service to setup the view state on initialisation.
Eg. create a service
.factory('ModalStateService', function(){
var state = {
someValue: 'something'
};
return {
getState: function() { return state; }
};
});
Then in your controller:
.controller('ModalCtrl', function($scope, ModalStateService){
$scope.viewState = ModalStateService.getState();
});
Then in your modal content view for example:
<span>{{viewState.someValue}}</span>
If you were then to set someValue inside your modal, say through an input, the service state would be updated. Then when you create and destroy your modal, the state will persist.
As you might already know Angular initializes a controller when the associated view is added to the DOM. So the plugin author might have decided to add and remove the view element so that he does not have to worry about clearing the 'scope'each time user opens and closes the modal.
For example, we have a login box in the modal and if the scope is not cleared, it will keep the filled in details even the next time we show it.
An easy hack to solve your problem will be to wrap the originl modal in a custom directive, reneder it. And just change the display property of your custom modal to show and hide the modal ;)

Bootstrap modal - backdrop stays when I use the back button from the browser

When I display an error message to the user, I use the following script to open a modal message:
jQuery('#errorDialog').modal({
keyboard: false,
show: true,
backdrop: 'static'
});
It works very well and displays the message as I wanted to.
The problem is that when I use the back button from the browser, it takes me to the previous page in the history (all good) but the backdrop is still on the screen.
I tried to remove the backdrop: 'static' line which had the effect of dismissing the modal message when I clicked the anywhere on the backdrop. Nevertheless, it still stays when going back the the previous page.
Is there a way to remove it when I use the back button (or navigate through browser history otherwise)?
If you are working with a SPA javascript framework like for example Vue, React or Angular, is normal that when there is a back button pressed, the bootstrap or jQuery UI backdrop stays visible.
The reason is because the backdrop div is inserted usually at the top of the DOM and when back is pressed, it just re-renders the Node more down in the DOM.
The solution is for example, detect every history change and execute:
$(".modal-backdrop").remove()
In the case of Vue for example, it can be done in the vue-router like so:
router.beforeEach((to, from, next) => {
$(".modal-backdrop").remove();
next();
});
I had a similar problem using backbone.js. For anyone else experiencing this issue. Here's my hack to fix it.
I have a function in myRouter that loads my views on route change.
loadView: function(view) {
var _this = this;
if (_this.currentView) {
_this.currentView.close();
}
_this.currentView = view;
_this.currentView.render();
// Render view to dom
$(".content").html(_this.currentView.el);
// Set opacity of modal backdrop to 0
$('.modal-backdrop').css('opacity', 0);
} //,
Then on route change you just call loadView like this:
index: function() {
_this.loadView(new IndexView());
} //,

Categories