I try to use a Router from route_hierarchical/client.dart to listen to an onpopstate event and enable/disable a <div> in my index.html. (Example in stagehand.pub dart plugin)
If this is done via normal <a href="/relativePath"> in index.html, it works.
But if I try to change the path via a button.onClick.listen() handler in which I call:
window.location.assign('/relativePath');
I get 404 and the router is not handling my event properly.
Should that that action not invoke a popstate event which is caught by Router like described here?
handlers.dart
...
button.onClick.listen((_){
window.location.assign('/about');
});
...
router.dart
var router = new Router();
router.root
..addRoute(name: 'about', path: '/about', enter: showAbout)
..addRoute(name: 'login', defaultRoute: true, path: '/', enter: showLogin)
..addRoute(name: 'context', path: '/context', enter: showContext);
router.listen();
}
void showAbout(RouteEvent e) {
// Extremely simple and non-scalable way to show different views.
querySelector('#login').style.display = 'none';
querySelector('#about').style.display = '';
querySelector('#context').style.display = 'none';
} ...
index.html
...
<form>
<button type="button" id="submit" disabled="true" >
Login
</button>
</form>
...
onPopState is the wrong event. This event is only fired if you navigate to an existing history entry (back, forward, pushState, go to 2nd entry in history).
What you are looking for is probably the window.onHashChange event.
OK looks like I am not achieving my goal with assuming the above behavior.
Thanks to Günther Zöchbauer for helping.
I filed it with corresponding Github project as I think it should work.
What I now use and what works including history support is
router.gotoUrl('/relativePath')
in the onButtonClick handler.
That totally does it.
Related
I'm building a mid sized app with Polymer and used the Polymer Starter Kit to kick things off which uses page.js for routing.
I want to implement flash message functionality using the paper-toast element.
In other technologies/frameworks this is implemented by checking to see if a property exists when the route is changed.. if it does, it shoes the relevant flash/toast message.
How... with Polymer & Page.js is it possible to replicate this type of functionality? Page.js doesn't seem to have any events for changed routes.
The only way I can think is to create a proxy function for the page('/route') function that I have to call every time I want to go to a new page which then calls the actual page function. Is there a better way?
I've implemented this like follows for the time being... seems to be ok but if anyone can suggest improvements let me know.
In routing.html
window.addEventListener('WebComponentsReady', function() {
// Assign page to another global object
LC.page = page;
// Define all routes through this new object
LC.page('/login', function () {
app.route = 'login';
app.scrollPageToTop();
});
....
//implement remaining routes
// page proxy... to intercept calls
page = function(path) {
// dispatch event
document.dispatchEvent(new Event('LC.pageChange', {path: path}));
// call the real page
LC.page(path);
};
});
Then where you want to listen.. in my case in a lc-paper-toast element added to the index.html file of the app I can now listen to when the page is changed...
ready: function() {
document.addEventListener('LC.pageChange', function(e){
console.log('page change' , e);
}, false);
}
Only thing to be aware of is that all page changes must be called with page('/route') otherwise it won't go through the proxy.
On my meteor app I have a login system that sends you to the /dashboard path if you log in or sign up successfully. However, right now it is possible to get to the /dashboard path just by typing in localhost:3000/dashboard. How can I prevent this?
In addition to filtering the route with router hooks or custom actions, you may ensure that the template itself is displayed only to privileged users:
<template name="secret">
{{#if admin}}
...
{{/if}}
</template>
Handlebars.registerHelper('admin', function(options) {
if(Meteor.user() && Meteor.user().admin) return options.fn(this);
return options.inverse(this);
});
If you want to show a template to all registered users, you may use {{#if currentUser}} instead, in which case you don't need to register an additional helper.
You can accomplish this using before hooks. Here is a simple example with three routes: index, signin, and dashboard:
Router.map(function() {
this.route('index', {
path: '/'
});
this.route('signin');
this.route('dashboard');
});
var mustBeSignedIn = function() {
if (!(Meteor.user() || Meteor.loggingIn())) {
Router.go('signin');
this.stop();
}
};
Router.before(mustBeSignedIn, {except: ['signin']});
Before all routes except signin, we redirect the user back to the signin page unless they are logged in or in the process of logging in. You can see more examples in the using hooks section of the IR docs.
You need to check the state of the user before each route is run. If the user is not logged in (Meteor.userId() returns null) then redirect the user to the login route.
Router.before(function() {
if (!Meteor.userId()) {
this.redirect('userLoginRoute');
this.stop();
}
}, {
except: ['userLoginRoute', 'userSignupRoute', 'userNewPasswordRoute']
});
I believe you can use custom actions for iron-router. You can check Meteor.userId() if it's null (not logged in) in the custom action, and redirect accordingly.
I am still learning angularjs so maybe there's something stupid I am not understanding but I have a really strange behaviour when using routing.
In my application I use the following code to define my routes:
var app = angular.module('app', []);
app.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.
when('/pneumatici/:chunka', {}).
when('/pneumatici/:chunka/:chunkb', {});
$locationProvider.html5Mode(true);
}]);
And in a controller I manage them this way:
app.controller('appCtrl', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (current,previous) {
if (!($location.path().indexOf('/pneumatici') === -1)) {
$scope.chunka = $route.current.params.chunka; $scope.chunkb = $route.current.params.chunkb;
/** do my stuff with chunka and chunkb **/
} else {
window.location.href = $location.path();
}
});
I have no ngView, no template, nothing.
It works like a charm.
Please note the line where I actually force a page load in case the url is not intended to be managed by the controller appCtrl.
I was forced to do that because once I define my route to catch '$routeChangeSuccess' all links in the page when clicked are catched by angular and no page load occurs even if the link doesn't have the format defined with 'when'.
I would have like to do it with 'otherwise' but I could not understand how to, if doable.
Now the problem.
In the page of course I have links like just '/privacy.html', if I click them the page load is correctly triggered and I do see '/privacy.html' but unfortunately once there if I click the back button I can see the url of the browser changing to (let's say) /pneumatici/foo/bar but no page load is triggered.
Please note in the privacy.html page I have no angular routing defined, there's no .config no .when; there's an anagular app defined, with a controller, but no injection of '$routeProvider' anywhere, no definition of any route.
What is happening? What I am doing wrong?
Thanks for any help!
Update.
I found a viable solution adding:
angular.element("a").prop("target", "_self");
Angular routing is ignored for all 'a' elements with 'target' set to "_self", didn't know that.
Still if I look at this strategy as a whole doesn't sound very elegant to me and I would love to improve it. What I don't like is since I am defining the route in .config I should be able to tell angular to skip any url which do not match the format/path I defined there.
But I don't know if that is doable or not, does anyone know out there?
By turning on html5mode your app should be acting like it should intercept everything on the site by default (from '/'.)
From that perspective, it seems like $location.path() should work in your explicit override, but it isn't really correct ($location.url() would be) and the browser already has the correct URL, so maybe you can't force a reload with location.href = location.href in your specific browser.
Rather than going down that path, I would do the following to make it DRY:
If you add a base href:
<base href="/pneumatici/"></base>
and replace /pneumatici/ with / in your when clause(s):
$routeProvider.
when('/:chunka', {}).
when('/:chunka/:chunkb', {});
then you should just need this:
$scope.$on('$routeChangeSuccess', function (current,previous) {
$scope.chunka = $route.current.params.chunka;
$scope.chunkb = $route.current.params.chunkb;
/** do my stuff with chunka and chunkb **/
});
I think you should let Angular manage all your routes like this:
var app = angular.module('app', []).config(function($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
$routeProvider
.when('/',
{
controller: 'HomeController',
templateUrl: '/partials/home.html'
})
.when('/about',
{
controller: 'AboutController',
templateUrl: '/partials/about.html'
})
.when('/privacy',
{
controller: 'PrivacyController',
templateUrl: '/partials/privacy.html'
})
.when('/404',
{
controller: 'NotFoundController',
templateUrl: '/partials/404.html',
})
.otherwise({
redirectTo: '/404'
});
});
Notice the otherwise above. That tells angular to load the 404 page when a route is not recognized.
I'm starting to learn about Expressjs, Twitter Bootstrap and BackBonejs.
I have created the basic Expressjs app with the command line tool and added an index.html for the sign in form. When the user click on the "Sign in" button which have an event attached, I retrieve the form information and make an ajax call to the '/login' route but it does not work ..
Here a list of the necessary files :
index.html
login.js
server.js
routes.js
Thank you for your help.
The issue is that the form is still submitting via redirect as that's its default bahavior and it hasn't been instructed to do otherwise. And, because of the redirect, the browser is is aborting the Ajax request.
To prevent the redirect, you'll want to bind to the .submit() event of the <form> and use event.preventDefault():
$(document).ready(function () {
$('#login-form').submit(function (e) {
e.preventDefault();
});
});
It may also be worthwhile to use this event for the Ajax rather than the .click() of the <button> as many browsers allow submitting through other actions besides just clicking a type="submit" button (e.g., pressing Enter when focus is on a <input type="text">):
$(document).ready(function () {
$('#login-form').submit(function (e) {
e.preventDefault();
var _login = $('#login').val(),
_password = CryptoJS.SHA512($('#password').val()),
_remember = $('input:checkbox:checked').val() ? 1 : 0;
// etc.
});
});
For one, you need to prevent the default action from the button click:
$('#btn-login').click(function () {
// ...
});
// should accept the passed event and `prevenDefault`, like...
$('#btn-login').click(function (e) {
e.preventDefault();
// ...
});
Is there an API to programmatically refresh the current tab from inside a browser action button? I have background page configured, which attaches a listener via:
chrome.browserAction.onClicked.addListener(function(tab) { ... });
So the callback function retrieves a reference to the tab that it was clicked from, but I don't see an API anywhere to refresh/reload that tab.
I think what you're looking for is:
chrome.tabs.reload(integer tabId, object reloadProperties, function callback)
Check out tabs API() documentation for more information.
The API for chrome.tabs.getSelected(), which the accepted answer uses, has been deprecated. You should instead get the current tab and reload it using something like the following:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(arrayOfTabs[0].id, {code: code});
});
Or perhaps:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
chrome.tabs.reload(arrayOfTabs[0].id);
});
I had no real luck with the second version, though other answers seem to suggest it should work. The API seems to suggest that, too.
I recommend using chrome.tabs.executeScript to inject javascript that calls window.location.reload() into the current tab. Something like:
chrome.tabs.getSelected(null, function(tab) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(tab.id, {code: code});
});
Reference here
More specifically:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.reload(tab.id);
});
You can also use this:
chrome.tabs.reload(function(){});
reload function params: integer tabId, object reloadProperties,
function callback
Reference: http://developer.chrome.com/extensions/tabs.html#method-reload
if you want to reload all the tabs which have loaded completely and are active in their window
chrome.tabs.query({status:'complete'}, (tabs)=>{
tabs.forEach((tab)=>{
if(tab.url){
chrome.tabs.update(tab.id,{url: tab.url});
}
});
});
you can change the parameter object to fetch only active tabs as {status:'complete', active: true} refer to query api of chrome extensions
Reason for not using chrome.tabs.reload :
If the tab properties especially the tab.url have not changed, tab does not reload. If you want to force reload every time, it is better to update the tab URL with its own tab.url which sends the event of the change in property and tab automatically reloads.