I have a URL: http://app/material/id/58
I want to get the id '58' on another widget but I am not able to splice the value.
Any suggestions?
Dojo 2 Widgets can then be configured with these outlet identifiers
using the Outlet higher order component. Outlet returns a new widget
that can be used like any other widget within a render method, e.g.
w(MyFooOutlet, { })
Map Parameters:
When a widget is configured for an outlet it is possible to provide a callback function that is used to inject properties that will be available during render lifecycle of the widget.
mapParams(type: 'error | index | main', location: string, params: {[key: string]: any}, router: Router)
The following example uses mapParams to inject an onClose function that will go to the route registered against the other-outlet route and id property extracted from params in the MyViewWidget properties:
const mapParams = (options: MapParamsOptions) {
const { type, params, router } = options;
return {
onClose() {
// This creates a link for another outlet and sets the path
router.setPath(router.link('other-outlet'));
},
id: params.id
}
}
const FooOutlet = Outlet(MyViewWidget, 'foo', { mapParams });
Related
I am adapting a ReactNative mobile app to ReactNative Web. The app is done with react-navigation.
Currently, every time I set the params of a route (either through navigate or setParams), those params show in the URL. I end up with bad looking URLs like so:
http://localhost:19006/me/undefined?user=%5Bobject%20Object%5D
Either that or the URL contains irrelevant data for the user and generally looks messy.
Is there a way to not show the route params inside the URL?
You should re-consider if params is an appropriate place to have this data if you don't want in the URL. That you think that the URL contains irrelevant data is a sign that the data doesn't belong in the navigation state.
If you visit a screen directly from a URL, it should render the same as when you navigated to it porgrammatically. If you're passing something in params, it means that that information is needed for the screen to render correctly, and if you remove it from the URL, then that information is lost. Consider that it's possible to open the page directly from a URL, either on Web or with a deep link. If the required data isn't available, then it's not going to work.
In your case, seems like you're passing a full user object (maybe not, hard to say without code). Ideally, this object should be in your global store instead of params, and you should only pass the user id in params. Then you should gran the full object from your global store using that id, or trigger a data fetch if the objet isn't fetched yet (if needed).
You didn't specify the version of React Navigation in your question. In v5, you can customize how your params are stringified to URLs, and how they are parsed back using the stringify and parse options:
const linking = {
screens: {
Profile: {
path: 'user/:id',
parse: {
id: (id) => id.replace(/^#/, '')
},
stringify: {
id: (id) => `#{id}`,
},
},
},
};
This should help you with making URLs look prettier, and handle cases where params are not simple strings. However you can't omit params from the URL altogether since they are necessary data for the screen to render.
More details: https://reactnavigation.org/docs/configuring-links#passing-params
satya164's answer is definitely the proper path to follow. Just wanted to also post this solution as it is a direct answer to the question, even if not the most advisable.
import { getPathFromState} from "#react-navigation/native";
const linking = {
screens: {
...
},
getPathFromState(state, config){
let path = getPathFromState(state, config);
const index = path.indexOf("?")
if(index>=0){
path = path.substr(0, index);
}
return path;
}
};
NOTE: To use this solution you need to make sure that every object and function parameters are optional, otherwise if you reload the page you will get an error.
I removed every object and function from the url adding this custom getPathFromState to linkingOptions:
const linking = {
config: {
screens: {
...
}
},
getPathFromState: (state, options) => {
const cleanState = {
...state,
routes: state.routes.map(route => {
if(!route.params) {
return route
}
const cleanParams = {}
for(const param in route.params) {
const value = route.params[param]
if(typeof value !== "object" && typeof value !== "function") {
cleanParams[param] = value
}
}
return {
...route,
params: cleanParams,
}
}),
}
return getPathFromState(cleanState, options) //imported from #react-navigation/native
},
}
You can pass the parameters the component needs as a prop
like this
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
then in Details Component
const { itemId , otherParam} = route.params;
Alternatively, if you use Redux/Mobx or any other global state management
You can pull the data from there and not pass it through the URL
then get data with the help connect or with useSelector hooks
I'm curious since both seem to work and I'm having trouble finding an answer in the Vue docs. Is there a reason you should refer to data in Vue as this.$data.whatever vs just this.whatever?
The data with $ prefix is specifically defined for accessing vue data property rather than user defined property.
For eg.
var data = { foo: 'foo' } // user defined data
var inst = new Vue({ data: { foo: 'foo' } }) // data - built-in vue property
data.foo // user defined data
inst.$data.foo // vue property - data
When you're inside the Vue hooks, you can just simply use this.foo for eg. inside computed method.
For more detail, you can see the docs
The $data attribute is used to access the data property outside the component:
var data = { a: 1 }
// direct instance creation
var vm = new Vue({
data: data
})
vm.a // => 1
vm.$data === data // => true
// must use function when in Vue.extend()
var Component = Vue.extend({
data: function () {
return { a: 1 }
}
})
Source: https://v2.vuejs.org/v2/api/#data
Background: I'm working on building a mobile app with react-native, and am setting up AWS's AppSync for synchronizing the app with cloud data sources.
The challenge: I have a view which shows all items in a list. The list's ID is passed in as a prop to the component. I need to use that list ID to query for the items of that list. I have the query working fine if I hard-code the list ID, but I'm having a hard time figuring out how to dynamically set the list ID for the query when props update.
Here's what I have working (with a hard-coded ID of testList01) in my ListPage component:
const getListItems = id => gql`
query getListItems {
getListItems(listID: ${id}) {
reference_id,
quantity,
}
}
`;
export default graphql(getListItems('testList01'), {
options: {
fetchPolicy: 'cache-and-network',
},
props: props => ({
listItems: props.data ? props.data.getListItems : [],
data: props.data,
}),
})(withNavigationFocus(ListPage));
I would like to be able to dynamically set which list to look up the items for based on a list ID, which is being passed in from props. Specifically, I'm using react-navigation to enter the ListPage, a view where a user can see the items on a List. So here's the code that gets executed when a user clicks on a list name and gets routed to the ListPage component:
handleListSelection(list: Object) {
const { navigation, userLists } = this.props;
navigation.navigate('ListPage', {
listID: list.record_id,
listName: list.list_name,
userLists,
});
}
From my previous (pre-AppSync/GraphQL) implementation, I know that I can access the list ID in ListPage via this.props.navigation.state.params.listID. I would like to be able to use that in my AppSync query, but because the query is created outside the component, I'm unable to access the props, and so am struggling to get the ID.
Got this working using a package called react-apollo-dynamic-query which I found here. The author of that package also links directly to a simple function for doing what I'm trying to do here.
Essentially it just wraps the regular graphql call in a simple way that exposes the props so they can be passed down to the query.
My code now looks likes this (which I have below my definition of the ListPage component, in the same file):
const getListItems = props => {
const listID = props.navigation.state.params.listID;
return gql`
query getListItems {
getListItems(listID: "${listID}") { // Note the variable being wrapped in double quotes
reference_id,
quantity,
}
}
`;
};
const config = {
options: {
fetchPolicy: 'cache-and-network',
},
props: props => ({
listItems: props.data ? props.data.getListItems : [],
}),
};
const MyApolloComponent = graphqlDynamic(getListItems, config)(ListPage);
export default MyApolloComponent;
It should work like this:
const getListItems = (id) => {
return gql`
query getListItems {
getListItems(listID: ${id}) {
reference_id,
quantity,
}
}
`;
}
Call this getListItems like the below
export default graphql(getListItems(id), { //from where ever you want to send the id
options: {
fetchPolicy: '
......
I have not tested this code. Please update if this works. Although I am quite sure that it works.
I have a vuejs app using vue-router with the following routes.
const routes = [
{ path: '/list', component: list, alias: '/' },
{ path: '/resources/:id?', component: resources },
{ path: '/emails', component: emails },
{ path: '/list/:id', component: editHousehold, props: true },
{ path: '/list/turn-off/:id', component: editHousehold, props: true }
]
The first time the page loads the start event calls /resources w/o an ":id" and the page loads a list of resources (see below).
start: function () {
this.$http.get('/resources')
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
},
Resource1
Resource2
Rescouce3
...
When the user clicks on one of the resources in the list I want to have /resources/1 called so a different set of resource data can be loaded and displayed.
I have a file click event attached to each resource where the "id" is appended to the path. This calls the server side module which would retrieve new data which would replace the "files" data in the component which I would expect would cause vuejs to "react" and update the contents of the page.
onFileClick: function (id, mimeType, event) {
const _this = this;
this.$http.get('/resources/' + id)
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
}
However, calling above does not initiate a call to the server module.
this.$http.get('/resources/' + id)
I've also tried
this.$router.push('/resources/' + id)
which did not work.
Being new to vuejs, any help in how to achieve this functionality would be appreciated.
You lack host, because this.$http.get('/resources/' + id) is u component resources, this not json...
It looks like you're not making the REST call correctly. I think you're getting routing and REST calls mixed up. What you show above is for routing not making calls to the server.
You're not calling the server here:
this.$http.get('/resources/' + id)
and doing this is just for the routing:
this.$router.push('/resources/' + id)
Look at using axios for REST calls:
https://github.com/axios/axios
Using the vue-router package, it is easy to match dynamic segments:
router.map({
'/user/:username': {
component: {
template: '<p>username is {{$route.params.username}}</p>'
}
}
})
However, I couldn't figure out how to use the value a component method, e.g.
router.map({
'/user/:username': {
component: {
ready: function() {
// How to access the param here?
alert($route.params.username);
}
}
}
})
How can I access the matched segment in the component method?
Is almost as what you posted
// inside your component
this.$route.params.username
The key is that in the template you don't need to refer to the this scope, but in methods you have to use it
The $route object is injected in every router maped compeonents , as per your case you would use the params method to get the key/value passed .
router.map({
'/user/:username': {
component: {
ready: function() {
// How to access the param
// use the scope 'this'
alert(this.$route.params.username);
}
}
}
})
for more info check out http://router.vuejs.org/en/api/route-object.html