I have designed a flutter screen, in which I have button upon pressing that Button A I get a popup window, which has Button 1 to add new textfield, and we can add any number of textfield, for this I have used flutter_form_bloc dependency example. Then in the popup window there is another button, ie Button 2, which upon pressed process the data entered into the textfields and exits the popup window.
Now when again I press the Button A to open the popup window all the textfields are gone and so the data. I don't want that to happen. I want that those should there until the main flutter screen is there or not exited.
Moreover, upon pressing the Button 2 in the popup window the data should be passed to the class of the main flutter screen in which Button Ais there and should stored in a instance so that the data passed could be processed further.
Here are the screenshots to get the idea
[Image 1]1 [Image 2]2
CODE
FormBlocListener<ListFieldFormBloc2, String, String>(
onSubmitting: (context, state) {
},
onSuccess: (context, state) {
String name1;
var parsedData = json.decode(state.successResponse);
List members = parsedData['members'];
members.forEach((member){
name1 = member['step'];
List<String> _step = [];
_step.add(member["step"]);
_AddStepsState().getsteps(members);
});
_AddStepsState(steps: members);
Navigator.pop(context);
},
onFailure: (context, state) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(state.failureResponse)));
},
child: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Column(
children: <Widget>[
BlocBuilder<ListFieldBloc<MemberFieldBloc2>,
ListFieldBlocState<MemberFieldBloc2>>(
bloc: formBloc.members,
builder: (context, state) {
if (state.fieldBlocs.isNotEmpty) {
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: state.fieldBlocs.length,
itemBuilder: (context, i) {
return MemberCard2(
memberIndex: i,
memberField: state.fieldBlocs[i],
onRemoveMember: () =>
formBloc.removeMember(i),
);
},
);
}
return Container();
},
),
RaisedButton(
color: Colors.blue[100],
onPressed: formBloc.addMember,
child: Text('ADD STEP'),
),
],
),
),
),
I tried to pass the LIST generated to another class in these ways _AddStepsState(steps: members); and _AddStepsState().getsteps(members); but both time it failed.
I want to the the list of the values in the text field generated to be passed to another class
And Also I want that while the user is in Screen1 as in Image 1 if the fields are edited as in image 2 and if the user opens the popup screen again the fields should remain there and not removed.
How should I achieve it?
if any more information is required , please let me know
the link to the dependency used is here flutter form bloc
I have just recently created an app that deals with a lot of forms and the solution I've gone with is as follows:
Have a file called data_center.dart where you can define classes to represent data created by a form / to be displayed in a "review" page.
class MyFormData{
String firstField;
String secondField;
int quantity;
// more attributes
// optional constructor
MyFormData({this.firstField, this.secondField, this.quantity});
}
Create a variable to hold instances of the class in data_center.dart
MyFormData currentMyFormDataInstance; // assign an instance every time a new form starts
Create instance in dialog (for example)
import 'data_center.dart' as DataCenter;
// code removed for brevity
return showDialog(
context: context,
builder: (BuildContext context) {
// create an instance to hold the current form data
currentMyFormDataInstance = DataCenter.MyFormData();
return AlertDialog(...);
]);
});
Store controller (assume we have a TextFormField) value in instance
TextFormField(
controller: _myController,
onChanged: (String _incomingValue){
DataCenter.currentMyFormDataInstance.firstField = _incomingValue;
}
)
I don't know if there are any critical flaws or inefficiencies that might come along but so far, it has worked very well for me as it allows me to easily manage all the different kinds of data groups I am collecting from the UI.
Moreover, storing these data as objects rather than data types such as Maps has allowed me to easily transform them by adding named constructors or extra methods that easily allows me to do common and frequent operations on my data.
For example, if you are using Cloud Firestore. I can add the following named constructor to easily map DocumentSnapshots to the class attributes.
MyFormData.fromDocumentSnapshot(){...}
I'm using these style for suggested actions. When the number of suggested actions are more, i want the suggested actions to be in a container with fixed height and overflow hidden with scrollable.
It looks like there are no style options to do the currently. Could you please check if this can done?
const styleOptions = {
suggestedActionBackground: 'White',
suggestedActionBorder: 0,
suggestedActionBorderRadius: 4,
suggestedActionBorderStyle: 'solid',
suggestedActionBorderWidth: 1,
suggestedActionHeight: 32,
suggestedActionLayout: 'stacked', // either "carousel" or "stacked"
};
enter image description here
This is achievable thru use of CSS, Web Chat's store, and an event listener. A couple things to note, however.
One, this requires manipulating the DOM directly. Generally, this is frowned upon in a React environment. Whether you are using the React version of Web Chat or not, Web Chat is built upon React. Because of this, components may change in the future which could break this setup. Please bare this in mind.
Two, the example below is a simple setup. You will need to adjust it to meet your needs. For instance, you may need to further isolate certain buttons or specific suggested actions as they arrive.
First, we setup our CSS. I have two classes. hideSuggestedActionsContainer is used to, initially, hide any suggested actions. If we don't set this immediately, then the CSS changes made to suggested actions will be momentarily visible to the user as they are rendered. suggestedActionContainer sets the container styling, including enabling (but hiding) scrolling in the container.
.hideSuggestedActionContainer {
display: none;
}
.suggestedActionContainer {
background: white;
width: 300px;
height: 200px;
display: flex;
flex-direction: column;
justify-content: flex-start;
overflow-y: scroll;
-ms-overflow-style: none;
}
.suggestedActionContainer::-webkit-scrollbar {
display: none;
}
In Web Chat, we utilize the store to manage what actions we take and when. The store is passed in as a parameter into Web Chat.
When Web Chat first connects (DIRECT_LINE/CONNECT_FULFILLED), we assign the hideSuggestedActionContainer class to the suggested actions DIV wrapper.
As the suggested action arrives (WEB_CHAT/SET_SUGGESTED_ACTIONS), we remove the hideSuggestedActionContainer class and assign the suggestedActionContainer class allowing the suggested action to be viewed.
At the same time, we monitor the incoming activities (DIRECT_LINE/INCOMING_ACTIVITY) looking for the associated HTML element that houses the suggested action. As Web Chat only allows for one suggested action to be displayed at a time, this should be the first object in the [role=status] array (again, things could change in the future). From that array, we collect the various suggested action buttons and, when one is clicked, we dispatch an event.
const store = window.WebChat.createStore( {}, ({dispatch}) => next => action => {
if ( action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
setTimeout( () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.add( 'hideSuggestedActionContainer' );
}, 20 )
}
if ( action.type === 'WEB_CHAT/SET_SUGGESTED_ACTIONS' ) {
const { suggestedActions } = action.payload;
if ( suggestedActions.length > 0 ) {
setTimeout( () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.remove('hideSuggestedActionContainer');
suggestedAction.classList.add( 'suggestedActionContainer' );
}, 20 )
}
}
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.type === 'message') {
const actions = document.querySelectorAll( '[role=status]' );
const buttons = actions[0].querySelectorAll('button');
buttons.forEach( button => {
button.onclick = function() {
const buttonClick = new Event('buttonClick');
window.dispatchEvent( buttonClick )
};
} )
}
}
next(action);
} );
[ ... ]
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine( {
token: token
} ),
store: store,
styleOptions: styleOptions
},
document.getElementById( 'webchat' )
);
Below the Web Chat renderer, we place our event listener. As a suggested action button is clicked, we remove the suggestedActionContainer class and re-assign the hideSuggestedActionContainer class.
const buttonClickEvent = ( function () {
window.addEventListener( 'buttonClick', () => {
let actions = document.querySelectorAll( '[role=status]' );
let suggestedAction = actions[ 0 ];
suggestedAction.classList.remove( 'suggestedActionContainer' );
suggestedAction.classList.add( 'hideSuggestedActionContainer' );
} );
} )()
A note about the setTimeout() functions used in the store. The store processes every activity as it arrives before displaying it. Because of this, a slight delay needs to be applied to the changes we are pushing to the DOM. Without setTimeout(), the page tries to render our changes before the store is able to display the activity's associated HTML. I set the time outs to 20 milliseconds, but you may find you will need to adjust this. I have found that if I set the time out to too low a number then the changes occur before the activity is rendered. If it's too long (300+ ms or thereabouts), then the changes become visible to the user.
Hope of help!
In my viewer I want to be able to select multiple dbids and save to database, but with control-shift I am able to do selection, but later when retrieving I may be able to show using select([dbid array]), should work fine. But again If I want to select a new dbid, it's pain to use control to select new dbids every time and another thing is my event handler(AGGREGATE_SELECTION_CHANGED_EVENT) I need to write extra code to identify which is the latest dbid I selected and all?
Any suggestion on this for an easy solution to manage this?
If you'd like to preserver the current selection while selecting extra nodes programmatically try concatenate the current selected dbids with new ones:
const currentSelection = NOP_VIEWER.getSelection()
currentSelection.push(dbid)
NOP_VIEWER.select(currentSelection)
I need to write extra code to identify which is the latest dbid I selected and all?
Yes Viewer does not keep track of the order/timestamps of your selection so you will need to manage this yourself.
control-shift I am able to do selection
You might also want to find out about the click behavior settings to change default behavior of clicks on objects:
const config = {
"click": {
"onObject": ["selectOnly"],
"offObject": ["deselectAll"]
},
"clickAlt": {
"onObject": ["setCOI"],
"offObject": ["setCOI"]
},
"clickCtrl": {
"onObject": ["selectToggle"]
// don't deselect if user has control key down https://jira.autodesk.com/browse/LMV-1852
//"offObject": ["deselectAll"]
},
"clickShift": {
"onObject": ["selectToggle"]
// don't deselect if user has shift key down https://jira.autodesk.com/browse/LMV-1852
//"offObject": ["deselectAll"]
},
}
NOP_VIEWER.setCanvasClickBehavior(config)
I am new to React Native. How can we refresh/reload previous screen when returning to it by calling goBack()?
Lets say we have 3 screens A, B, C:
A -> B -> C
When we run goBack() from screen C it goes back to screen B but with old state/data. How can we refresh it? The constructor doesn't get called 2nd time.
Adding an Api Call in a focus callBack in the screen you're returning to solves the issue.
componentDidMount() {
this.props.fetchData();
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
() => {
this.props.fetchData();
}
);
}
componentWillUnmount() {
this.willFocusSubscription.remove();
}
UPDATE 2023: willFocus event was renamed to focus
componentDidMount() {
this.props.fetchData();
this.focusSubscription = this.props.navigation.addListener(
'focus',
() => {
this.props.fetchData();
}
);
}
componentWillUnmount() {
this.focusSubscription();
}
How about using useIsFocused hook?
https://reactnavigation.org/docs/function-after-focusing-screen/#re-rendering-screen-with-the-useisfocused-hook
const componentB = (props) => {
// check if screen is focused
const isFocused = useIsFocused();
// listen for isFocused, if useFocused changes
// call the function that you use to mount the component.
useEffect(() => {
isFocused && updateSomeFunction()
},[isFocused]);
}
For react-navigation 5.x use
5.x
use
componentDidMount() {
this.loadData();
this.focusListener = this.props.navigation.addListener('focus', () => {
this.loadData();
//Put your Data loading function here instead of my this.loadData()
});
}
For functional component
function Home({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
loadData();
//Put your Data loading function here instead of my loadData()
});
return unsubscribe;
}, [navigation]);
return <HomeContent />;
}
On your screen B constructor will work like magic :)
this.props.navigation.addListener(
'didFocus',
payload => {
this.setState({is_updated:true});
}
);
Yes, constructor is called only for the first time and you can't call it twice.
First: But you can separate the data getter/setter from the constructor and put it in a function, this way you can pass the function down to the next Scene and whenever you're going back you may simply recall the function.
Better: You can make a go back function in your first scene which also updates the scene while going back and pass the go back function down. This way the second scene would not be aware of your update function which is reasonable.
Best: You can use redux and dispatch a go-back action in your second scene. Then in your reducer you take care of going back & refreshing your scene.
The built in listener function which comes with React-Navigation would be the easiest solution. Whenever a component is 'focused' on a again by navigating back, the listener will fire off. By writing a loadData function that can be called both when loading the Component AND when the listener is notified, you can easily reload data when navigating back.
componentWillMount(){
this._subscribe = this.props.navigation.addListener('didFocus', () => {
this.LoadData();
//Put your Data loading function here instead of my this.LoadData()
});}
Easy! insert the function inside useFocusEffect(func)
import { useFocusEffect } from '#react-navigation/native'
I have a similar situation and the way i refreshed was to reset the route when the back button is pressed. So, what happens is when the back button is pressed the screen is re-pushed into the stack and the useEffect on my screen loads the data
navigation.reset({
index: 0,
routes: [{ name: "SCREEN WHERE THE GOBACK BUTTON SHOULD GO" }],
});
Update for react-navigation v5 and use the React Hooks. Actually, the use is the same with react base class. For more detail, please checkout the documentation here
Here is the sample code:
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
As above code, We add the event listener while the variable navigation change then We do something like call function refresh() and finally, we return the function for removing the event listener. Simple!
I think we have a very easy way (which works in 2021) to do so. Instead of using goBack or navigate, you should use push
this.props.navigation.push('your_route_B').
You can also pass params in the same way as we pass in navigate.
The only difference b/w navigate and push is that navigate checks if the route which we are passing exists in the stack. Thus taking us to the older one but, push just sends us there without checking whether that is in the stack or not (i.e, whether the route was visited earlier or not.)
This can be achived by useFocusEffect from '#react-navigation/native'
useFocusEffect will effect every time when screen is focus
Ref: https://reactnavigation.org/docs/use-focus-effect/
import { useFocusEffect } from '#react-navigation/native';
function Profile({ }) {
useFocusEffect(
React.useCallback(() => {
//Below alert will fire every time when profile screen is focused
alert('Hi from profile')
}, [])
);
return // ...code ;
}
You can use this event: navigation.addListener('focus'
And you can implement like this:
const Cards = ({ navigation }) => {
...
useEffect(() => {
const load =async ()=>{
const a = await selectGlobalCards()
}
navigation.addListener('focus',() =>{
load();
});
}, [])
or you can use useIsFocused, and you can use that as a dependecy for useEffect
import { useIsFocused } from '#react-navigation/native'
const Cards = ({ navigation }) => {
const isFocused = useIsFocused()
useEffect(() => {
const load =async ()=>{
const a = await selectGlobalCards()
}
load()
}, [isFocused])
For react navigation (5.x), you just need to add a focus subscription and put your component initializing logic in a separate function like so:
componentDidMount() {
this.init();
this.didFocusSubscription = this.props.navigation.addListener(
'focus',
() => {
this.init();
}
);
}
init = async () => {
//fetch some data and set state here
}
If you're trying to get new data into a previous view, and it isn't working, you may want to revisit the way you're piping data into that view to begin with. Calling goBack shouldn't effect the mounting of a previous component, and likely won't call its constructor again as you've noted.
As a first step, I would ask if you're using a Component, PureComponent, or Functional Component. Based on your constructor comment it sounds like you're extending a Component class.
If you're using a component, the render method is subject to shouldComponentUpdate and the value of your state is in your control.
I would recommend using componentWillReceiveProps to validate the component is receiving the new data, and ensuring its state has been updated to reflect the new data.
If you're using the constructor to call an API or async function of some kind, consider moving that function into a parent component of both the route you're calling goBack from and the component you're wanting to update with the most recent data. Then you can ask your parent component to re-query the API, or update its state from a child component.
If Route C updates the "state/data" of the application, that update should be propagated to a shared parent of routes A, B and C, and then passsed down as a prop.
Alternatively, you can use a state management solution like Redux to maintain that state independent of parent/child components - you would wrap your components in a connect higher-order component to get the latest updates any time the application state changes.
TL;DR Ultimately it sounds like the answer to your question is rooted in where your application state is being stored. It should be stored high enough in your component hierarchy that each route always receives the latest data as a prop, passed from its parent.
Thanks to #Bat.
I have spent a lot of hours on finding the answer and finally, I got a basic solution which is working according to my needs. I was quite worried though.
Simply make a function like this in your previous activity make sure to bind it.
changeData(){
var mydata= salesmanActions.retrieveAllSalesman();
this.setState({dataListFill: mydata});
alert('' + mydata.length);
}
Simple, then in constructor bind this,
this.changeData= this.changeData.bind(this);
After that, as I am using react native navigation, so I will simply pass this function to the second screen just like the code below:
onPress={() => this.props.navigation.navigate('Add Salesman', {doChange:
this.changeData} )}
So when the new screen registered as "Add Salesman" will be called, a parameter named "doChange" which is assigned a function will also be transfered to other screen.
Now, in other screen call this method anywhere, by :
this.props.route.params.doChange();
It works for me. I hope works for you too, THANKS for the idea #Bat.
let we have 2 screen A and B , screen A showing all data . and screen B is responsible for adding that data. we add some data on using screen B and want to show instant changes on Screen A . we use below code in A
componentDidMount(){
this.focusListener = this.props.navigation.addListener('focus', () => {
thi`enter code here`s.startData();
//Put your Data loading function here
});
}
This is what you can do with react navigation v6.
Create a separate stack in stack navigator like this:
const PropertyListStack = () => {
return (
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name={ROUTE_PROPERTY_LIST} component={PropertyList}/>
</Stack.Navigator>
)};
Now, whenever you you want to reload your initial screen navigate using this stack. like this:
navigation.navigate(
ROUTE_DASHBOARD_TABS,
{screen: ROUTE_PROPERTY_LIST_STACK}
);
This will reload your base screen. In my case base screen is PropertyList.
If you know the name of the Screen you want to go , then you can use this code.
navigation.navigate("Screen"); navigation.replace("Screen");
This code works fine if you don't have nested routes.
This answer assumes that the react-native-navigation library is being used, which is unlikely because it doesn't actually have a goBack() method...
The constructor doesn't call a second time because screen A and B are still rendered (but hidden behind screen C). If you need to know when screen B is going to be visible again you can listen to navigation events.
class ScreenB extends Component {
constructor(props) {
super(props);
// Listen to all events for screen B
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
}
onNavigatorEvent = event => {
switch (event.id) {
case 'willAppear':
// refresh your state...
break;
};
}
Other events: willDisappear, didAppear, didDisappear
An alternate solution to your problem is to use a state management solution like Redux to provide the state to all screens whenever it is updated (rather than just on screen transitions. See old react-native-nav/redux example.
I've been reading through the documentation, but I can't seem to get it right.
I'm trying to implement a custom conditional hook by wrapping some supplied hooks. It should restrict access to a service (the method doesn't matter) by:
1) First checking if the user has the admin or super-admin roles using:
auth.restrictToRoles({
roles: ['admin', 'super-admin']
}),
If the user has the required roles, the hook should allow access. Otherwise..
2) Restrict access to owner using:
auth.restrictToOwner({ ownerField: 'id' }),
What I can't figure out is how to get and check the result of auth.restrictToRoles so I can run auth.restrictToOwner if needed.
Any help would be greatly appreciated!
There are two options. The easier on is to not use the pre-built hooks. Almost every pre-built hook can be implemented on your own in just a couple of lines of code. It could look like this:
app.service('myservice').before({
find(hook) {
const { user } = hook.params;
const {roles } = user;
if(roles.indexOf('admin') !== -1 && roles.indexOf('super-admin') !== -1) {
hook.params.query.userId = user._id;
}
}
});
The other way would be to create a wrapper hook that first calls restrictToRoles and then catches any error (notice that it is basically more code than implementing it entirely on your own):
const restrictToRoles = auth.restrictToRoles({
roles: ['admin', 'super-admin']
});
const restrictToOwner = auth.restrictToOwner({ ownerField: 'id' });
app.service('myservice').before({
find(hook) {
return restrictToRoles(hook).catch(() => restrictToOwner(hook));
}
});