I want to be able to specify a base url for all my routes for development. Some of the devs have machines setup to work out of subdirectories instead of the application sitting at the webroot.
I would like to only define these routes once.
Instead of:
routes: {
"toms-subdirectory/users": "init_users"
}
I would like:
routes: {
"/users": "init_users"
}
and be able to specify a baseurl for that installation so I could easily make it work across installs.
Right now I'm forcing them by defining a route object using bracket syntax to keep the dynamic keys and assigning that to the routes property inside the route. I was wondering if there is a cleaner way.
my_routes = {};
my_routes[window.webroot + '/users'] = 'init_users';
MyRoute = Backbone.Router.extend({ routes: my_routes })
You can use Backbone.history.start like this
Backbone.history.start({
pushState: true,
root: "/public/search/"
});
Related
I have a locale.js file which is responsible for defining user locale. Here it is:
import store from '#/vuex/index'
let locale
const defaultLocale = 'en_US'
if (store.getters['auth/authenticated']) {
locale = store.getters['auth/currentUser'].locale || defaultLocale
} else {
if (localStorage.getItem('locale')) {
locale = localStorage.getItem('locale')
} else {
locale = defaultLocale
}
}
export default locale
Also I have a i18n.js file which is responsible for making i18n instance which I use when I init my app.
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import locale from '#/services/locale'
Vue.use(VueI18n)
const fallbackLocale = 'en_US'
let i18n = new VueI18n({
locale,
fallbackLocale,
})
i18n.setLocaleMessage('ru_RU', require('#/lang/ru_RU.json'))
i18n.setLocaleMessage('en_US', require('#/lang/en_US.json'))
export { i18n }
Now I think that it'd be more convenient to have URLs prefixed with locale, like /en/profile or /ru/profile. This way I can share a link with locale which would be already set.
Not sure how do to this though. Making all routes child and put /:locale? is not that convenient because router is not yet initialized (I pass i18n and router instances simultaneously when initing root app instance).
How can I achieve that, what would be the best approach?
You can implement router
routes: [{
path: '/:lang',
children: [
{
path: 'home'
component: Home
},
{
path: 'about',
component: About
},
{
path: 'contactus',
component: ContactUs
}
]
}]
and set locale in beforeEach hook
// use beforeEach route guard to set the language
router.beforeEach((to, from, next) => {
// use the language from the routing param or default language
let language = to.params.lang;
if (!language) {
language = 'en';
}
// set the current language for vuex-i18n. note that translation data
// for the language might need to be loaded first
Vue.i18n.set(language);
next();
});
There are two or three problems I can think of that comes with nesting all your routes under a single /:locale?.
Route definitions may become ambiguous. If you have paths /:locale?/foo/bar and /:locale?/bar defined as routes, what will <RouterLink to="/foo/bar" /> match? That will depend on which of those routes is defined first, and if the second of my examples is matched it will lead to an invalid locale. This problem has a simple-enough solution; just constrain your :locale parameter using a regex. If you know the exact list of supported locales statically, you could do something like:
import locales from '#/lang' // Your list of supported locales.
const regexp = locales.join('|') // You may want to filter out 'en' first.
const routes = [{
path: `/:locale(${regexp})?`,
children: [
...
],
}]
If your translations and list of supported locales are otherwise only available at runtime (e.g. they're retrieved via an API), you may be forced to create a regex specific to your locale tag format. If they match BCP-47, I believe that means either 2 or 3 characters for the primary subtag, and the script and region are optional. If you use normalized tags (lowercase primary, titlecase script, uppercase region), that's even better, because that will further reduce ambiguity:
const routes = [{
path: '/:locale([a-z]{2,3}(-[A-Z][a-z]+)?(-([A-Z]{2}|[0-9]{3}))?',
caseSensitive: true,
children: [
...
],
}]
You'll want to read the spec more closely than I have to ensure that regex is correct. You'll also need to guard against unsupported locales in your beforeEach hook, so that you can load a "Not found" error page.
As long as you do not define any routes whose first path segment could be mistaken for a locale tag, the above should fix the ambiguity problem.
Routes may accidentally be defined using root paths. Nested routes are usually defined using relative paths, i.e. paths not anchored with a /. However, nesting is not simply a mechanism for sharing prefixes or parameters among many routes, it is most often used for sharing layout components. Vue-router therefore allows you to override the parent route definition's path by defining an absolute path. The documentation explains:
Note that nested paths that start with / will be treated as a root path. This allows you to leverage the component nesting without having to use a nested URL.
Mistakenly defining an absolute path will cause the route to only be matched for the fallback (I assume English) locale. As developers are likely to prototype and test using English most of the time, it might not appear like anything is amiss.
For a small application where all your routes are defined within a single file, this may not be a big deal as the error is probably easy to spot. But for a large application with many route definition files and many developers, such an error is going to be more difficult to catch.
Every usage of <RouterLink> and programmatic navigation will require injecting the locale parameter. You'll need to remember to interpolate $i18n.locale into every to prop and push() call. Not doing so does not cause an error or break the page, so your tests are unlikely to catch this, and you won't notice any problems if you're only browsing in English. You could wrap or extend <RouterLink> with your own component that does this automatically, but that doesn't prevent someone from accidentally using RouterLink, as it is still globally-registered. You could also write a global mixin to add convenience methods for router.push()/.replace()/.go(), but this again would not protect you against accidental use of those methods.
One not-ideal solution to the above problems is to forego defining the locale as a path parameter, and instead match it prior to initializing the router. To do this, you have to pass it as the base constructor option. Unfortunately, the base path does not appear to be alterable, meaning locale changes will require a new page request. Since most users will likely change locale at most once, this might not be a huge problem, but nonetheless does not give the best user experience.
I have created a simple Node.js application, throughout which I use static route paths. So I need to know how to access an object without requesting in every route in my application.
Current method =>
routeLink.js
var routesMap = [{
createUserRoute: '/create-user',
route2: '/user-profile',
// ...
}];
createUserRoute.js
var routLinks = require('./config/routeLink');
module.exports = function(router){
router.post('/', function(req, res){
// do the task
res.redirect(routLinks.createUserRoute);
});
}
Just like you see in this example, I have to
require('./config/routeLink')
without using this how to I access routesMap from all of the Routers?
You have two option if you don't want to require your config in each route file:
1/ make your config global in your whole application ( not recommended )
2/ use environment variables, take a look at dotenv
In Flow Router, I have some routes
/projects/project-name
/projects/project-name/tasks
/projects/project-name/tasks/deleted-tasks
/projects/project-name/tasks/completed-tasks
/projects/project-name/tasks/labels/school
/projects/project-name/tasks/labels/football
/projects/project-name/tasks/labels/training
/projects/project-name/tasks/labels/personal
[...]
So almost all of my routes should share most of the same characteristics.
Are there any tricks to group my routes, so I do now have to check if the project exists in every single route or if can I say that some routes build upon other routes, so I do not have to write the long paths for all the routes?
I have found Flow Router, but it doesn't seem that's right tool to accomplish what I need.
Flow router definitely has the ability to group your routes. You can group them as follows -
var projectRoutes = FlowRouter.group({
prefix: '/projects/project-name',
name: 'projects',
});
To handle routers within this group, you can add
// route for /projects/project-name
projectRoutes.route('/', {
action: function() {
BlazeLayout.render(...);
}
});
// route for /projects/project-name/tasks
projectRoutes.route('/tasks', {
action: function() {
BlazeLayout.render(...);
}
});
This is just an example for grouping your routes.
You can read more here.
I have a Router.map defined to my application. I'm working with EmberJS AppKit architecture. https://github.com/stefanpenner/ember-app-kit
I'd like to access to my page "profile" using the following path:
http://localhost:8000/#/profile
But, the name of my route differ to this path, because it's call user-profile, so I did this:
router.js
var Router = Ember.Router.extend();
Router.map(function () {
this.resource('user-profile', { path: 'profile'}, function() {
//Some other things...
});
});
export default Router;
user-profile.js
export default Ember.Route.extend({
model: function () {
return this.store.find('user-profile');
}
});
When I launch my application, Ember is telling me that profile route doesn't exist, even though I defined the path:
Uncaught Error: Assertion Failed: Error: Assertion Failed: The URL '/profile' did not match any routes in your application
Do you know what's wrong with my code at this point?
Thanks
I dont use ember appkit but perhaps try with underscore, ie 'user_profile' and rename your file too. Just a shot in the dark.
I would have to guess it is the way that you are designing your router and the namespace.
Typically a barebones Ember app requires:
window.App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true
});
App.Router.map(function () {
this.resource('user-profile', { path: 'profile'}, function() {
//Some other things...
});
In your example your router is not in the App namespace, or whatever your root object is named (It doesn't have to be 'App'). I would give this a try or maybe post more code if there are other factors I do not see here.
Also, typically you would name your route userProfile. While i dont think the dasherized name is a problem, it doesn't follow Ember naming conventions.
Hope this helps.
I'm building my first Express app. It's a bit messy as my controllers and my models are all in the same place: the app.js file.
Is there a way that I can separate those?
Even artificially, by creating different files and then using some third party program to compile them into the app.js file.
First of all, you need to create your controllers and model folders.
You can use a module called express-load which can be used to autoload models, routes, schemas, configs, controllers, object maps... etc...
in your main file, mine is called app.js you load them right before start the server code line.. it should look like
//requires....
var load = require('express-load');
//your code
load('models')
.then('controllers')
.then('routes')
.into(app);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express listening on port "+ app.get('port'));
});
module.exports = app;
Then, your view folder you can create folders to keep your code organized, then subfolders, I created a folder called home, and inside of it my index view.
In my controllers folder I created a js file called home.js, and which will look for my index view:
module.exports = function(app){
var HomeController = {
index: function(req, res){
res.render('home/index');
}
};
return HomeController;
}
At last in your routes folder, you can set your application routes, each view needs to be specified in your controller. My file for routes its called home.js
module.exports = function(app){
var home = app.controllers.home;
app.get('/', home.index);
}
What I generally do it is to write a module which contains all the routes definition and load it in app.js e.g
require('./routes')(app);
My ./routes.js generally looks like this
module.exports = function (app) {
log.info('Loading express routes...');
/* registration */
app.post('/users', require('./routes/register-users')); // register user
app.post('/agents', require('./routes/register-agents')); // register agents
};
and I keep all the routes (.js) files inside a directory call routes
Hope it is what you are looking for.
Is there a way that I can separate those?
Yes, and you should separate them.
What most people do is declare the routes in the main app.js file and include separate files for the controllers (just like Rituparna described).
Those controllers files will in turn very likely include your model files via a require. For example.
In app.js
var blogRoutes = require('./routes/blogRoutes');
app.get('/api/blog/all', blogRoutes.all);
In routes\blogRoutes.js
var model = require('../models/blogModel');
var all = function(req, res) {
// your controller logic
// and very likely calls to your model
var m = model.blog(whatever);
res.send(m.something());
};
module.exports = {
all: all
}
In models\blogModel.js
var something = function() {
return "something";
};
module.exports = {
something: something
}
You can see a working version of this in this repo https://github.com/hectorcorrea/hectorcorrea.com
You should checkout the examples from the Express Github repo, there are multiple ways to do this (based on personal preference):
https://github.com/visionmedia/express/tree/master/examples/mvc
https://github.com/visionmedia/express/blob/master/examples/resource/app.js
https://github.com/visionmedia/express/tree/master/examples/route-separation
There are some examples here that may help you..
Route Separation: https://github.com/visionmedia/express/tree/master/examples/route-separation
MVP: https://github.com/visionmedia/express/tree/master/examples/mvc