How can I create a discrete slider in react-native (iOS)? - ios

I have a slider component in my react-native app that is nicely restricted to discrete values from 1-5 using the minimum/maximumValue properties and some rounding in onValueChange:
<View>
<Text style={styles.text} >
{this.state.value}
</Text>
<SliderIOS
ref='slider'
style={styles.slider}
value={1}
minimumValue={1}
maximumValue={5}
onValueChange={(value) => {
this.setState({
value: Math.round(value)
});
}}
/>
</View>
What I would like is for the slider handle button to snap to the discrete positions 1,2,3,4,5 rather than move continuously along the slider. Hints appreciated!

For future reference: SliderIOS has been deprecated in the meantime and one should use the Slider component. <Slider> comes with a step attribute:
Step value of the slider. The value should be between 0 and (maximumValue - minimumValue). Default value is 0.
So the solution to the specific question would be to simply set
<Slider
step={1}
...
/>

you're almost there but in the docs of SliderIOS it says:
value number
Initial value of the slider. The value should be between minimumValue
and maximumValue, which default to 0 and 1 respectively. Default value
is 0.
This is not a controlled component, e.g. if you don't update the
value, the component won't be reset to its inital value.
Therefore, it's not possible to control the behavior of the native slider in the way you want it to work.
Solution using another component
However, there is a JavaScript version of the <Slider> component which let's you do it. Since it uses some of the props SliderIOS has, you can easily replace it. Just load the npm module, require it and change <SliderIOS> to <Slider>. Now you need to make some adjustments to your current code:
The property value of the component should reference a variable which can be changed by your code. You can use getInitialState to have a default value.
Add your callback function used for onValueChange to onSlidingComplete. Otherwise you could still have values in between when you release the slider.
I used sliderValue instead of value to make it clearer.
`
getInitialState() {
return {
sliderValue: 1
}
},
onSliderValueChange(value) {
this.setState({
sliderValue: Math.round(value)
});
},
render() {
return(
<View>
<Text style={styles.text} >
{this.state.sliderValue}
</Text>
<Slider
ref='slider'
style={styles.slider}
value={this.state.sliderValue}
minimumValue={1}
maximumValue={5}
onValueChange={this.onSliderValueChange}
onSlidingComplete={this.onSliderValueChange}
/>
</View>
)
}
`
I didn't check my last version the code but it should work like that.

Related

Querying the length of elements in an expression object with filtering?

So in my sapui5 view, the following returns a correct answer of 2:
<Text text="Test text 1: {= ${notif>CatToPhoto/}.length}"/>
This also returns a correct answer of 2:
<Text text="Test text 2: {= ${path: 'notif>CatToPhoto/'}.length}"/>
This, however, totally ignores the filtering and continues to return an answer of 2 when it should now return 1.
<Text text="Test text 3: {= ${path: 'notif>CatToPhoto/', filters: [{path: 'PhotoTypeKey', operator: 'EQ', value1: 2}]}.length}"/>
Does anybody know, please, is there a way to perform a filtering of the odata dataset that will allow me to get a count for elements with a certain value?
So I have found that I can achieve what I need to do through the use of a formatter.
An xml sample looks like this:
<Text text="Test text: {path: 'notif>CatToPhoto/', formatter: '.filterForOverview'}"></Text>
With a formatter function added to a .js file. For simplicity sake here, I've just added it to my Controller.js file, but I will be creating several of these, so I will segragate them out into a formatter.js file:
filterForOverview: function (photos) {
return photos.filter(photo => parseInt(photo.PhotoTypeKey) === 4).length;
},

ReactNative TextInput value doesn't update on IOS

Expo SDK v27.0.0 based on React-Native 0.55
I have a value I want numeric values only so I filter the input using onChangeText. On Android you see the non-numeric value but it is then erased but on IOS all characters are displayed until another digit is pressed. The code is as follows:-
state = {
appCode: ""
};
render() {
console.log(this.state.appCode);
return (
<View style={styles.container}>
<TextInput
label={"App Code"}
placeholder={"App Code"}
keyboardType="phone-pad"
maxLength={6}
onChangeText={text => {
this.setState({ appCode: text.replace(/\D/g, "") });
}}
value={this.state.appCode}
/>
</View>
);
}
I can see on the console that the appCode value is being updated correctly but the value on the IOS screen doesn't follow the variable.
If I enter
1*#+
that is displayed on the IOS screen (the console shows this.state.appCode is 1 for each keypress) but then pressing, for example, 7 and the value displayed on the screen is updated to
17
All the documentation shows this is the correct way to filter the input, and on Android it works but not on IOS
This is a known bug - only fix for now seems to revert to pre-Jan 2018 React Native:
https://github.com/facebook/react-native/issues/18874
(answering as SO won't let me just comment)
A work around can be - before setting the state on onChangeText, first check that the changed text does not contain any non-numeric value and if does then simply do not update the state. In this way, it should work on both iOS and android and also you will not see the non numeric entries in TextInput.

What is the right way to bind 2 angular 2 form controls together

I want to hook up 2 input controls to each other, so when one changes, it updates the other. As an example, its 2 percentage fields, if I set one to 80, the other will get set to 20 to balance it to total 100.
Both inputs are in a form group, so I feel like I should use these and methods on these to subscribe to value changes and not touch native elements or events.
Can anyone suggest the base way to go about it?
You can subscribe to valueChanges for that particular formControlName.
For example in your controller you can do
this.myForm.get('firstControl').valueChanges.subscribe(val => {
this.myForm.patchValue({
secondControl:100-val
});
});
You should repeat the same to listen when the second control changes.
Remember to validate with max values too i.e set maximum to 100.
A simple way would be to use the ngModelChange event emitted by one input field to update the other.
In the code below it updates input #2 when input #1 changes, and vice versa.
Input 1: <input type="text" [(ngModel)]="first" (ngModelChange)="second = 100 - first" />
Input 2: <input type="text" [(ngModel)]=second (ngModelChange)="first = 100 - second"/>
Note: this is pretty basic, all inline, but in your example you'd want to add some error handling for non-numeric characters, range values > 100 etc. So you might want to define the handler for ngModelChange in your components definition (presumably in typescript) rather than in the template like I've done here.
I'm using angular reactive forms and was able to create a component that binds to the form FormGroup and the names of the controls, like this:
<app-percentage-balance
[formGroup]="form"
firstControlName="firstControl"
secondControlName="firstControl">
in my component I have:
#Input() formGroup: FormGroup;
#Input() firstControlName: string;
#Input() secondControlName: string;
public ngOnInit(): void {
this.firstControl = this.formGroup.controls[this.firstControlName] as FormControl;
this.secondControl = this.formGroup.controls[this.secondControlName] as FormControl;
this.firstControl.statusChanges.subscribe((status) => {
if (status == "VALID") {
// do stuff
}
});
this.secondControl.statusChanges.subscribe((status) => {
if (status == "VALID") {
// do stuff
}
});
}

React Native ListView slow to load

I have a simple ListView which seems to take a long time to load its items. I've tested in Release mode, and its taking about 3 seconds to load the whole page. If I set initialListSize={1} I can see it building the list item by item.
The ListView JSX code:
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
renderSeparator={(sectionID, rowID) => <View key={`${sectionID}-${rowID}`} style={styles.separator} />}
style={styles.listView}
initialListSize={1}
/>
And the renderRow method:
renderRow(row) {
// console.log ('rendering scale row: ' + row.numerator + ':' + row.denominator );
return (
<TouchableHighlight onPress={() => this.pressRow(row)} underlayColor="grey">
<View style={styles.rowContainer}>
<Text style={styles.rowText}>{row.hasOwnProperty('label') ? row.label : row.numerator + ':' + row.denominator}</Text>
<Text style={styles.rowText}>{row.hasOwnProperty('label') ? row.numerator + ':' + row.denominator : ''}</Text>
</View>
</TouchableHighlight>
);
}
I'm not doing anything very complicated in renderRow... and the data had already been fetched in a previous view and passed in via props.
Is there something I don't know about that could be affecting load/render time?
This is iOS only and on an iPhone 4S. Only 12-21 rows in my tests.
I should also add that the core of the app is using the JUCE C++ framework and running some audio processing in one of the views. I have an audio processing thread that is only run when that view is visible - all other views (including the one with this ListView) will stop the audio processing thread. I've tried also stopping the audio thread in a similar manner but it did not make any difference.
Not sure if this is going to help you, but I can think of three things you can try...
cmd+T will toggle "slow animations" on/off. This is a long shot
If you are writing to the console.log, comment out those lines. They can surprisingly bog things down considerably sometimes.
Turn off dev mode. You shouldn't need to, but worth a shot
Better start using FlatList or SectionList since ListView is now Deprecated.
https://facebook.github.io/react-native/docs/listview.html
There are few Caveats like you must use a FLUX/ REDUX or RELAY. Please Checkout the details here (Features/Caveats)
https://facebook.github.io/react-native/blog/2017/03/13/better-list-views.html

How to set start time for primefaces clock widget?

Is it possible to set start time for PrimeFaces clock widget?
I know about Analog Clock from PrimeFaces Extensions, but I need digital clock with this option.
I have tried to override javascript method for this clock, but it doesn't work.
PrimeFaces.widget.Clock = PrimeFaces.widget.BaseWidget.extend({
init: function(cfg) {
this._super(cfg);
this.cfg.value = 1430304817141;
this.current = this.isClient() ? new Date() : new Date(this.cfg.value);
var $this = this;
},
isClient: function() {
return this.cfg.mode === 'client';
},
});
The first problem was that you were overriding the widget too late, after PrimeFaces has instantiated its original unmodified widget. According to PrimeFaces Customizable Resource Ordering the right place to override would be in h:head.
The second problem is that you're overriding the widget with a crippled version, that doesn't contain many necessary functions that were present in the original widget.
I wouldn't recommend this approach at all - to basically break the whole PrimeFaces widget like that. What if you'd want to use the normal unchanged clock? Copy-pasted code is harder to maintain too. I advise going the more localized approach: tweak only a single widget instance.
<p:clock id="my_clock" />
<script>
// get widgetVar via EL function, since p:clock doesn't have the widgetVar attribute
var myClockVar = #{p:widgetVar('my_clock')};
myClockVar.current = new Date(1430304817141);
</script>
Just be careful not to update the clock with AJAX requests, or it will to reset to showing client time; and not to update the script, or the clock will reset to the specified time again.

Resources