I'm using ReactiveCommand:
LoginCommand = new ReactiveCommand(this.WhenAny(x => x.UserName, x => x.Password, (r, g) => !string.IsNullOrEmpty(r.Value) &&!string.IsNullOrEmpty(g.Value)));
LoginCommand.Subscribe(async _ =>
{
var user = await _authenticationService.AuthenticateUser(_userName, _password);
if (user.Error != null)
{
MessageBox.Show("The user was not found. Please try again!", "User Not Found", MessageBoxButton.OK, MessageBoxImage.Exclamation);
return;
}
screen.Router.Navigate.Execute(new MainViewModel(screen));
});
And UserName, Password field for binding:
public string Password
{
get { return _password; }
set { this.RaiseAndSetIfChanged(ref _password, value); }
}
And Textbox for this binding to:
<TextBox x:Name="txtPassword" Text="{Binding Password}" Grid.Column="1" Grid.Row="2" Margin="3,3,0,3" MinWidth="100" HorizontalAlignment="Left" Width="10" Height="30"/>
This code work but when I lose focus on textbox. Is there any proper way to do this when I start writing on textbox with reactiveUI.
Use UpdateSourceTrigger property. As the name implies, this means that whenever there is a change in the Text property of TextBox, RaiseAndSetIfChanged fires.
<TextBox x:Name="txtPassword" Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="2" Margin="3,3,0,3" MinWidth="100" HorizontalAlignment="Left" Width="10" Height="30"/>
Related
I'd like to have my markers popup open even after rerender. I have a marker showing user position so that updates all the time. After that marker rerenders that closes the popup of other marker.
My code:
const StaticReferencePoints = (props) => {
const { selectedCalibrationPoint, setSelectedCalibrationPoint, staticReferencePoints } = props;
const addToast = useToastContext();
const [snackbarOpen, setSnackbarOpen] = useState(true);
const [latitude, longitude] = useGeolocationStoreHelper(['latitude', 'longitude']);
const [map, setMap] = useState(null);
const center = [latitude, longitude];
const markerRef = useRef({});
const [selectedMarker, setSelectedMarker] = useState(null);
useEffect(() => {
// open popup if it exists
if (selectedMarker) {
markerRef.current[selectedMarker]?.openPopup();
}
}, [selectedMarker, latitude, longitude]);
useEffect(() => {
if (map) {
map.addEventListener('click', () => {
setSelectedMarker(null);
});
}
}, [map]);
const handleSnackbarClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSnackbarOpen(false);
};
const handleDeletePoint = (point) => {
if (confirm('Are you sure you want to delete this point?')) {
Meteor.call(...) => {
if (err) {
console.log(err);
addToast('Error deleting point', 'error');
}
if (res) {
console.log(res);
addToast('Point deleted', 'success');
}
});
}
};
const SingleMarker = (point) => {
const [anchorEl, setAnchorEl] = useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<Marker
key={'staticPoint-' + point.point?.name}
position={point.point?.coordinates}
ref={(el) => (markerRef.current[point.point.name] = el)}
eventHandlers={{
click: () => {
setSelectedMarker(point.point.name);
},
}}
>
<Popup options={{ autoClose: false }}>
<Grid container item justifyContent={'center'} xs={12}>
<Grid item container direction={'row'} xs={12}>
<Grid item xs={1} container justifyContent={'center'} alignItems={'center'}>
{ACL.check) && (
<div>
<IconButton size="small" onClick={handleClick}>
<MoreVertIcon />
</IconButton>
<Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
<MenuItem onClick={() => handleDeletePoint(point.point)}>
<ListItemIcon>
<DeleteIcon />
</ListItemIcon>
<ListItemText primary="Delete" />
</MenuItem>
</Menu>
</div>
)}
</Grid>
<Grid item xs={10} container justifyContent={'center'} alignItems={'center'}>
<Typography>{point.point?.name}</Typography>
</Grid>
<Grid item xs={1}></Grid>
</Grid>
<Button
onClick={() => {
setSelectedCalibrationPoint(point.point);
setSelectedMarker(null);
}}
>
Select For Calibration
</Button>
</Grid>
</Popup>
</Marker>
);
};
const StaticPointMarkers = () => {
return staticReferencePoints.map((point, i) => {
return <SingleMarker key={'marker-' + i} point={point} />;
});
};
const UserPositionMarker = () => <Marker position={[latitude, longitude]} icon={userPosition}></Marker>;
return (
<Grid item xs={12}>
<Snackbar
anchorOrigin={{
vertical: 'top',
horizontal: 'center',
}}
open={snackbarOpen}
onClose={handleSnackbarClose}
autoHideDuration={5000}
message="Calibrate first by selecting a point from the map"
action={
<IconButton size="small" aria-label="close" color="inherit" onClick={handleSnackbarClose}>
<Close fontSize="small" />
</IconButton>
}
/>
<MapContainer
center={center}
zoom={18}
maxZoom={28}
scrollWheelZoom={false}
style={{ height: '65vh' }}
whenCreated={setMap}
>
<TileLayer
url="https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}"
maxZoom={28}
subdomains={['mt0', 'mt1', 'mt2', 'mt3']}
/>
{staticReferencePoints && <StaticPointMarkers />}
{latitude && longitude && <UserPositionMarker />}
</MapContainer>
<Grid id={'info'} item container xs={12} justifyContent={'center'} marginTop={'1rem'}>
<Typography>{`${latitude}, ${longitude}`}</Typography>
</Grid>
<Grid id={'info'} item container xs={12} justifyContent={'center'}>
<InfoIcon onClick={() => setSnackbarOpen(true)} />
</Grid>
</Grid>
);
};
export default StaticReferencePoints;
I have now set current open popup on state and on useEffect open the popup but that creates flickering.
What would be the best way to force popup stay open?
If I understand you question, the problem is that the selected marker popup flickers when the user location changes?
In general the popup should be able to stay open as long as the marker is not created again.
I can see that you have latitude and longitude as dependencies in the useEffect they are not used in the useEffect tough. This will cause the useEffect too trigger on each update on latitude and longitude.
My first suggestion is to remove them from the dependency array.
Change this:
useEffect(() => {
// open popup if it exists
if (selectedMarker) {
markerRef.current[selectedMarker]?.openPopup();
}
}, [selectedMarker, latitude, longitude]);
Secondly a good thing to do is to make sure that the popup is not already open this can be done with
To this:
useEffect(() => {
// open popup if it exists
if (selectedMarker && markerRef.current[selectedMarker]?isPopupOpen()) {
markerRef.current[selectedMarker]?.openPopup();
}
}, [selectedMarker, markerRef]);
As a side note in my experience with react-leaflet, unnecessary rerenders can cause some visual irritation such as flickering. You should strive to reduce the amount of re renders. This can be done using useMemo and useCallback hooks. Genrally passing props that are functions, arrays or object might cause rerenders even if they are the same.
From what I can see your code is deeply nested and it looks like you define component inside other components. Try to break out you code to clear and clean components instead and pass props to them instead, you can still have them all in the same file.
Using a eslint and typescript might also help you to find issues with the code.
Than you #Disco for your answer.
I managed to solve the problem with:
const StaticPointMarkers = (markers) => {
return useMemo(() => markers.map((point, i) => <SingleMarker key={'marker-' + i} point={point} />), [markers])};
I would like to set the state of a checkbox to true in a custom component for Atlassian Jira when a button is clicked. I am using the UI kit with Forge.
So what do I have to write in the line // todo: check Checkbox "V2"?
import ForgeUI, { CustomField, CustomFieldEdit, render, Text, TextField, useProductContext, CheckboxGroup, Checkbox, Select, Option, Button } from "#forge/ui";
const View = () => {
const { extensionContext: { fieldValue } } = useProductContext();
return (
<CustomField>
<Text
content={`Hello ${fieldValue || "world"}!`}
/>
</CustomField>
);
};
const Edit = () => {
const onSubmit = values => {
return values.text
};
const onClick = () => {
// todo: check Checkbox "V2"
};
return (
<CustomFieldEdit onSubmit={onSubmit}>
<CheckboxGroup label="Products" name="products">
<Checkbox value="V1" label="V1" />
<Checkbox value="V2" label="V2" />
<Checkbox value="V3" label="V3" />
</CheckboxGroup>
<Button text="button" onClick={onClick} />
</ CustomFieldEdit>
);
}
export const runView = render(
<View/>
);
export const runEdit = render(<Edit/>)
I'm basically new to React-native and I'm trying to integrate it with MongoDB, apollo-graphql to implement a basic chat app.
I need to update the screen automatically and show the newly created group when I add a new group. Now what happens is, when I create the group, I need to reload the app every time to show the updation made.
GroupScreen.tsx
const MY_GROUPS = gql`
query chatRooms {
chatRooms {
id
name
createdAt
imageUri
}
}
`;
export default function GroupScreen() {
const [groups, setGroups] = useState(null);
const { data, error, loading } = useQuery(MY_GROUPS);
useEffect(() => {
if (error) {
Alert.alert("Something went Wrong! Please reload.");
}
}, [error]);
useEffect(() => {
if (data) {
//console.log(data);
setGroups(data.chatRooms);
}
}, [data]);
return (
<View style={styles.container}>
<FlatList
style={{ width: "100%" }}
data={groups}
renderItem={({ item }) => <GroupListItem chatRoom={item} />}
keyExtractor={(item) => item.id}
/>
<NewGroupButtonItem />
</View>
);
}
NewGroupButtonItem.tsx
const CREATE_CHATROOM = gql`
mutation Mutation(
$createChatRoomName: String!
$createChatRoomImageUri: String
) {
createChatRoom(
name: $createChatRoomName
imageUri: $createChatRoomImageUri
) {
id
name
imageUri
createdAt
users {
id
name
}
}
}
`;
const NewGroupButtonItem = () => {
const [modalVisible, setModalVisible] = useState(false);
const [groupName, setGroupName] = useState("");
const [groupPic, setGroupPic] = useState(null);
const [newGroup, { data, error, loading }] = useMutation(CREATE_CHATROOM);
const onPress = () => {
setGroupName("");
setGroupPic(null);
setModalVisible(!modalVisible);
};
const onPressSave = () => {
newGroup({
variables: {
createChatRoomName: groupName,
createChatRoomImageUri: groupPic,
},
});
setModalVisible(!modalVisible);
};
return (
<View style={styles.container}>
<Modal animationType="fade" transparent={true} visible={modalVisible}>
<TouchableOpacity
style={styles.touchableContainer}
activeOpacity={1}
onPress={() => setModalVisible(!modalVisible)}
>
<View style={styles.mainContainer}>
<View style={styles.innerContainer}>
<Pressable
onPress={() => {
console.warn("Clicked Image!");
}}
>
<Image source={{}} style={styles.avatar} />
</Pressable>
<TextInput
placeholder={"Group Name"}
style={styles.inputBox}
value={groupName}
onChangeText={setGroupName}
/>
<Pressable
onPress={() => {
console.warn("Clicked Emojies!");
}}
>
<Entypo name="emoji-flirt" size={30} color="#37474f" />
</Pressable>
</View>
{!groupName ? (
<Text style={styles.saveButton} onPress={onPress}>
Cancel
</Text>
) : (
<Text style={styles.saveButton} onPress={onPressSave}>
Save
</Text>
)}
</View>
</TouchableOpacity>
</Modal>
<TouchableOpacity onPress={onPress}>
<MaterialIcons name="group-add" size={30} color="white" />
</TouchableOpacity>
</View>
);
};
export default NewGroupButtonItem;
I am trying to add a datepicker for my mobile app in Native script angular. I used book flight example in Playground as reference. My page is getting blured. My date picker is not coming up. I am new to native script and java script. I am including my code. Please let me know where I have gone wrong.
I may be missing something.
component.html
<GridLayout>
<ScrollView>
<GridLayout>
<StackLayout class="form">
-------
----------
<TextField hint="Start Date" [(ngModel)]="leaveDetails.startDate"
(openSelectDate)="onOpenSelectDate($event)"
[selectedDate]="selectedDate"
[isOnOpenStartDate]="isOnOpenStartDate"
class="input input-border" (tap)="onOpenSelectDate(true)">
</TextField>
<TextField hint="End Date" [(ngModel)]="leaveDetails.endDate"
class="input input-border" (tap)="onOpenSelectDate(false)">
</TextField>
--------
---------
</GridLayout>
</ScrollView>
<GridLayout row="0" col="0" rowSpan="4" colSpan="2" opacity="0"
class="overlay" id="overlayGridLayout"></GridLayout>
<GridLayout row="0" col="0" rowSpan="4" colSpan="2" rows="auto, auto,
auto"
columns="*,*" verticalAlignment="center" visibility="hidden"
opacity="0" class="select-date" id="selectDateGridLayout">
<Label row="0" col="0" colSpan="2" text="Select Date" class="title-
select-date"></Label>
<DatePicker row="1" col="0" colSpan="2" [(ngModel)]="dateSelector"
(dateChange)="onDateChanged($event)" verticalAlignment="center">
</DatePicker>
<Button row="2" col="0" text="Cancel" class="btn-next"
(tap)="onCloseSelectDate(true)"></Button>
<Button row="2" col="1" text="OK" class="btn-previous"
(tap)="onCloseSelectDate(false)"></Button>
</GridLayout>
</GridLayout>
compoment.ts
import { Page } from "tns-core-modules/ui/page";
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
import { Visibility } from "tns-core-modules/ui/enums";
export class CreateleavesComponent {
leaveDetails : LeaveDetails;
public selectedDate: Date;
public isOnOpenStartDate: boolean = false;
public dateSelector = new Date();
private _selectDateGridLayout: GridLayout;
private _overlayGridLayout: GridLayout;
constructor(private router: Router, private page: Page) {
this.leaveDetails = new LeaveDetails();
this.leaveDetails.startDate = new Date();
this.leaveDetails.endDate = new Date();
}
ngOnInit(): void {
this._selectDateGridLayout =
this.page.getViewById('selectDateGridLayout');
this._overlayGridLayout = this.page.getViewById('overlayGridLayout');
}
// Select Date
onOpenSelectDate(event) {
this.isOnOpenStartDate = event;
if (this.isOnOpenStartDate) {
this.dateSelector = this.leaveDetails.startDate || new Date();
} else {
this.dateSelector = this.leaveDetails.endDate || new Date();
}
this._selectDateGridLayout.visibility = <any>Visibility.visible;
this._selectDateGridLayout.className = 'select-date';
this._overlayGridLayout.animate({ opacity: 0.5, duration: 300 });
}
onCloseSelectDate(isCancel: boolean) {
if (!isCancel) {
this.selectedDate = this.dateSelector;
if (this.isOnOpenStartDate) {
this.leaveDetails.startDate = this.dateSelector;
} else {
this.leaveDetails.endDate = this.dateSelector;
}
}
this._selectDateGridLayout.className = 'select-date';
this._overlayGridLayout.animate({ opacity: 0, duration: 300 })
.then(() => {
this._selectDateGridLayout.visibility = <any>Visibility.collapse;
})
.catch(() => {
});
}
onDateChanged(args) {
let date: Date = args.value;
this.dateSelector = date;
}
}
I tried to get pointers from other question/answers but I am not able to fix my issue.
I expect the date picker to come up when I click on the start date text field.
But the datepicker is not coming up.I have displayed selectDateGridLayout in onOpenSelectDate function and it is getting changed from hidden to visible.
Looks like you haven't imported the Datepicker in your component. At the top of that component.ts file put:
import { DatePicker } from "tns-core-modules/ui/date-picker";
I have a select menu populated with available companies from my database. When the user clicks one of the companies I would like the to set the state of the selectedCompany to that company object.
This works with my implementation. However, React complains with the following error.
Invalid prop value supplied to TextField
Here's my
<TextField
id="selectedCompany"
select
label="Select a company"
margin="normal"
className={classes.textFieldSelect}
value={props.selectedCompany === null ? "" : props.selectedCompany}
onChange={props.handleInputChange('selectedCompany')}
SelectProps={{
MenuProps: {
className: classes.menu,
},
name: "selectedCompany"
}}
helperText="Example: Company 1"
>
{props.availableCompanies.map((company, index) => (
<MenuItem key={index} value={company}>
{company.name}
</MenuItem>
))}
</TextField>
And the relevant functions in my parent component:
export class Jobs extends Component {
constructor() {
super();
this.state = {
currentJob: {
selectedCompany: null,
}
availableCompanies: [],
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange = name => e => {
e.preventDefault();
const target = e.target;
const value = target.value;
console.log(value);
this.setState({ currentJob: { ...this.state.currentJob, [name]: value } });
};
}