I'm actually getting the params like that:
http://localhost:9080/app?{%22address%22:%22rsPENV8NaobtaFqHmArDVVhDRRGVjmD5ep%22}
with this route
routes: {
"app":"app"
}
As you can see it's really ugly and I would like to have this simple:
http://localhost:9080/app/rsPENV8NaobtaFqHmArDVVhDRRGVjmD5ep
Or something like that
http://localhost:9080/app/#/rsPENV8NaobtaFqHmArDVVhDRRGVjmD5ep
You see the idea...
But when I try app/*address or app/:address it's not working , meaning I can't catch my params or even the page.
So basically /app is server, how to get the param without the ugly way I use ?
Edit: Here is a pretty good example I found in a tutorial:
routes: {
"posts/:id": "getPost",
// Example
"download/*path": "downloadFile",
// Download
":route/:action": "loadView",
// Load Route/Action View
},
So here the question would be how to get something like that
http://example.com/app/#/myparam
The good rule is to separate your routes. In your situation I'd do something like this:
routes: {
"p/:param_name": "getSomething"
};
...
getSomething: function(param_name) {
...
}
But if really don't need to use specific area in the router you should add your target route to the end of your routes.
routes: {
"p/:param_name": "getSomething",
...
":param": "getSomething"
};
Related
I am using navigate to move to another URL. I saw many posts using Link to move to another page with dynamic url. But I want to change url without writing jsx
When I navigate to the following url, I get a 404 error
navigate(`/vidx/${u}`, {
state: { vid: r }
})
I changed gatsby-node.js to following, still getting the same error. I have a file named vidx.js in pages folder
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
if (page.path.match(/^\/vidx/)) {
page.matchPath = "/vidx/*";
createPage(page);
}
}
My url will look like this - www.xyz.com/vidx/123456789. The number 123456789 will depend upon the user logged in
I want to redirect to vidx.js; but the URL should be /vidx/123456789
That will never work since /vidx/123456789 will always throw a 404 error since it's not generated and doesn't exist, it's a separate new page.
One easy thing you can do use: /vidx?queryParameter=123456789. In that case, your page will remain being /vidx and you can get the queryParameter to make your stuff with your own logic.
I have a settings page, with a few sub routes:
--/home
--/articles
--/settings
--/Account(default)
--/Help
--/About
I would like it in such a way: when I'm in any one of the sub pages under settings, and the browser go back in history, it should always go to the (default)Account page. Going back again will follow the normal browser history behavior.
What's the best way of handling it?
You can use history:
import createHistory from "history/createBrowserHistory"
const history = createHistory()
history.push("/account")
<Router history={history}/>
After quite some research, it seems there's no easy way of doing it, discussions in react-router github wouldn't disagree. A workaround seems to be the consensus. Which is a bit raw to my liking, but anything that works is good.
So instead of keeping every sub page under settings with their own route(to be handled by react-router), I have them controlled by state in settings component. And the following event handling is used:
componentDidMount = () => {
window.onpopstate= () => {
if(this.state.currentSubPage !== 'account-settings') {
this.props.history.push('/settings');
} else {
window.onpopstate = null;
}
};
}
So, currently, I have a routing component:
<Route path="/lists/:query" component={Lists} />
I get a call like:
http://localhost:4567/lists/page=17&city_codes=2567
In my Lists component, I handle this query in this way:
componentDidMount() {
const query = match.params.query;
const cleanQueryString = query.replace(/[|;$%#"<>()+,]/g, '');
// break up the string using '&' and '=' into an object
const properties = this.queryURL(cleanQueryString);
const cleanQueryObj = _.pick(Object.assign({}, ...properties), [
'page',
'city_codes',
'min_monthly_fee',
'max_monthly_fee',
'order_by',
]);
// update the query object based on component state
this.setState({ query: cleanQueryObj }, () => {
cleanQueryObj.page && this.updateIndex(parseInt(cleanQueryObj.page, 10));
});
// call axios request and update redux
dispatch(handleLists(cleanQueryObj));
// update browser url
this.props.history.push(cleanQueryObj);
Now, I see a lot of major sites using ?q= before the query and I'm wondering what I'm missing or what could be improved?
Thoughts?
While what you are doing is technically valid, it is a bit non-standard. The way you use the router :query param and the way it is formatted, reaaaaly looks like an actual location.search parameter format, and not a path parameter.
A more standard way to do it, would be with the following URL:
http://localhost:4567/lists?page=17&city_codes=2567
And code as follow:
// In your routes, just a simple route with no path params
<Route path="/lists" component={Lists} />
// In your component
import queryString from 'query-string'
[...]
componentDidMount() {
// Use location object from react-router
const { search } = this.props.location
// Parse it using a npm dedicated module
const { page, city_codes } = queryString.parse(search)
// Now you can use those params
]);
Edit: and now an actual answer to the question:
?q=blah is usually used in a search context, with q parameter being a string used to search something. There can be other parameters following for example ?q=blah&ext=txt.
It is hence different from your :query path param, which is encoded to contain multiple parameters, while q here is a single ready-to-use parameter.
I've read this post, but I don't like having browserHistory.push('/some/path') in one of my components while I have <Route path="/some/path" component={SomePage} /> in my router file since the path is duplicated. What if I want to change that path to /another/path? Now I need to remember to update it in the router file and also my component.
Is there a better way around this? I was thinking that I could have "/some/path" and all my other paths defined in some constants file that gets imported and referenced in my router and my component. Example:
paths.js
var Paths = {
myPath: "/some/path",
...
}
module.exports = Paths
router.jsx
var Paths = require('constants/paths');
...
<Route path={Paths.myPath} component={SomePage} />
component.jsx
var Paths = require('constants/paths');
...
browserhistory.push(Paths.myPath)
This seems like it could get a little messy when dealing with URL parameters like /some/path/:id, so I was hoping there might be a better way.
This is what I have done in the past for routing to make it simpler / more streamlined.
(as a side note i used lodash here so if you aren't you can use native functions to do basically the same thing. lodash just adds a bunch of nice features / functions that you dont need to go write yourself)
in my routes.jsx file you should create functions that convert any parameters into a url with a default path for this answer lets just make one for a profile route
export function pathToProfile(userName, params) {
return path(Paths.PROFILE, _.assign({userName}, params));
}
the path() function is just a simple helper utility function for generating a path.
path(url, params, urlMap) {
if(!url) {
console.error("URL is not defined for action: ", params);
}
if(!params)
return url;
params = _.merge({}, params);
if(urlMap) {
_.keys(urlMap).forEach((k) => {
params[urlMap[k]] = params[k];
delete params[k];
});
}
if(url.indexOf(":") !== -1) {
url.match(/:([0-9_a-z]+)/gi).forEach((match)=>{
var key = match.replace(":", "");
url = url.replace(match, params[key]);
params = _.omit(params, key);
});
}
if(_.keys(params).length > 0) {
url = url + "?" + this.paramsToString(params);
}
return url;
}
now looking at the constants file
Paths {
PROFILE: '/user/:username',
}
Finally usage.
I wouldn't recommend broswerHistory.push() when you can have an onClick handler. Yes it works and will redirect, but is it the best thing to use? react-router also has a Link that should be used wherever possible. you get some nice additional features one for example would be an active route for whatever page you're on.
browserHistory.push() is a good way to handle redirecting when you do things like an auth login redirect or if you are responding to data from a request and conditionally taking them to a page.
<Route path={Paths.PROFILE} component={Profile} />
<Link to={pathToProfile(this.props.user.username, {myParams: 'here'})></Link>
what that would be translated into if you wanted to see the url from that exact link it would be /user/someUsername?myParams=here
Does NancyFX supports ASP.NET MVC like 'Catch All' route? I need one, that basically match every URL. This is very handy for building up Single Page applications.
Is that possible?
Tested in Nancy version 0.23.2
Get[#"/(.*)"] did not work for me as a catch-all route. The routes "/", "/foo/bar", and longer routes would not catch. It seems like there's no getting around having to define a Get["/"] route for the root URL. Nothing else seems to catch it (tried Get["{uri*}"]). Here's how I ended up defining my routes (keep in mind I'm doing this for an Angular application):
Get["/views/{uri*}"] = _ => { return "A partial view..."; };
Get["/"] =
Get["/{uri*}"] = _ =>
{
var uri = (string)_.uri;// The captured route
// If you're using OWIN, you can also get a reference to the captured route with:
var environment = this.Context.GetOwinEnvironment();// GetOwinEnvironment is in the 'Nancy.Owin' namespace
var requestPath = (string)environment["owin.RequestPath"];
return View["views/defaultLayout.html"];
};
It's important to understand Pattern Scoring. The route patterns are weighted, if two routes match the same url segment, the higher score wins. The catch-all pattern is weighted 0 and even though the /views/{uri*} route pattern is also a catch-all, it starts with a literal, which is weighted 10000, so it will win out on all routes that start with /views.
Here's more info on Accessing Owin's Environment Variables. Note that the captured uri variable and requestPath will be slightly different. The requestPath will start with a / where as the uri variable will not. Also, if the matched route pattern is Get["/"], uri will be null and requestPath will be "/".
The Views route will return a partial html file, based on the url path, and all other routes will return the default Layout page that will bootstrap the SPA.
Yes, using Regex
Get[#"/(.*)"] = parameters => {
return View["viewname", parameters];
};
But you don't really need it for building a Single Page Application with NancyFX - you can just use Get and Post with all your routing logic and still have a single page app.
An updated answer for whom #synhershko 's solution does not work. Try:
Get[#"^(.*)$"] = parameters => {
return "hi";
};
This will capture all paths except for the index page. I am not sure if this will work in the context of Angular, but this worked for me when trying to hack together a simple server with just one handler.
Answer provided by #synhershko does not work for me. It does not handle /users/2 or any other route containing more segements.
Below code works on my machine ;) :
public class IndexModule : NancyModule
{
dynamic IndexPage() { return View["Index"]; }
public IndexModule()
{
Get["/"] = _ => { return IndexPage(); };
Get["/(.*)"] = _ => { return IndexPage(); };
Get["/(.*)/(.*)"] = _ => { return IndexPage(); };
Get["/(.*)/(.*)/(.*)"] = _ => { return IndexPage(); };
}
}
My solution is not perfect, cause it does not match everything. I repeated as many '/(.*)' as in my longest Angular route.