I have an Array of Strings that I have mapped using the Map funtion and rendered a Text with each item. Now if I click any mapped Text I want to highlight that clicked Text. Moreover, I want to keep on highlighting the next Text after some delay and so on.
How to do it efficiently? So far I have witten the following code and I am able to Highlight the clicked text with the help of an extra style based on the selected page and index clicked. Now I want to have to select the next mapped item automatically after some delay.
function QiratContainer() {
const [selectedIndex, setSelectedIndex] = useState<any>(2)
const [selectedPage, setSelectedPage] = useState<number>(1)
return (
<SafeAreaView >
<FlatList
data={quranData}
showsVerticalScrollIndicator={false}
renderItem={({ item, index }) => (
<View style={styles.pageContainer}>
<PageHeader surahName={item.firstSurahName} juzzNumber={item.juz} />
<View style={{ flex: 1 }}>
{item.ayahs.map((ayah: any, index: any) => (
<>
{ayah.name !== undefined &&
<SurahHeader ayah={ayah} />
}
<Text onPress={() => playAyah(ayah, index)} style={[styles.ayahStyle, selectedIndex === index && selectedPage === ayah?.page && styles.selectedAyah]}>{ayah?.text?.replace("بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ", "")}</Text>
</>
))}
</View>
<PageFooter pageNumber={item.page} />
</View>
)}
/>
</SafeAreaView>
)
function playAyah(ayah: any, index: any) {
console.log(ayah.audio)
//Setting the Selected Index and the specific page of that index to highlight the selected ayah...
console.log(index)
// console.log(ayah.page)
setSelectedIndex(index)
setSelectedAyah(ayah)
}
}
const styles = StyleSheet.create({
ayahStyle: {
fontSize: 24,
fontWeight: 'bold',
marginVertical: 8,
color: 'black'
},
selectedAyah: {
backgroundColor: 'grey'
},
pageContainer: {
width: width,
height: height - 20,
},
})
Following is my JSON Array that is used in the FlatList and Map
[
{
"juz": 1,
"page": 1,
"firstSurahName": "سورة الفاتحة",
"ayahs": [
{
"number": 1,
"name": "سورة الفاتحة",
"englishName": "Al-Faatiha",
"englishNameTranslation": "The Opening",
"revelationType": "Meccan",
"numberInPage": 0,
"ayahsNumber": 7
},
{
"number": 1,
"text": "بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ",
"numberInSurah": 1,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 1,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001001.mp3"
},
{
"number": 2,
"text": "الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ",
"numberInSurah": 2,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 2,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001002.mp3"
},
{
"number": 3,
"text": "الرَّحْمَٰنِ الرَّحِيمِ",
"numberInSurah": 3,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 3,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001003.mp3"
},
{
"number": 4,
"text": "مَالِكِ يَوْمِ الدِّينِ",
"numberInSurah": 4,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 4,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001004.mp3"
},
{
"number": 5,
"text": "إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ",
"numberInSurah": 5,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 5,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001005.mp3"
},
{
"number": 6,
"text": "اهْدِنَا الصِّرَاطَ الْمُسْتَقِيمَ",
"numberInSurah": 6,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 6,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001006.mp3"
},
{
"number": 7,
"text": "صِرَاطَ الَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ الْمَغْضُوبِ عَلَيْهِمْ وَلَا الضَّالِّينَ",
"numberInSurah": 7,
"juz": 1,
"page": 1,
"hizbQuarter": 1,
"ayahsNumber": 7,
"surahNumber": 1,
"numberInPage": 7,
"audio": "https://everyayah.com/data/ahmed_ibn_ali_al_ajamy_128kbps/001007.mp3"
}
],
"number": 1,
"counter": 1
}
]
I always do this stuff by creating a state called "selected" and I save the ID of the selected .map child component in it.
In the .map children components I put classname={selected == id ? "cssSelected" : "cssNotSelected"}
And when I click on a .map child component: onClick={() => setSelected(id)}
Related
I 'm trying to use Searchable Dropdown to show an array of objects:
<SearchableDropdown
style={{height:'100%'}}
onTextChange={(text) => console.log(text)}
onItemSelect={(item) => this.sendrequest(JSON.stringify(item.title))}
containerStyle={{padding: 5}}
textInputStyle={{
padding: 12,
borderWidth: 1,
borderColor: '#ccc',
backgroundColor: '#FAF7F6',
}}
itemStyle={{
padding: 10,
height:50,
marginTop: 2,
backgroundColor: '#FAF9F8',
borderColor: '#bbb',
borderWidth: 1,
}}
itemTextStyle={{
color: '#222',
}}
itemsContainerStyle={{
maxHeight: '60%',
}}
items={this.state.hospitals}
defaultIndex={1}
placeholder="placeholder"
resetValue={false}
underlineColorAndroid="transparent"
/>
Following is my "this.state.hospitals"
"hospitals": [
{
"title": "Holy Family Hospital Rawalpindi",
"distance": "71.45372179866516"
},
{
"title": "Fauji Foundation Hospital Islamabad",
"distance": "62.242918533343705"
},
{
"title": "PIMS Hospital Islamabad",
"distance": "80.0576175928936"
}
I want the titles to be displayed in the dropdown but it shows nothing. Everything else works corectly, but there are just blank fields to scroll through. Any idea what I'm doing wrong?
SearchableDropdown doesn't have any custom prop to handle keyName of dataObject inside array.
you're sending key as title in object but it's access keyName as name. so you need to format your data before sending it as items to that component
let formatHospitalsData = [...this.state.hospitals];
formatHospitalsData = formatHospitalsData.map((item) => {
return {
distance: item.distance,
name: item.title
}
});
after replacing the key, send it to SearchableDropdown Component
[
{
"name": "Holy Family Hospital Rawalpindi",
"distance": "71.45372179866516"
},
{
"name": "Fauji Foundation Hospital Islamabad",
"distance": "62.242918533343705"
},
{
"name": "PIMS Hospital Islamabad",
"distance": "80.0576175928936"
}
]
Im rendering multiple slides and each slide have a list of items.
so I had to render a Flatlist inside Flatlist like this:
<FlatList
ref={(list) => this.ref= list}
data={this.state.buttons} // parent data
keyExtractor={(item) => item.id.toString()}
...
getItemLayout={(data, index)=> (
{
length: wp('100%'),
offset: wp('100%') * index,
index,
borderWidth: 1, borderColor: 'red',
}
)}
showsHorizontalScrollIndicator={false}
renderItem={({item}) => {
let parentData = item;
let myData = this.state.listGifts + '.' + parentData.name;
console.warn('data ', parentData, item);
return (
<View style={{width: wp('100%')}}>
{
this.state.isLoading ?
<ActivityIndicator size='large' style={Styles.styleAI} color={Colors.mainYellow}/>
:
<FlatList
contentContainerStyle={Styles.flatContent}
data={myData}
// keyExtractor={(item) => item.id.toString()}
renderItem={this.renderItem}
removeClippedSubviews={true}
extraData={this.state}
/>
}
</View>
)
}
}
extraData={this.state}
/>
I fetch two JSON :
this.state.buttons >
{
"message": "",
"success": true,
"Category": [
{
"id": 2,
"name": "Peinture"
},
{
"id": 3,
"name": "Cuisine"
},
{
"id": 4,
"name": "Outils"
},
{
"id": 5,
"name": "Electromenager"
}
]
}
this.state.giftsList >
{
"message": "OK",
"success": true,
"Peinture": [
{
"idCadeau": 2,
"Cadeau": "Cadeau1",
"Unites": "100",
},
{
"idCadeau": 3,
"Cadeau": "Cadeau2",
"Unites": "1000",
},
{
"idCadeau": 4,
"Cadeau": "Cadeau3",
"Unites": "50",
}
],
"Cuisine": [
{
"idCadeau": 5,
"Cadeau": "Cadeau4",
"Unites": "200",
},
{
"idCadeau": 6,
"Cadeau": "Cadeau5",
"Unites": "2500",
}
],
"Outils": [
{
"idCadeau": 7,
"Cadeau": "Cadeau6",
"Unites": "100",
}
],
"Electromenager": [
{
"idCadeau": 9,
"Cadeau": "Cadeau7",
"Unites": "500",
}
]
}
for the second Flatlist (the child), I try to get data like this (see code below) :
let myData = this.state.listGifts + '.' + parentData.name;
...
data={myData}
but it doesn't work ! I comment this // keyExtractor={(item) => item.idCadeau.toString()} because it give an error and then it give me an empty list .
**
what I want is set data like this :
**
data={this.state.listGifts.Peinture}
data={this.state.listGifts.Cuisine}
data={this.state.listGifts.Outils}
...
If this.state.listGifts is an object then I believe you mean to do something like this:
let myData = this.state.listGifts[parentData.name];
I'm trying to make a calendar of event using react-native-big-calendar
when i believe it's suppose to work with both start and end time, but somehow it's not work when i uncomment the end property
here are the codes:
const events = [
{
title: 'Meeting',
start: new Date(2020, 5, 20, 10, 0),
// end: new Date(2020, 5, 20, 22, 30),
},
{
title: 'Coffee break',
start: new Date(2020, 1, 14, 15, 45),
// end: new Date(2020, 1, 14, 16, 30),
},
{
title: 'Repair my car',
start: new Date(2020, 5, 20, 7, 45),
// end: new Date(2020, 5, 20, 13, 30),
},
]
class BookingListScreen extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
console.log('logged by phuognn start: ', new Date(2020, 5, 20, 10, 0));
console.log('logged by phuognn end: ',new Date(2020, 5, 20, 22, 30));
return (
<View style={{ flex: 1 }}>
<Calendar
height={Dimensions.get('window').height}
style={styles.calendar}
events={events}
height={600}
eventCellStyle={{ backgroundColor: 'blue' }}
/>
</View>
);
}
}
if I uncomment the end property of events, the calendar show no event.
Wonder why?
The end property is required on the type BaseEvent. So you must specify it!
node_modules\react-native-big-calendar\build\interfaces.d.ts
export interface BaseEvent {
start: Date;
end: Date;
title: string;
}
If what you're looking for is an event which lasts all day, use event's time.
const events = [
{
title: 'Meeting',
start: new Date(2020, 1, 11, 0, 0),
end: new Date(2020, 1, 12, 0, 0),
}
]
I would just like to use a FlatList to list annotation and editedAnnotation, but I can't list both. As shown below, it is listing annotation only.
My state and API:
const [cards, setCards] = useState([]);
useEffect(() => {
async function loadCards() {
const response = await api.get('annotation');
setCards(response.data);
}
loadCards();
}, []);
My list:
<FlatList
data={cards.Annotation}
keyExtractor={call => String(call.id)}
renderItem={({item: call}) => (
<Card {...call}/>
)}
/>
API Return:
{
"Annotation": [
{
"id": 1,
"dateIn": "2019-12-13T18:54:39.0248433+00:00",
"message": "test1",
"statusId": 1,
"symbolId": 5,
"symbol": {
"id": 5,
"status": "start",
}
},
{
"id": 2,
"dateIn": "2019-12-13T14:23:10.6056632+00:00",
"message": "test2",
"statusId": 1,
"symbolId": 2,
"symbol": {
"id": 2,
"status": "end",
}
}
],
"editedAnnotation": [
{
"Annotation": {
"id": 3,
"dateIn": "2019-12-13T19:28:10.6056632+00:00",
"message": "test3",
"statusId": 1,
"symbolId": 2,
"symbol": {
"id": 2,
"status": "start",
}
}
},
"id": 1,
"dateEdit": "2019-12-13T22:27:23.6273816+00:00",
"newMessage": "test3 updated",
"annotationId": 3
}
]
}
You could use spread operator to mix both lists into only one list.
<FlatList
data={[...(cards.Annotation || []), ...(cards.editedAnnotation || [])]}
keyExtractor={call => String(call.id)}
renderItem={({item: call}) => (
<Card {...call}/>
)}
/>
Or you could try using SectionList.
I would like to have three inputs which add data to each data array.
Input looks like this:
<input type="range" min="0" max="10" step="1" v-model="newData">{{ newData }}
<button #click="addData(newData, 'first')">Add</button>
and script
const app = new Vue({
el: '#app',
data: {
newData: 5,
dimensions: [
{
title: 'first',
data: [0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0]
},
{
title: 'second',
data: [1, 3, 8, 1, 2, 3, 3, 3, 5, 1, 9, 2, 4, 6, 0]
},
{
title: 'third',
data: [6, 1, 6, 1, 2, 5, 3, 9, 5, 1, 0, 2, 4, 4, 10]
}]
},
methods: {
addData() {
???
}
}
})
What kind of should my addData method be? I can't push to particular dimension. I just manage to add new one.
I'm glad if anyone can help me :)
Change your addData() method to accept two parameters, the data and the dimension to which to push. Then it should look like the following:
addData(mData, mDimension) {
this.dimensions.forEach((dimension) => {
if (dimension['title'] === mDimension) {
dimension['data'].push(parseInt(mData));
}
});
}
Don't forget to pass the data and dimension in your method call.