Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: undefined is not an object (evaluating 'this._layouts[i].x') #234

Closed
sksin28 opened this issue Aug 18, 2018 · 8 comments
Closed

Comments

@sksin28
Copy link

sksin28 commented Aug 18, 2018

I'm trying to implement search (as the user types in the search box) on the list. However, I'm getting the following error TypeError: undefined is not an object (evaluating 'this._layouts[i].x').

When the search string (value) is empty and the list is updated with all the elements, the error occurs. I also tried different conditions such as returning originalList when value is '', but it throws the same error as the list is updated with all the elements.

This is my code-

constructor(props) {
	super(props);
	let list = [{ name: 'Item1' }, { name: 'Item2' }];

	this._dataProvider = new DataProvider((r1, r2) => {
		return r1.name !== r2.name;
	});

	this.state = {
		list,
		originalList: _.clone(list),
		dataProvider: this._dataProvider.cloneWithRows(list)
	};
}

search(value) {
	this.setState(prevState => {
		return {
			list: _.filter(prevState.originalList, item=> {
				return value == '' || _.includes(item.name, value);
			})
		};
	});
}

render() {
	return (
		<Input
			placeholder="Search"
			autoFocus
			onChangeText={value => {
				this.search(value);
			}}
		/>
		<RecyclerListView
			layoutProvider={this._layoutProvider}
			dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
			rowRenderer={this._rowRenderer.bind(this)}
		/>
	);
}

Any help would be much appreciated.

@naqvitalha
Copy link
Collaborator

Try out the beta version and see if you face the same issue npm install --save recyclerlistview@beta

@sksin28
Copy link
Author

sksin28 commented Aug 19, 2018

I tried the beta version but to no avail. I'm still getting the same error. :(

@sksin28
Copy link
Author

sksin28 commented Aug 19, 2018

Debugging through the code, I found out the function where error occur, though I've not investigated how it can be fixed.

In the layoutManager.js, we have the WrapGridLayoutManager.prototype._locateFirstNeighbourIndex function, where the error is thrown.

    WrapGridLayoutManager.prototype._locateFirstNeighbourIndex = function (startIndex) {
        if (startIndex === 0) {
            return 0;
        }
        var i = startIndex - 1;
        for (; i >= 0; i--) {
            if (this._isHorizontal) {
                if (this._layouts[i].y === 0) {
                    break;
                }
            }
            else if (this._layouts[i].x === 0) {
                break;
            }
        }
        return i;
    };

Considering the case where the original list has 1000 items, the search function modifies the list variable in state and the _locateFirstNeighbourIndex function gets the startIndex value as 1000 and the size of this._layouts is 1000. After filtering (due to search function), let's consider the list size is 800.

When the search string is '', the startIndex is now 1000 but the size of this._layouts is 800. So, either the startIndex or the this._layouts is not updated correctly.

I am not sure how it can be fixed.

@direwolf424
Copy link

@naqvitalha @sksin28 I am facing the same issue , did you find any solution for it?

@naqvitalha
Copy link
Collaborator

Can you share a repro on expo or, git so that I can quickly check this?

sksin28 added a commit to sksin28/recyclerlist-repro that referenced this issue Sep 26, 2018
@sksin28
Copy link
Author

sksin28 commented Sep 26, 2018

@naqvitalha
You can find the repro here- https://github.com/sksin28/recyclerlist-repro
Or in expo- https://snack.expo.io/rk_j9yYtQ

The issue is when you type '1' in search box, 'Item 1' appears in list. However, when you clear search box, instead of returning both 'Item 1' and 'Item 2', it throws an error.

It would be great to find the root cause of the issue. Thanks.

@sksin28
Copy link
Author

sksin28 commented Sep 27, 2018

The issue has been resolved. The dataprovider was not passed correctly which I believe resulted in dataprovider and list not being in sync.

So that no one else faces this issue, this is what my earlier code looked like-

import * as React from "react";
import { Text, View, TextInput } from "react-native";

import _ from "lodash";

import {
  DataProvider,
  LayoutProvider,
  RecyclerListView
} from "recyclerlistview";

export default class App extends React.Component {
  constructor(props) {
    super(props);

    let list = [{ name: "Item 1" }, { name: "Item 2" }];

    this._dataProvider = new DataProvider((r1, r2) => {
      return r1.name !== r2.name;
    });

    this._layoutProvider = new LayoutProvider(
      index => {
        return 1;
      },
      (type, dim) => {
        dim.width = 400;
        dim.height = 120;
      }
    );

    this.state = {
      list,
      originalList: _.clone(list),
      dataProvider: this._dataProvider.cloneWithRows(list)
    };
  }

  search(value) {
    this.setState(prevState => {
      return {
        list: _.filter(prevState.originalList, item => {
          return value == "" || _.includes(item.name, value);
        })
      };
    });
  }

  _rowRenderer(type, item) {
    return (
      <View>
        <Text>{item.name}</Text>
      </View>
    );
  }

  render() {
    return (
      <View style={{ marginTop: 50, width: 400, height: 400 }}>
        <TextInput
          style={{ width: "100%" }}
          placeholder="Search"
          placeholderTextColor="red"
          onChangeText={value => {
            this.search(value);
          }}
        />
        <RecyclerListView
          layoutProvider={this._layoutProvider}
          dataProvider={this.state.dataProvider.cloneWithRows(this.state.list)}
          rowRenderer={this._rowRenderer.bind(this)}
        />
      </View>
    );
  }
}

After changing the dataprovider property, the code looks like-

import * as React from "react";
import { Text, View, TextInput } from "react-native";

import _ from "lodash";

import {
  DataProvider,
  LayoutProvider,
  RecyclerListView
} from "recyclerlistview";

export default class App extends React.Component {
  constructor(props) {
    super(props);

    let list = [{ name: "Item 1" }, { name: "Item 2" }];

    this._dataProvider = new DataProvider((r1, r2) => {
      return r1.name !== r2.name;
    });

    this._layoutProvider = new LayoutProvider(
      index => {
        return 1;
      },
      (type, dim) => {
        dim.width = 400;
        dim.height = 120;
      }
    );

    this.state = {
      list,
      originalList: _.clone(list)
    };
  }

  search(value) {
    this.setState(prevState => {
      return {
        list: _.filter(prevState.originalList, item => {
          return value == "" || _.includes(item.name, value);
        })
      };
    });
  }

  _rowRenderer(type, item) {
    return (
      <View>
        <Text>{item.name}</Text>
      </View>
    );
  }

  render() {
    return (
      <View style={{ marginTop: 50, width: 400, height: 400 }}>
        <TextInput
          style={{ width: "100%" }}
          placeholder="Search"
          placeholderTextColor="red"
          onChangeText={value => {
            this.search(value);
          }}
        />
        <RecyclerListView
          layoutProvider={this._layoutProvider}
          dataProvider={this._dataProvider.cloneWithRows(this.state.list)}
          rowRenderer={this._rowRenderer.bind(this)}
        />
      </View>
    );
  }
}

@naqvitalha Thanks anyways.

@sksin28 sksin28 closed this as completed Sep 27, 2018
@keshavhub
Copy link

Hey @sksin28
Thanks for pointing out this issue but even after making the change you recommended, still the issue exists. I got a workaround(hack) for this but still didn't find a good solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants