React Router: How to properly append to route/url without replacing anything? - reactjs

How do I append to the route with react router?
Let's say the current route is /page1/page2 and I want to route to /page1/page2/next-page
first I get the router
const router = useHistory();
When I use push like this
router.push("next-page");
It routes to /page1/next-page.
When I use add a / like this
router.push("/next-page");
It routes to /next-page
I also tried something like this
router.push(`${router.location.pathname}/next-page`)
But the problem this way is, when I'm currently at /page1/page2/, I end up at /page1/page2//next-page with two //.
Is there a good way to solve this without having to write the complete route like router.push("/page1/page2/next-page")?

What I ended up doing is defining a function that removes an / form the url if there
export const removeSlashSuffix = (input) => {
if (input.charAt(input.length - 1) === "/") {
return input.substr(0, input.length - 1)
} else {
return input;
}
}
and then route like this
router.push(`${removeSlashSuffix(router.location.pathname)}/nest-page`)
This way I get no issues with routes that resolve in url with // in it.
This is somewhat of a hacky solution and I wish react-router-dom would support this out of the box but it doesn't seem like it does

If you do router.push("/page1/page2/next-page"), it should work. I think you need to specify the full path, I don't see anything wrong in doing so

if you want to append something to an existing path, you should be able to do something like
const location = useLocation()
const currentPath = location.pathname // to get current route
router.push(`${currentPath}/next-page`)
THis is a sudo-code, so you may need to tweak it a bit for proper syntax

Related

Netlify Redirect or Rewrite for Gatsby Wildcard Path

So I've already implemented a wildcard path on my gatsby-node.js file:
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
if (page.path.match(/^\/my-path/)) {
page.matchPath = "/my-path/*"
createPage(page)
}
}
and this works fine when I am running the site locally (in development). i.e., if i provide /my-path/anything123 or /my-path/asdfasdfasdf, both will lead to a rendering of the component I've created in my Gatsby project under pages/my-path.tsx.
Now we come to my problem. When I deploy my site to Netlify, I don't get the same behavior as in development. Can behavior like this be handled with a redirect or rewrite in Netlify? I don't want to lose the content in what comes after /my-path/, as in reality I'm using it to parse an id, i.e. if the URL in the browser is /my-path/123, I want to be able to see that 123 in window.location.href, and parse it with some logic in my-path.tsx.
I hope this is clear. Appreciate anyone who can help or guide me in the right direction!
Of course after writing this all up the answer becomes clear... I tried it, and it works! for the example I was providing, the following redirect would work in your netlify.toml file:
[[redirects]]
from = "/my-path/*"
to = "/my-path"
status = 200
force = true
So it essentially has to match 1:1 with the rules you define in gatsby-node.js.

Disabling routes in angular js + laravel project

I have a laravel application which uses angular js as the front end. There I need to disable this route. appo.dev/ which means the root path of the application. How can I disable that path only. Here I need to access other routes such as appo.dev/progess. I tried the following way in routes.php file. It's better if I can find a solution with this code.
Route::any('{path?}', function () {
return view("appo_app");
})->where("path", ".+")
->whereNotIn("path", "appo.dev/");
Above without whereNotIn clause it will work for all the routes. So I am thinking a way to disable only that particular route via wherenotin clause. Or is there a better wild card character? Anyone knows how to solve this issue.
Maybe without what you want is like the root route did not exist, you can try this.
And it will return an error 404. Maybe that's what you're looking for?
I assume that appo.dev is the domain.
Route::any('/', function () {
abort(404);
});
Route::any('{path?}', function () {
return view("appo_app");
})->where("path", ".+");
If it were not the domain, maybe this will help you.
Route::any('appo.dev', function () {
abort(404);
});
Route::any('appo.dev/{path?}', function () {
return view("appo_app");
})->where("path", ".+");
I hope it helps you. A cordial greeting.

react-router-dom with multiple query strings does not work

I am new to react router. I use react-router-dom 4.2.2
in my router set up I have:
<Route path={"/confirmuser/:confirmation_code/:username"} component={ConfirmUser} />
and here is a sample url I am trying to achieve:
localhost:3003/confirmuser?confirmation_code=986797&username=5f1
As you see I am trying to send multiple query strings.
in the confirmUser I read the query strings as follow:
console.log(this.props.match.params.confirmation_code);
console.log(this.props.match.params.username);
However I do not even get directed to this component and it seems react is not able to route to that page properly.
Any idea?
React-router v4 doesn't parse query strings anymore, so you either have to do the parsing yourself (not recommended), or use a package like query-string. An easy way to access the values is with a wrapper component, like this:
import * as queryString from 'query-string';
..
const WrappedConfirmUser = () => {
const {confirmation_code, username} = queryString.parse(location.search);
return <ConfirmUser confirmation_code={confirmation_code} username={username}/>;
}
You are trying to map search-params to path segments?
The Route you defined will try to match the path, not the search params.
Try:
http://localhost:3003/confirmuser/986797/5f1
and the values will be in this.props.match.params like this:
{
confirmation_code: '986797',
username: '5f1',
}
if you still want to read the search params, you can access them from this.props.location.search, but react-router will not match them to a route for you.
Your path doesn't match your url.
It matches localhost:3003/confirmuser/986797/5f1
Then you can access params using extra prop match:
{props.match.params.confirmation_code}
{props.match.params.username}

Avoid traliing slash for default routes in Backbone.js

I'm looking for something to accomplish in Backbone. Here is the explanation.
I have backbone routes like
{
'': 'defaultRoute',
'test': 'test',
'testing': 'testing'
}
Assuming my root url is '/routes'
Now when I say 'router.navigate('test', {trigger: true});' url changes to /routes/test.
Similar way when I call 'router.navigate('testing', {trigger: true});' url changes to /routes/testing.
But when I call 'router.navigate('', {trigger: true});' url changes to /routes/.
You know i didn't expect that / at the end. I never passed that. It should have been back to root url i.e. '/routes'.
Adding / at the end makes lot of difference/meaning. Checkout 'http://googlewebmastercentral.blogspot.in/2010/04/to-slash-or-not-to-slash.html'
Any fix for that (i.e. not having / at the end for default route)?
Try to override Backbone.History.prototype.navigate.
Copy default function and change this line :
var url = this.root + fragment;
to :
if(this.root !== '/' && fragment === ''){
var url = this.root.replace(trailingSlash, '');
}else{
var url = this.root + fragment;
}
First things first:
If your application is not being served from the root url / of your
domain, be sure to tell History where the root really is, as an
option: Backbone.history.start({pushState: true, root:
"/public/search/"})
Backbone#History
In your case, it is most likely to be something like root: "/routes". Something you need to keep in mind is that your website is seen in the browser as either a resource or a remote folder, therefore the default route without a trailing slash may not fully work by just leaving it as "" because that means usually "the current folder". You could try to set your root url as root: "/" instead (just as it should be by default) and create a "routes" resource as your default route, something like the following:
{
'test': 'test',
'testing': 'testing',
'routes': 'defaultRoute',
'*': 'catchAll'
}
Another recommendation that I am doing to you (as you can see it above) is to set your a catch all URL at the end in case someone enters a non-existent one, and you can also use it to redirect your users to your default route.
// your code above ...
defaultRoute: function() {
// your default route code...
},
catchAll: function() {
this.navigate('routes', {trigger: true});
}
// your code below ...
Finally, by any reason mess up with Backbone URLs manually, you are highly risking yourself to break the whole thing AND if in the future the API changes it should be easier to update if you just follow the intended use.
Update:-
This has been already fixed in Backbone's latest version. I asked a question on there forum and found the answer. I'm adding it here as an answer if it helps anyone who is looking for the same thing.
https://github.com/jashkenas/backbone/issues/2871

Router in backbone not handling route after initialization

I have multiple routers in my app, in general way it looks like this:
// Start backbone.js
if (!Backbone.History.started) {
Backbone.history.start({pushState: true, hashChange: false});
}
// Perform some RPC requests ...
// Depending on user role, received from the server should be created suitable router:
var router;
if (typeof app.user.role === 'manager') {
router = new routers.manager();
} else {
router = new routers.guest();
}
Problem is that after page is loaded and script is executed routers do not do. anything. They do not load route for current url automatically. So, i had to fix it this way (i am not sure that it is a right way):
routers.guest.initialize = routers.manager.initialize = function() {
var defaultRoute = 'default';
if (typeof this.routes[Backbone.history.fragment] !== 'undefined') {
this[this.routes[Backbone.history.fragment]]();
} else {
this.navigate(defaultRoute, true);
}
};
It is working fine, except one bug: when i use route with params, for example /reset-password-confirm/:code - it is unable to find in in routes property. I could write some more code to fix it, but i suppose that i am doing something wrong, if i have to write such things - as i understand router should handle routes just after it was created.
So, questions:
Why my router(s) does not handle routes for current url after it is being created? Perhaps i need to start backbone history later? (but this bug will happen again later then)
How it is possible to make routes with params like /user/:id work there?
Perhaps it is bad idea to re-create routers? Perhaps it is better to create all of them one time?
P.S. I've tried to create both routers and keep them, also i've trie to call backbone history start method after all routers were created.. but this didn't help :/
Assuming you route is declared as the following:
routes : {
'/user/:id' : 'user'
}
Your initialize code is not working because when you initialize your router with a url such as: /user/1234. Backbone.history.fragment will be /user/1234 (not /user/:id). Since the this.routes object doesn't have a key of /user/1234, your else clause calls the default route.
If you first instantiate your router then call Backbone.history.start(), you will be able to remove your router initialize code. When you navigate to a url as /user/1234 your router will match the /user/:id route and call the user function.
The following should work for you without adding your initialize code:
var router = (app.user.role === 'manager') ? new routers.manager()
: new routers.guest();
Backbone.history.start({pushState: true, hashChange: false});
Looking at the code, seems like you're starting the backbone history before initializing any routes. That's most likely not goning to work.
The correct way of doing this type of seperation is by creating all the routes based on the role received from the server and then start the backbone history. Here's an SO thread that talks about it with code samples as well : How to protect routes for different user groups

Resources