const router = new VueRouter({
routes: [
{path: '*', redirect: '/'}
}
)}
I have set this as redirect route in routes.js file.
how i can set more than 1 redirect path and call it on particular condition
In the component you want to set multiple redirects based on a condition you can use beforeRouteEnter() property in that component like below:
beforeRouteEnter(to,from,next){
next(vm => {
if(condition 1){
vm.$router.push('the path you want to redirect');
}else if(condition 2){
vm.$router.push('the path you want to redirect');
}else{
//no redirect
next();
}
});
}
Since the vue instance is not yet created when beforeRouteEnter() property is called you cannot use this to access the vue instance and follow the process the method shown above via vm
Another way would be by using route meta feilds where you would include a meta field when defining a route and checking for a meta field in the global navigation guard. In that global navigation guard you can redirect by checking various if statements.
Related
I want to insert a script in my application's <head>, but the src attribute of that script depends on a runtime environment variable in my hosting server (OpenShift).
So if process.env.ENVIRONMENT === "test", I want to insert <script src="www.someurl.com/test.js" /> into the application's <head> and if it's "prod" then something else.
I have all these src values stored in a json file that I don't want to show up in the client. How do I make sure the client can receive the correct src from the server without having access to the json file with all the environment's endpoints?
Express:
With Express I used to just inject the src value into the window object at runtime before serving index.html but I'm not sure how to do it in Next.js
Code: Here's what I tried
// _app.tsx
...
<Head>
<script src={getScript()} type="text/javascript" />
</Head>
...
where getScript() is a function in <root>/scripts
export function getScripts() {
if (process.env.ENVIRONMENT === "test") {
return scriptSrc.test;
} else if (process.env.ENVIRONMENT === "prod") {
return scriptSrc.prod;
}
}
You can use getServerSideProps to pass properties from the server to the client. Since the server has access to any runtime env variables, you can simply pass your variable to the client. In the render function use the env variable to decide which script to inject into the header.
This simple page showcases how to pass an env variable:
export const getServerSideProps = async () => {
return {
props: {
my_env: process.env.RUNTIME_ENV || 'default',
}
}
}
export default function MyPage(props) {
return <div>{props.my_env}</div>
}
npm run dev renders "default" while RUNTIME_ENV="foobar" npm run dev renders "foobar".
I couldn't find a way to populate the data in _app.js at fetch time from the server since that file doesn't support getServerSideProps so I took the long road and did it client side instead.
Step 1:
Create an api route that returns back a JSON object with all the data you need in all the pages of the application. All process.env references work inside the pages/api folder since that code always runs on the server.
export default (
req: NextApiRequest,
res: NextApiResponse<StartResponseType>
) => {
res.status(200).json(getScripts(process.env.ENVIRONMENT.trim()));
};
Step 2:
Now we need an efficient way to cache this response on the client since we don't want to keep fetching it for every page. I used react-query for this.
export function queryStart() {
return useQuery<StartResponseType>("start", getStart, {
staleTime: Infinity,
});
}
Step 3:
We can't use the hook created above in _app.js until we wrap our App component in QueryClientProvider, so we need to create a Higher Order Component since there's no component that wraps App.
export const withQueryCache = (Page: any) => (props: any) => (
<QueryCacheProvider>
<Page {...props} />
</QueryCacheProvider>
);
Step 4:
Now we just need to put it all together and add a loading state to the App so it only initiates the application once the initial data has been fetched.
// _app.tsx
function App({ Component, pageProps }: AppProps) {
const startQuery = queryStart();
if (startQuery.isSuccess) {
return (
<>
<Head>
<script src={startQuery.data.scriptEndpoint} type="text/javascript" />
</Head>
<Component {...pageProps} />
</>
);
} else return <>Loading</>;
}
export default withQueryCache(App);
However, I would've still preferred for a way to just inject data from the server at fetch time. That would've been possible if _app.js file supported getServerSideProps. But until that's supported, this seems to be the best workaround.
I want to use the current route's name in a v-if statement in a a template. I have read that there is a complicated 3rd party way, but I want something better.
<template v-if="$this.routes.getName() == '/customers'">
if you register the route with a name then it's too simple
Your route
{
name: 'Foo',
path: '/foo'
component: 'Foo.vue'
}
Then it's just
this.$route.name
And it will return Foo
You can compare with name, however if you want to compare with path then
this.$route.path // it will return exact path after domain i.e. www.google.com/foo
if(this.$route.path === '/foo') {
console.log('I am on foo route')
}
Try loggin your route object and explore what else you have
console.log(this.$route)
I´m making a CRUD in laravel with vue.js & axios. I did create the complete CRUD, but using routes that return the data from my controller, but if I put the route that returns the data, obviously all people can access to the data that returns the controller.
I´m using laravel 5.5, vue.js & axios. if I put the route in the browser, for example: localhost/tasks all the data that I passed in my controller it shows.
Routes:
Route::get('/', function () {
return view('dashboard');
});
Route::resource('tasks', 'TaskController',['except' => 'show', 'create', 'edit']);
Controller:
public function index()
{
$tasks = Task::orderBy('id', 'DESC')->get();
return $tasks;
}
app.js
data: {
keeps: [],
newKeep: '',
fillKeep: {'id': '', 'keep': ''},
errors: []
},
methods: {
getKeeps: function()
{
//este es el nombre de las rutas (index)
var urlKeeps = 'tasks';
axios.get(urlKeeps).then(response =>{
this.keeps = response.data
});
},
// Metodo de editar
editKeep: function(keep){
this.fillKeep.id = keep.id;
this.fillKeep.keep = keep.keep;
$('#edit').modal('show');
},
The principal dashboard is in the '/' route, the controller returns the data from my controller, the route is "/tasks" and the other methods, but when any other user put in the browser "www.myweb.com/tasks" it returns all the data from my controller, ¿How can I avoid that problem?
If the Tasks model has multiple users' data you should be restricting the tasks route to return only the current logged in user's data. This is the same whether its accessed via Ajax or directly in the browser window.
Restrict that route with the auth middleware and scope the tasks Eloquent query to return that user's data.
e.g.
$tasks = Task::where('user_id', \Auth::user()->id)->orderBy('id', 'DESC')->get();
Then it doesn't matter if the user visits the URL directly and sees their own data.
Well if you want to restrict all from entering this path you could simply put a middleware that if the requested url is this then return to home.
Here you can find all middleware documentation:
https://laravel.com/docs/5.8/middleware
About the condition you could simply put in your user table a column that its name for example tasks_access and you put it nullable() so that the middleware will do an if statement then if this column is null then return redirect home and basically it will be always null.
In migration the user migration
$table->boolean('tasks_access')->nullable();
then you can either make a middleware or you can do simply in your controller
if (!#Auth::user()->tasks_access){
return redirect('/user');
so that your controller will be like this
public function index()
{
if (!#Auth::user()->tasks_access){
return redirect('/user');
}
$tasks = Task::orderBy('id', 'DESC')->get();
return $tasks;
}
so that based on your user table the tasks_access column the user tasks access is null by default so that it will always return redirect the user to the /user route or you could change it to be /home or whatever you want
Note : I answered based on your question but I don't know why you want to block all users from seeing data and the data in the first place should be shared with users because data without users is useless
Here is a screenshot from their docs about <Link> component
What state do they mean? A Redux state?
How does it look like to pass a state? Like this?
pathname: '/foo',
query: {
x: this.props.x,
},
state: store.getState()
It's a piece of information that you'd like to send to the next page. Nothing to do with Redux. It's a plain object. I believe Flipkart is a very nice example of how it can be used to improve user experience:
Go to a Flipkart search page on a mobile device (or simulate one using Chrome DevTools)
Tap on one of the items
You'll see that the transition happens instantly and pieces of information like product images, title, rating and price are readily available on the product page. One way to implement that is passing the state they had already loaded on the search page onto the next one:
<Link
to={`/product/${id}`}
state={{
product,
}}
/>
And then:
function ProductPage(props) {
// Always check because state is empty on first visit
if (props.location.state.product) {
console.log(props.location.state.product);
// { id: '...', images: [...], price: { ... } }
}
}
There are two ways to pass data from one route to another via Link.
URL Parameter.
As state.
URL parameter help when the route params contain strings for example we want to route to a particular profile:
<Link to='/azheraleem'>Visit Profile</Link>
However, the later i.e. the state helps us pass data from one route to another which is complex data structure. (objects/arrays).
As per the react router documentation, in case of passing data from one route to another it can be done as per the below code sample:
<Link
to={{
pathname: "/profile",
search: "?name=azheraleem",
state: { fromDashboard: true }
}}
/>
The pathname is the link to the route while the search attribute contains the query string parameters, thus the on clicking the link the URL will form something like:
http://localhost:3000/profile?name=azheraleem.
But the state variable value can be accessed in the called route using the useLocation hook:
import { useLocation } from "react-router";
const profile() => {
let data = useLocation();
console.log(data.state.fromDashboard);
}
The the state property of the to prop is the param of pushState method of History DOM object described here
That props used in push/replace methods of router as described here for transitions to a new URL, adding a new entry in the browser history like this:
router.push('/users/12')
// or with a location descriptor object
router.push({
pathname: '/users/12',
query: { modal: true },
state: { fromDashboard: true }
})
It also mentioned here:
router.push(path)
router.push({ pathname, query, state }) // new "location descriptor"
router.replace(path)
router.replace({ pathname, query, state }) // new "location descriptor"
state is a property that's part of the object you can provide to the to prop of the <Link> component.
It is particularly useful if you want to send data from the current view to one the <Link> directs you to, without using common techniques such as setting URL parameters or using libraries, such as Redux.
There isn't much official information about the state key, but here's what I found in the source code of that component:
Links may pass along location state and/or query string parameters
in the state/query props, respectively.
So basically, it's like sending props to a component from a parent. Here, you are sending "state" from the current view to the target view. That's about it, really.
In simple term state in <Link/> component is use to pass information from one view to other view through router in form of object.On other page it can be access using prop.location.state.
(Note: on browser refresh state no longer contain information)
To pass state in Link:
<Link to={{pathname: "/second_page", state: {id: 123}}} />
To access id in second page view:
let id = props.location.state.id;
For more Link properties : React Router Link
I am trying to implement simple authentication with react-router. I think there is an issue with replace and callback. Consider following code:
1) Routing configuration
function getRoutes() {
return {
path: "/",
indexRoute: require("./Home"),
component: require("./Shared/Layout"),
onEnter: handleEnter,
childRoutes: [
require("./Login"),
require("./Secured"),
require("./Any")
]
}
}
function handleEnter(nextState, replace, callback) {
let state = store.getState()
if (!state.hasIn(["shared", "user"])) {
store.dispatch(fetchUser())
.then(callback)
}
}
2) ./Secured route configuration
export = {
path: "/secured",
component: require("./Secured"),
onEnter(nextState, replace) {
let state = store.getState()
if (!state.getIn(["shared", "user"])) {
replace("/login")
}
}
}
It should work like this:
Fetch user when entering root route (async operation, we need callback)
Go to /secured and check whether user is authenticated when entering the route
If user is not authenticated go to /login
The problem is that the /login page will not be rendered. The URL is changed to /login, but nothing is displayed and there are no error messages in console. When I remove callback parameter from the root route configuration, it starts working as expected.
Am I doing something wrong?
Well, it was really stupid :) I've forgot to call callback when user is already authenticated.