I'm currently experiencing a problem with Bootstrap Modal, when changing views through the URL. ReloadOnSearch is disabled.
If I'm on a view such as:
blah.com/examples/1
and open up a Modal with a faded backdrop, then change the URL to change views such as:
blah.com/examples/2
the Modal window will close, but the faded backdrop will remain, and disable interaction to the web page.
I'm wondering if there is a way to define one function, which will programmatically remove the faded backdrop, which will execute on URL change, regardless of the controller in use.
Though the cause of the issue is due to AngularJS, the solution doesn't need to use AngularJS.
I had same issue, the solution is to remove that overlay class while your hashurl change
window.onhashchange = function() {
$(".lean-overlay").fadeOut(500); // whatever class name your overlay has
}
Use the event onhashchange to hide all modals on screen using the proper hide method:
window.onhashchange = function(event) {
$('.modal').modal('hide');
// You can even add some tests based on the new and old URL
console.log('new URL', event.newURL);
console.log('old URL', event.oldURL);
}
Related
I have a requirement that I am trying to implement as follows -
I have an audit log page which has a button to display the logs on a new browser window, while continuing to do other stuff on the application open in the main window.
We use ui-router and angularjs (1.6). Below is my code -
Route to the controller -
.state('auditlog', {
url: '/auditlog',
templateUrl: 'app/system/audit/audit-log.html',
controller: 'AuditLogController',
controllerAs: 'al'
})
On the click event of a button in a different controller, I have the following code -
unDockEventsPanel(event) {
let location = this.$state.href('auditlog');
this.$window.open(location, '', 'scrollbars=no,fullscreen=yes,toolbar=no');
}
and the HTML -
<i class="Icon-MoveOut Icon-Large icon-btn" ng-click="eventsPanelVM.unDockEventsPanel($event)">
Now, when I click on the "MoveOut" button the unDockEventsPanel() method gets called and a new window is opened with the contents of the controller/template in the route definition "auditlog".
The problem I'm facing however is, any operation I perform on the child window is randomly triggering something else on the parent window and vice versa. For eg. When I click on a select button in the child window, the select opens up on the child, but also, on the parent the a text box comes into focus like it would if I had clicked it. Likewise, when I click a select on the parent, a different control on the child gets highlighted.
I can see that a new instance of the application/controller is not created on the child and hence there is an overlap of the controls and events between the two. But I'm not able to figure out how to isolate the two.
Any help is greatly appreciated.
I believe the issue is related to the use of '$state'
let location = this.$state.href('auditlog');
this.$window.open(location, '', 'scrollbars=no,fullscreen=yes,toolbar=no');
from the angular-ui github wiki
When a state is activated, its templates are automatically inserted into the ui-view of its parent state's template.
I would suggest trying to avoid the use of $state by using plain old Javascript to do the new window navigation
window.open("{yourURL}/auditlog", 'scrollbars=no,fullscreen=yes,toolbar=no');
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 ;)
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());
} //,
First of all, here is the site I am working on.
I am trying to get a modal window to pop-up when elements in the Flash are clicked on. Which at this point I have about 90% working when you click on the warrior image. Below is a list of issues I am still trying to solve that I hope you can help me with...
The modal background doesn't fill up
the whole page like it should.
I cannot get the close button to work
I need to set the vidname variable in
both the Flash and Java to load in a
dynamic HTML file. Depending on which
image is clicked on. My naming
convention will probably be something
like vid-1.html, vid-2.html, etc.
If you need to look at the .js file you can view it at /cmsjs/jquery.ha.js
Below is the ActionScript I currently have...
var vidname = "modal.html";
peeps.vid1.onRelease = function() {
getURL('javascript:loadVid(\'' + vidname + '\');');
};
Well I have one for you.
Your current close code is
$('#modalBG, #modalClose').click(function(){
closeModal();
});
If you click the background after a video loads you'll see that the modal does close. The reason your close button does not work is because #modalClose does not exist in the DOM when you are binding to the click function.
You need to either rebind the modalClose element when you modify the DOM or use live. If you use live you just need to change your click code to this:
$('#modalBG, #modalClose').live("click", (function(){
closeModal();
});
Is there a way to make the user's back button on their browser, call a javascript function instead of going back a page?
You can't override the behaviour that if a user follows a link to your page, clicking Back will take them off it again.
But you can make JavaScript actions on your page add entries into the history as though they were clicks to new pages, and control what happens with Back and Forward in the context of those clicks.
There are JavaScript libraries to help with this, with Really Simple History being a popular example.
yes, you can. Use this js:
(function(window, location) {
history.replaceState(null, document.title, location.pathname+"#!/stealingyourhistory");
history.pushState(null, document.title, location.pathname);
window.addEventListener("popstate", function() {
if(location.hash === "#!/stealingyourhistory") {
history.replaceState(null, document.title, location.pathname);
setTimeout(function(){
location.replace("http://www.programadoresweb.net/");
},0);
}
}, false);
}(window, location));
That will redirect your back button to the location.replace you specify
I think this will do the trick.
you can write your custom code to execute on browser back button click inside onpopstate function.
This works in HTML5.
window.onpopstate = function() {
alert("clicked back button");
}; history.pushState({}, '');
I assume you wish to create a one-page application that doesn't reload the website as the user navigates, and hence you want to negate the back button's native functionality and replace it with your own. This can also be useful in mobile web-apps where using the back button inside apps is common to close an in-app window for example. To achieve this without a library, you need to:
1st. Throughout your application modify the window's location.hash instead of the location.href (which is what tags will do by default). For example, your buttons could fire on click events that modify the location.hash like this:
button.addEventListener('click', function (event) {
// Prevent default behavior on <a> tags
event.preventDefault()
// Update how the application looks like
someFunction()
// Update the page's address without causing a reload
window.location.hash = '#page2'
})
Do this with every button or tag you have that would otherwise redirect to a different page and cause a reload.
2nd. Load this code so that you can run a function every time the page history changes (both back and forward). Instead of the switch that I used in this example, you can use an if and check for other states, even states and variables not related to location.hash. You can also replace any conditional altogether and just run a function every time the history changes.
window.onpopstate = function() {
switch(location.hash) {
case '#home':
backFromHome()
break
case '#login':
backFromLogin()
break
default:
defaultBackAnimation()
}
}
This will work until the user reaches the first page they opened from your website, then it will go back to new tab, or whatever website they were in before. This can't be prevented and the teams that develop browsers are patching hacks that allow this, if a user wants to exit your website by going back, they expect the browser to do that.
If you are creating a one-page web application, where your html body has different sections and you want to nevigate through back button to the previous section you were. This answer will help you.
Where your website sections are differentiated by #. Such as:
your-web-address.com/#section-name
Just follow a few steps:
Add a class and a id in every section in you html body. Here it is ".section"
<section class="section" id="section-name">...</section>
Add two CSS class in your linked css (e.g., style.css) file to your html (e.g., index.html) file such:
.section .hide {
display: none;
}
.section .active{
dislplay: block;
}
Add this JavaScript function in you linked .js (e.g., main.js) file to your html file.
window.onpopstate = function () {
if (location.hash !== "") {
const hash = location.hash;
// Deactivating existing active 'section'
document.querySelector(".section.active").classList.add("hide");
document.querySelector(".section.active").classList.remove("active");
// Activating new 'section'
document.querySelector(hash).classList.add("active");
document.querySelector(hash).classList.remove("hide");
}
}