Ask confirmation BEFORE Redirect from page - javascript

I have application.
Client side is - knockout.
so I have page with form, and i want to ask user confirametion before he will try go to another page (in case if he changed something (this pard is ready))
So routing on all website - its Sammy.js.
I tried :
Sammy JS - before
function ViewModel()
{
Sammy.before(/.*/, function () {
if (window.confirm('Really go to another page?')){
}
else{
//DO NOTHING AND STAY IN THE SAME PAGE
//OR SOMETHING ELSE THAT YOU WANT
return false;
}
});
}
its work , but its still working for all website - and its bad.
I'm not found way to disable it, so maybe I can do it without sammy???
Thank you guys!
Update: This website is SPA

You can use before, but you must specify options to show the confirmation dialog only when necessary. See the docs. You're specifying to run it for all the routes, you must specify in which routes you want it executed. Before option only gives you information on the next route. If it depends on the current route, you can get it examining the current url:
function extractSammyUrlFrom (context)
{
// get the hash fragment (curernt route)
"#" + context.path.split("#")[1] ;
}
If it depends on any other thing in your page, just check it before showing the dialog.

Related

How to change this function execution order

I have this search function , which should refresh the page first (clean what was in the page)and then show the results.
What happens is that the page shows the results first and then refreshs the page.
searchForm.addEventListener("submit" , function(event)
{
window.location.reload(); //should do this first
event.preventDefault();
searchedName.innerText = searchBar.value;
changeLogoImage(searchedName);
giveCompanieSymbol(searchedName);
TurnVisible(companyLogo);
TurnVisible(overviewDataContainer);
TurnVisible(separadoresAnalise);
TurnVisible(personaliseParagrafo);
}
)
I can't think of a easy/simple solution to do this without creating another function or separated events. Isn't there an easier way to say to this function :
"First reload the page , then show the results." ?
I thought this is what would happen If I place the reload() in the first line of the function but doesn't seems to be the case.
You can't refresh the page and then make modifications to it, because the environment in which your code was running (along with your code) has been torn down and discarded by the process of reloading the page.
Instead, either:
Modify the page in place rather than refreshing it.
or
Encode the search information in query string parameters and assign teh URL to window.location to load the new page, and read and apply those query string parameters on page load.
or
Use sessionStorage to store them temporarily and then, again, apply them on page load.
#1 is a common approach these days. Given it's search information, #1 is also quite a normal way to do this.

Redirect from within Angular controller if condition is met at start of page

I have an Angular app used to track hours worked by the user. When the user adds a new job, they are taken through a wizard, with each page/controller adding a new property to the job object. Once the wizard is complete, the user can start tracking by navigating to the jobs home page from the app main page.
It is, however, possible to exit the wizard before it is completed (via the back button) and then navigate to the home page of the job. What I need is for the controller for that home page to redirect to the appropriate wizard page for whichever job property is missing.
The job variable is retrieved from local storage at the start of the controller code.
var job = DatastoreService.objectJob();
job.initFromHash($routeParams.jobHash);
function checkJobProps(prop, route){
if(!job.data.hasOwnProperty(prop))
$location.path('/wizard/add-position/' + $routeParams.jobHash + '/' + route);
}
checkJobProps('taxSettings', 'tax');
checkJobProps('payrollSettings','payroll-opt');
checkJobProps('breaks', 'breaks');
checkJobProps('allowances', 'allowances');
checkJobProps('deductions', 'deductions');
checkJobProps('generalSettings', 'general-settings');
There is code below this on the controller that breaks if certain properties are not available. None of these function calls execute fast enough to prevent errors. They will redirect, but not elegantly and it will also always be the last one in the list that takes effect.
Do I do this with a promise? The navigation that is used from the home page of the app to the home page of each job is a directive so, I guess it may be possible to init the job from the $routeParams.jobhash and check these properties within the directive, but I would have to learn more about directives first.
Any help would be much appreciated.
$location.path() is asynchronous and will not prevent the code that follows it from executing. You will have to manually stop the execution with a return statement.
Note that the return statement must belong to the controller function block. You cannot put it inside another function since that will only stop the execution of that specific function.
Something along these lines should work:
var job = DatastoreService.objectJob();
job.initFromHash($routeParams.jobHash);
var redirectPath;
function checkJobProps(prop, route) {
if (redirectPath || job.data.hasOwnProperty(prop)) return;
redirectPath = '/wizard/add-position/' + $routeParams.jobHash + '/' + route;
}
checkJobProps('taxSettings', 'tax');
checkJobProps('payrollSettings', 'payroll-opt');
checkJobProps('breaks', 'breaks');
checkJobProps('allowances', 'allowances');
checkJobProps('deductions', 'deductions');
checkJobProps('generalSettings', 'general-settings');
if (redirectPath) return $location.path(redirectPath);
... rest of the code ...

Allowing href links with hashes on them to bypass SammyJS routing

I have the following server-side URL mappings defined:
/main/item1
/main/item2
I've added SammyJS routing support so that I am able to do the following:
/main/item1#/ /* main view */
/main/item1#/topups /* topup view */
I've set up SammyJS like so:
s.app = Sammy(function() {
this.get('#/topups', function() {
console.log('Initializing topups view.');
});
this.get('#/', function() {
console.log('Initializing main view.');
});
});
The problem is, I have a summary section in my page that redirects to the topup view of a different "item". E.g., I am at the url /main/item1#/, and in this page, there exists a tag item 2's topups.
I expect to be redirected (page refresh) to the new URL, however, it seems like SammyJS is intercepting the /main/item2#/topups call and simply running the this.get('#/topups') route I've defined.
I expect that since the URL paths before the hash, /main/item1 and /main/item2 are different, the SammyJS routing won't be triggered.
Is there a way to prevent this behavior from happening in SammyJS?
I don't know much about Sammy but I can tell you from the way any router behaves, is that it catches the first match in the routing possibilities, and so, anything that ends with #/topups will be considered the same as long as it's after the hash sign.
so you better define the router this way:
this.get('#/topups/:item', function() {
console.log('Initializing topups view for item: '+ item);
})
and then call the pages with URLs like:
item 2's topups
I hope this is what you're looking for
I'm pretty sure using the full URL redirect you.
Item 2 top ups for the lazy coder
However, that will cause the page to reload. If you modify Labib's answer you can have an even better solution:
this.get('#/topups/:item', function () {
console.log('Doing some post processing on current item');
console.log('Now redirecting you to ' + this.params.item);
window.location.href = 'http://example.com/menu/# + this.params.item +#/topups';
});
Again this will cause the page to reload, but if you do not mind that, then just either method.
NOTE: Sammy will also check form submission for you. This trips me up EVERY time I use it. This post has the solution.

Backbone router not triggering view change

I've been trying to solve a pretty irritating for the last couple of days now, and I'm finally admitting defeat, and appealing to SO.
First I'll give an overview of what I'm trying to do, then I'll give you specifics of where I'm running into issues.
The Goal:
A user is filling out a form, and if any element is changed on the form and the user tries to leave the form without saving the changes, a modal should display with the following message:
You have made changes to this record. Do you want to save the changes?
The user gets a Yes/No/Cancel option.
If the user selects:
Yes: The record should save, then navigate to the originally intended route.
No: The record should not save, and the user should be navigated to the intended route.
Cancel: The modal should close and the user will remain on the current page with no route change.
I am using the backbone.routefilter library to detect route changes before the route change happens.
The Problem:
To solve the problem, I put a route change listener within my initialize method in the view that contains the form. Below is that code:
// If the user tries go to a different section but the record has been changed, confirm the user action
app.circulationRouter.before = function( route, params ) {
app.fn.clearNotifications();
if(app.recordChanged){
var confirmView = new app.views.confirm({
header:"Patron Record Changed",
bodyText:"You have made changes to this record. Do you want to save the changes?",
trueLabel:"Yes",
falseLabel:"No",
cancelLabel:"Cancel",
hasTrue:true,
hasFalse:true,
hasCancel:true,
trueCallback:function(){
// Ignore the patron record change
_this.saveRecord();
// Render the patron section AFTER the save
_this.model.on({
'saved' : function(){
// Render the new seciton
app.circulationRouter.renderPatronSection(_this.model, params[1]);
app.currentPatronSection = params[1];
// Set the record changed to false
app.recordChanged = false;
// Remove the 'before' listener from the circulationRouter
app.circulationRouter.before = function(){};
if(con)console.log('in saved');
// Remove the listener
_this.model.off('saved');
},
'notsaved' : function(){
// Stay on the patron record page, keep the url at record
app.circulationRouter.navigate("patrons/"+_this.model.get('PatronID')+"/record",false);
_this.model.off('notsaved');
}
}, _this);
},
falseCallback:function(){
if(con)console.log(params);
if(params.length){
// Ignore the patron record change
app.circulationRouter.renderPatronSection(_this.model, params[1]);
app.currentPatronSection = params[1];
}else{
if(con)console.log('blah');
setTimeout(function(){
if(con)console.log('should navigate');
app.circulationRouter.navigate("", true);
}, 5000);
}
app.recordChanged = false;
app.circulationRouter.before = function(){};
},
cancelCallback:function(){
// Stay on the patron record page, keep the url at record
app.circulationRouter.navigate("patrons/"+_this.model.get('PatronID')+"/record",false);
}
});
app.el.append(confirmView.render().el);
return false;
}
};
Each of the three options has a callback that gets called within the initialize function that will control the outcome. The Cancel button always behaves correctly. The issue I'm running into is when the user wants to navigate to the home page, ie when this line is called: app.circulationRouter.navigate("", true);. Everything else works correctly if there is a new, defined route to navigate to.
Here is the sequence of events that creates the issue:
1) Modify a record
2) Try to navigate to the home page
3) Route is changed home page route, but record is still in view
4) Modal is automatically displayed with three options
5) Select the No button
6) falseCallback is triggered
7) Modal is closed and view remains on record page, but route displayed in browser is for home page
The expected behavior for #7 was to display the view for home page, but only the url reflects that.
You can see in the falseCallback I even tried delaying the trigger for the redirection to make sure it wasn't a DOM issue, but that didn't work.
Does anyone know what may be happening?
Here's the problem. Once the route is changed, if you re-navigate to the same route, even if you set the param {trigger:true}, the page won't reload. There is a long discussion about it here.
Based off of the discussion listed in github, I am using this solution and adding the refresh option. If the refresh option is set to true, then the view will reload, even if the url doesn't change. Otherwise, the functionality remains the same.
_.extend(Backbone.History.prototype, {
refresh: function() {
this.loadUrl(this.fragment);
}
});
var routeStripper = /^[#\/]/;
var origNavigate = Backbone.History.prototype.navigate;
Backbone.History.prototype.navigate = function (fragment, options) {
var frag = (fragment || '').replace(routeStripper, '');
if (this.fragment == frag && options.refresh)
this.refresh();
else
origNavigate.call(this, fragment, options);
};

How to avoid showing loading text in Ext.form.ComboBox?

I use Ext.form.ComboBox in very similar way as in this example:
http://extjs.com/deploy/dev/examples/form/forum-search.html
What annoys me is that when the ajax call is in progress it shows loading text and I cannot see any results from before.
Eg I input 'test' -> it shows result -> I add 'e' (search string is 'teste') -> result dissapear and loading text is shown, so for a second I cannot see any result and think about if it's not what I'm searching for...
How can I change this to simply not to say anything when 'loading'...
The solution is to override 'onBeforeLoad' method of Ext.form.ComboBox:
Ext.override(Ext.form.ComboBox,
{ onBeforeLoad:
function() {this.selectedIndex = -1;}
});
Please be warned, that this overrides the class method, so all of the ComboBox instances will not have the LoadingText showing. In case you would like to override only one instance - please use plugins (in quite similar way).
You may also look at Ext.LoadingMask to set an appropriate loading mask to aside element if you wish.
If you don't show loading message to user how user will know what is happening? User will notice that its already loading results so may wait to see the results, but if nothing displayed then user wouldn't know if its bringing new data or not.
You may monit the expand event of the combobox and set picker loading to false.
// in the controller
init: function() {
this.control({
"form combobox[id=fieldId]": {
expand: function(combobox) {
combobox.getPicker().setLoading(false);
}
}
});
}

Categories