I'm having an issue with infinite scrolling with the ListView component. This is my list element:
const dataSource = this.state.dataSource.cloneWithRows(this.getDataSource())
<ListView
onEndReached={this.onEndReached.bind(this)}
onEndReachedThreshold={5}
onScroll={this.onScroll.bind(this)}
dataSource={dataSource}
renderRow={this.renderRow.bind(this)}
automaticallyAdjustContentInsets={false} />
And my onEndReached() code:
onEndReached() {
if (this.state.hasScrolled) {
const dataSource = this.state.dataSource.cloneWithRows(this.getDataSource())
this.setState({
offset: this.state.offset + this.state.limit,
dataSource
})
}
}
And getDataSource():
getDataSource() {
let dataSource = []
if (this.state.messages && this.state.messages.length) {
this.state.messages.map((message) => {
dataSource.push(message)
})
}
return dataSource
}
But when I test this code and reach the bottom. It doesn't do anything until my third time triggering onEndReached(), then at that point it sets the offset to a higher than expected number. I tried using a flag such as isLoaded to prevent the onEndReached() from being triggered more than once, but if I do that the list doesn't refresh with the new content.
Thanks in advance!
Related
I'm trying to perform some action on window scroll event but it is not working.
Here is my code
$(window).scroll(function () {
// var limit = 7; //The number of records to display per request
var lastID = $newsfeed_start;
if (($(window).scrollTop() == $(document).height() - $(window).height()&& (lastID != 0)) {
// increment strat value
$newsfeed_start = $newsfeed_start + $newsfeed_limit;
get_timeline_post('');
}
});
even $(window).scroll(function () { } ) function is not working
Your CSS is actually setting the rest of the document to not show overflow therefore the document itself isn't scrolling. The easiest fix for this is bind the event to the thing that is scrolling, which in your case is div#page.
So its easy as changing:
$(document).scroll(function() { // OR $(window).scroll(function() {
didScroll = true;
});
to
$('div#page').scroll(function() {
didScroll = true;
});
I want to manually close the tooltip but there are no documents on the react-native-elements site.
So I look over the tooltip code from github and noticed that it has a toggleTooltip function to toggle. Unfortunately I couldn't make it work.
This is the sample code for the tooltip
import { Tooltip } from 'react-native-elements';
render() {
return (
<Tooltip
ref="tooltip"
popover={
<ComponentTest
toggle={this.refs.tooltip}
>
>
<Text>Click me</Text>
</Tooltip>
);
}
The sample code for the ComponentTest
import { Button } from 'react-native-elements';
toggleOff = () => {
this.props.toggleTooltip;
}
render() {
return (
<Button
title="hide"
type="outline"
onPress={this.toggleOff}
/>
);
}
And this is the function from the tooltip.js that I am trying to use. The full code of the tooltip can found here https://github.com/react-native-training/react-native-elements/blob/master/src/tooltip/Tooltip.js
toggleTooltip = () => {
const { onClose } = this.props;
this.getElementPosition();
this.setState(prevState => {
if (prevState.isVisible && !isIOS) {
onClose && onClose();
}
return { isVisible: !prevState.isVisible };
});
};
i am new to react-native and was trying to use tooltip, what i found out that whenever u click inside the component which is popovered , it navigates to whatever onpress function u have written on that particular component and the tooltip doesn't closes,,it also remain mounted when u navigate to other pages,,one solution to it is that use react-native-popup-menu.its the best that we can use for now as a tooltip https://www.npmjs.com/package/react-native-popup-menu
It may be a stupid solution, but did you tried using this.props.toggleTooltip() ?
OH , and ref is not a string anymore, it's a function
<Tooltip
ref={ref => (this.tooltip = ref)}
popover={
<ComponentTest
toggle={this.tooltip}
>
>
On line 191 of Tooltip.js:
<TouchableOpacity onPress={this.toggleTooltip}>
{this.renderContent(true)}
</TouchableOpacity>
and in the definition of renderContent:112 on line 137, it is rendered your popover:
Thus wherever you touch in your popover will make it disappear. I don't know how to disable this behaviour, but I still want to know if and how the visibility of the popover can be controlled from the Tooltip's child element at least.
Just set its style to display:'none' after you touch your popover.
maybe try this way:
state = { theDisplay: 'flex' };
...
componentDidUpdate(prevProps: any) {
if (!prevProps.isFocused && this.props.isFocused) {
this.setState({ theDisplay: 'flex' });
}
}
...
<Popover.Item
value={'response'}
onSelect={() => {
this.setState({ theDisplay: 'none' });
navigate('NoticeResponse', { id: item.id });
}}>
<Text style={styles.toolsItem}>已读信息</Text>
</Popover.Item>
This is my own way of dealing with it. I hope it will help you.
DISCLAIMER I used the ref example in order to get my code to work, but it's something like this:
const tooltipRef = useRef(null);
const foo = (event, index) => {
event.stopPropagation();
tooltipRef.current.toggleTooltip()
}
...
<Tooltip
height={200}
ref={tooltipRef}
popover={<TouchableOpacity onPress={(event) => foo(event, index)}
/>
I had originally tried to implement this by simply using the tooltipRef.current.toggleTooltip() like in the example but it never ended up working because the event was propagating and continuing to toggle it on its own (effectively toggling it twice).
Without any 3rd party library, simple tooltip for both iOS and android can be implemented as follows:
onPress={() =>
Alert.alert("My Title", "My Msg", [], {
cancelable: true
})
}
React native elements documentation show that we can manually turn off the tooltip.
Docs
Store a reference to the Tooltip in your component by using the ref prop provided by React
const tooltipRef = useRef(null);
...
<Tooltip
ref={tooltipRef}
...
/>
Then you can manually trigger tooltip from anywhere for example when screen loads:
useEffect(() => {
tooltipRef.current.toggleTooltip();
}, []);
I'm working on a website for a school project containing a button which you need to press. When pressed, the button takes a value from the database, child 'aantal' and adds 1. When that is done, it re-uploads it back to the database. One page further, you can see the live number of that child. The problem is, this is not working on iOS 9 or lower and on OSX Yosemite or lower. On android and windows it works fine.
Reusable code;
This is just a button. If you press the button it adds 1 on the int. This is very strange because it doesn't doesn't work on the OS mentioned above.
<script src="https://www.gstatic.com/firebasejs/3.6.9/firebase.js"></script>
<script language="JavaScript">
// Initialize Firebase
var config = {
apiKey: //API KEY,
authDomain: //FIRBASE DOMAIN,
databaseURL: //DATABASE URL,
storageBucket: //STORAGE BUCKET,
messagingSenderId: //MESGSENDID
};
firebase.initializeApp(config);
var number;
var database = firebase.database().ref().child('aantal');
function buy() {
database.on('value', snap => number = snap.val());
var count = parseInt(number, 10) + 1;
database.set(count);
}
</script>
This code will not work, initialise own Firebase project for testing.
For security reasons I removed my details.
Edit
Turns out Safari (9.1/iOS 9.3 and below) doesn't support arrow functions.
Changing database.on('value', snap => number = snap.val()); to database.on('value', function(snap) { number = snap.val()}); fixed the issue.
Well I mean, that code shouldn't work anywhere.
function buy() {
database.on('value', snap => number = snap.val());
var count = parseInt(number, 10) + 1;
database.set(count);
}
Firebase is asynchronous, and you're not waiting for it to actually load number from the database.
This should work.
function buy() {
database.on('value', snap => {
number = snap.val();
var count = parseInt(number, 10) + 1;
database.set(count);
});
}
I don't know whether this is actually the issue you're having or if you just wrote this in your example. Also, when incrementing values you should be using Transactions.
function buy() {
database.transaction(function(value) {
if (value) {
value++;
}
return value;
});
}
I use the Add-on Builder & SDK to develop Firefox add-on. I catch the event when users select a piece of text by the snippet:
var selection = require("sdk/selection");
selection.on('select', function () {
//Doing something
});
However, what I want also is to do other things when users does not select that text anymore, but I can not figure it out how to do it. Anyone can help me with this? Thank you very much.
I am not aware if there are events on Deselection of a text.
However, you could register for Mouse click event on body or div containing that text and then in the callback function of the event, you could check if last selected texts is currently selected or not.
var selection = require("sdk/selection");
var lastText;
function addSelection(){
var selection = false;
var body = document.body;
if(!selection.text){
//deselection
//remove DOM listeners
body.removeListener('click', addSelection);
}
if (!selection.isContiguous) {
for (var subselection in selection) {
if(subselection.text == lastText){
selection = true;
}
}
} else if(selection.text && selection.text == lastText){
selection = true;
}
if(!selection){
//deselected
//remove DOM listeners
}
}
selection.on('select', function () {
var body;
if(lastText !== selection.text){
//deselected
//remove listeners
};
lastText = selection.text;
body = document.body;
//add DOM listeners like click - that can potentially remove selection
body.addEventListener('click', addSelection);
});
I'm trying to write a test script using automation in xcode 4.5.
I have a UICollectionView and I want to click on some cell not currently visible.
Per documentation, I should expect cells to return all cells in the collection view, and visibleCells to return only the currently visible ones.
Instead what I'm seeing is that cells returns only the currently visible cells, and calling visibleCells stops the script on 'undefined' is not a function (evaluating 'collection.visibleCells()')
var target = UIATarget.localTarget();
var collection = target.frontMostApp().mainWindow().collectionViews()[0];
UIALogger.logMessage("Looking in collection: " + collection);
UIALogger.logMessage("Cells: " + collection.cells() + " length " + collection.cells().length);
UIALogger.logMessage("Visible cells: " + collection.visibleCells());
The code above returns the right UICollectionView, second log line prints:
Cells: [object UIAElementArray] length 12
although I have 100 items in the collection view, and third log line crashes script.
Is this a documentation/UIACollectionView bug?
Any ideas how can I tell the automation to scroll until it sees a cell with the name "My cell"?
I've tried using someCell.scrollToVisible, but I need to have the cell to do that, and I don't since I can't get it from cells.
EDIT:
As suggested by Jonathan I've implemented a scroll-till-found function.
it's a bit implementation specific, so you'll probably need to tweak isCellWithName.
I'm also looking to add a break in case we didn't find the needed cell in the while loop, if anyone has ideas, feel free to edit this.
function isCellWithName(cell, name) {
return (cell.staticTexts()[0].name() == name);
}
function getCellWithName(array, name) {
for (var i = 0; i < array.length; i++) {
if (isCellWithName(array[i], name)) {
return array[i];
}
}
return false;
}
function scrollToName(collection, name) {
var found = getCellWithName(collection.cells(), name);
while (found === false) {
collection.dragInsideWithOptions({startOffset:{x:0.2, y:0.99}, endOffset:{x:0.2, y:0},duration:1.0});
found = getCellWithName(collection.cells(), name);
}
return found;
}
The documentation is apparently incorrect. There is no visibleCells() method on UIACollectionView. I figured this out by looping over all the collection view elements properties and printing out their names:
var target = UIATarget.localTarget();
var window = target.frontMostApp().mainWindow();
var collectionView = window.collectionViews()[0];
for (var i in collectionView) {
UIALogger.logMessage(i);
}
Table view elements, on the other hand, do list all the cells with the cells() method. I'm wondering if they choose not to do this because of the much more complicated nature of collection views. It could be very expensive to actually fetch all the collection view cells, build their representations and frames, and return the elements if you had a lot of them. That's what UI Automation does when it asks table views for all the cells. They have to all be instantiated and calculated in order to get the element representations.
But, to answer your larger question, how to scroll to a specific cell. Can you consistently scroll it into view with a swipe gesture? It's not the most convenient way to do it and we're "spoiled" by the ability to scroll to non-visible elements with table views. But from a user behavior testing standpoint, swiping a certain amount is what the user would have to do anyway. Could the test be structured to reflect this and would it address your need?
I couldn't get the the #marmor dragInsideWithOptions() bit to work in a generic fashion. Instead, I'm using the collectionView's value() function to get an index of the current page vs. last page, as in "page 3 of 11". Then I use collectionView's scrollUp() and scrollDown() methods to walk through the pages until we find what we're after. I wrote an extension for TuneUp's uiautomation-ext.js that seem to do the trick, and more:
function animationDelay() {
UIATarget.localTarget().delay(.2);
}
extend(UIACollectionView.prototype, {
/**
* Apple's bug in UIACollectionView.cells() -- only returns *visible* cells
*/
pageCount: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var lastPage = words[3];
return lastPage;
},
currentPage: function() {
var pageStatus = this.value();
var words = pageStatus.split(" ");
var currentPage = words[1];
//var lastPage = words[3];
return currentPage;
},
scrollToTop: function() {
var current = this.currentPage();
while (current != 1) {
this.scrollUp();
animationDelay();
current = this.currentPage();
}
},
scrollToBottom: function() {
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
}
},
cellCount: function() {
this.scrollToTop();
var current = this.currentPage();
var lastPage = this.pageCount();
var cellCount = this.cells().length;
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
cellCount += this.cells().length;
}
return cellCount;
},
currentPageCellNamed: function(name) {
var array = this.cells();
for (var i = 0; i < array.length; i++) {
var cell = array[i];
if (cell.name() == name) {
return cell;
}
}
return false;
},
cellNamed: function(name) {
// for performance, look on the current page first
var foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
if (this.currentPage() != 1) {
// scroll up and check out the first page before we iterate
this.scrollToTop();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
var current = this.currentPage();
var lastPage = this.pageCount();
while (current != lastPage) {
this.scrollDown();
animationDelay();
current = this.currentPage();
foundCell = this.currentPageCellNamed(name);
if (foundCell != false) {
return foundCell;
}
}
return false;
},
/**
* Asserts that this collection view has a cell with the name (accessibility identifier)
* matching the given +name+ argument.
*/
assertCellNamed: function(name) {
assertNotNull(this.cellNamed(name), "No collection cell found named '" + name + "'");
}
});