├── .gitignore ├── src ├── img │ └── arrow_icons.png ├── js │ ├── directives │ │ └── ngReactGridDirective.js │ ├── main.js │ ├── factories │ │ ├── ngReactGridCheckboxFieldFactory.js │ │ ├── ngReactGridTextFieldFactory.js │ │ ├── ngReactGridSelectFieldFactory.js │ │ └── ngReactGridCheckboxFactory.js │ ├── vendors │ │ └── miniUnderscore.js │ └── classes │ │ ├── NgReactGridEditManager.js │ │ ├── NgReactGridReactManager.js │ │ └── ngReactGrid.js ├── jsx │ ├── reactGridTextField.jsx │ ├── reactGridCheckboxField.jsx │ ├── reactGridSelectField.jsx │ ├── reactGridCheckbox.jsx │ └── reactGrid.jsx └── css │ └── ngReactGrid.css ├── bower.json ├── package.json ├── LICENSE ├── gulpfile.js ├── README.md └── examples ├── basic.html └── dataSet.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .DS_Store -------------------------------------------------------------------------------- /src/img/arrow_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josebalius/ngReactGrid/HEAD/src/img/arrow_icons.png -------------------------------------------------------------------------------- /src/js/directives/ngReactGridDirective.js: -------------------------------------------------------------------------------- 1 | var ngReactGrid = require("../classes/NgReactGrid"); 2 | 3 | var ngReactGridDirective = function ($rootScope) { 4 | return { 5 | restrict: "E", 6 | scope : { 7 | grid : "=" 8 | }, 9 | link: function (scope, element, attrs) { 10 | new ngReactGrid(scope, element, attrs, $rootScope); 11 | } 12 | } 13 | }; 14 | 15 | module.exports = ngReactGridDirective; 16 | 17 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngReactGrid", 3 | "version": "0.7.0", 4 | "description": "A really fast Angular grid using the power of React to render", 5 | "homepage": "https://github.com/josebalius/ngReactGrid", 6 | "authors": [ 7 | "Jose Garcia - jose.balius@gmail.com" 8 | ], 9 | "main": [ 10 | "build/js/ngReactGrid.min.js", 11 | "build/css/ngReactGrid.css", 12 | "build/img/arrow_icons.png" 13 | ], 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngReactGrid", 3 | "version": "0.7.0", 4 | "description": "A really fast Angular grid using the power of React to render", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "gulp": "gulp" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/josebalius/ngReactGrid.git" 12 | }, 13 | "author": "Jose Garcia - jose.balius@gmail.com", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/josebalius/ngReactGrid/issues" 17 | }, 18 | "homepage": "http://josebalius.github.io/ngReactGrid/", 19 | "devDependencies": { 20 | "gulp": "^3.6.2", 21 | "gulp-react": "2.0.0", 22 | "gulp-concat": "2.2.0", 23 | "gulp-filter": "0.4.1", 24 | "gulp-uglify": "0.3.0", 25 | "gulp-rename": "1.2.0", 26 | "gulp-replace": "0.3.0", 27 | "gulp-browserify": "0.5.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/js/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ngReactGridDirective = require('./directives/ngReactGridDirective'); 4 | var ngReactGridCheckboxFactory = require('./factories/ngReactGridCheckboxFactory'); 5 | var ngReactGridTextFieldFactory = require("./factories/ngReactGridTextFieldFactory"); 6 | var ngReactGridCheckboxFieldFactory = require("./factories/ngReactGridCheckboxFieldFactory"); 7 | var ngReactGridSelectFieldFactory = require("./factories/ngReactGridSelectFieldFactory"); 8 | 9 | angular.module('ngReactGrid', []) 10 | .factory("ngReactGridCheckbox", ['$rootScope', ngReactGridCheckboxFactory]) 11 | .factory("ngReactGridTextField", ['$rootScope', ngReactGridTextFieldFactory]) 12 | .factory("ngReactGridCheckboxField", [ngReactGridCheckboxFieldFactory]) 13 | .factory("ngReactGridSelectField", ['$rootScope', ngReactGridSelectFieldFactory]) 14 | .directive("ngReactGrid", ['$rootScope', ngReactGridDirective]); 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jose Garcia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/js/factories/ngReactGridCheckboxFieldFactory.js: -------------------------------------------------------------------------------- 1 | var NgReactGridReactManager = require("../classes/NgReactGridReactManager"); 2 | 3 | var ngReactGridCheckboxFieldFactory = function() { 4 | 5 | var ngReactGridCheckboxField = function(record, field, updateNotification) { 6 | this.record = record; 7 | this.field = field; 8 | this.updateNotification = updateNotification; 9 | 10 | var value = NgReactGridReactManager.getObjectPropertyByString(this.record, this.field); 11 | var ngReactGridCheckboxFieldElement = React.createFactory(NgReactGridCheckboxFieldComponent); 12 | return ngReactGridCheckboxFieldElement({value: value, updateValue: this.updateValue.bind(this)}); 13 | }; 14 | 15 | ngReactGridCheckboxField.prototype.updateValue = function(newValue) { 16 | NgReactGridReactManager.updateObjectPropertyByString(this.record, this.field, newValue); 17 | 18 | if(this.updateNotification) { 19 | this.updateNotification(this.record); 20 | } 21 | }; 22 | 23 | return ngReactGridCheckboxField; 24 | 25 | }; 26 | 27 | module.exports = ngReactGridCheckboxFieldFactory; -------------------------------------------------------------------------------- /src/jsx/reactGridTextField.jsx: -------------------------------------------------------------------------------- 1 | var NgReactGridTextFieldComponent = (function() { 2 | var NgReactGridTextFieldComponent = React.createClass({ 3 | getInitialState: function() { 4 | return { 5 | defaultValue: "" 6 | }; 7 | }, 8 | handleChange: function() { 9 | var value = this.refs.textField.getDOMNode().value; 10 | this.props.updateValue(value); 11 | this.setState({ 12 | defaultValue: value 13 | }); 14 | }, 15 | componentWillReceiveProps: function(nextProps) { 16 | this.setState({ 17 | defaultValue: nextProps.value 18 | }); 19 | }, 20 | componentWillMount: function() { 21 | this.setState({ 22 | defaultValue: this.props.value 23 | }); 24 | }, 25 | render: function() { 26 | return ( 27 | 28 | ) 29 | } 30 | }); 31 | 32 | return NgReactGridTextFieldComponent; 33 | })(); -------------------------------------------------------------------------------- /src/jsx/reactGridCheckboxField.jsx: -------------------------------------------------------------------------------- 1 | var NgReactGridCheckboxFieldComponent = (function() { 2 | var NgReactGridCheckboxFieldComponent = React.createClass({ 3 | getInitialState: function() { 4 | return { 5 | checked: false 6 | } 7 | }, 8 | handleClick: function() { 9 | var newState = { 10 | checked: (this.state.checked) ? false : true 11 | }; 12 | 13 | this.setState(newState); 14 | 15 | this.props.updateValue(newState.checked); 16 | }, 17 | componentWillReceiveProps: function(nextProps) { 18 | this.setState({ 19 | checked: (nextProps.value) ? true : false 20 | }); 21 | }, 22 | componentWillMount: function() { 23 | this.setState({ 24 | checked: (this.props.value === true) ? true : false 25 | }); 26 | }, 27 | render: function() { 28 | return ( 29 | 30 | ) 31 | } 32 | }); 33 | 34 | return NgReactGridCheckboxFieldComponent; 35 | })(); -------------------------------------------------------------------------------- /src/js/vendors/miniUnderscore.js: -------------------------------------------------------------------------------- 1 | var _ = { 2 | nativeForEach: Array.prototype.forEach, 3 | each: function (obj, iterator, context) { 4 | if (obj == null) return obj; 5 | if (this.nativeForEach && obj.forEach === this.nativeForEach) { 6 | obj.forEach(iterator, context); 7 | } else if (obj.length === +obj.length) { 8 | for (var i = 0, length = obj.length; i < length; i++) { 9 | if (iterator.call(context, obj[i], i, obj) === breaker) return; 10 | } 11 | } else { 12 | var keys = _.keys(obj); 13 | for (var i = 0, length = keys.length; i < length; i++) { 14 | if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; 15 | } 16 | } 17 | return obj; 18 | }, 19 | slice: Array.prototype.slice, 20 | extend: function (obj) { 21 | this.each(this.slice.call(arguments, 1), function (source) { 22 | if (source) { 23 | for (var prop in source) { 24 | obj[prop] = source[prop]; 25 | } 26 | } 27 | }); 28 | return obj; 29 | } 30 | }; 31 | 32 | module.exports = _; 33 | -------------------------------------------------------------------------------- /src/js/factories/ngReactGridTextFieldFactory.js: -------------------------------------------------------------------------------- 1 | var NgReactGridReactManager = require("../classes/NgReactGridReactManager"); 2 | 3 | var ngReactGridTextFieldFactory = function($rootScope) { 4 | 5 | var ngReactGridTextField = function(record, field, updateNotification) { 6 | this.record = record; 7 | this.field = field; 8 | this.updateNotification = updateNotification; 9 | 10 | var value = NgReactGridReactManager.getObjectPropertyByString(this.record, this.field); 11 | 12 | var ngReactGridTextFieldElement = React.createFactory(NgReactGridTextFieldComponent); 13 | return ngReactGridTextFieldElement({value: value, updateValue: this.updateValue.bind(this)}); 14 | }; 15 | 16 | ngReactGridTextField.prototype.updateValue = function(newValue) { 17 | NgReactGridReactManager.updateObjectPropertyByString(this.record, this.field, newValue); 18 | 19 | if(this.updateNotification) { 20 | if($rootScope.$$phase) { 21 | this.updateNotification(this.record); 22 | } else { 23 | $rootScope.$apply(function () { 24 | this.updateNotification(this.record); 25 | }.bind(this)); 26 | } 27 | } 28 | }; 29 | 30 | return ngReactGridTextField; 31 | 32 | }; 33 | 34 | module.exports = ngReactGridTextFieldFactory; 35 | -------------------------------------------------------------------------------- /src/jsx/reactGridSelectField.jsx: -------------------------------------------------------------------------------- 1 | var NgReactGridSelectFieldComponent = (function() { 2 | 3 | var NgReactGridSelectFieldComponent = React.createClass({ 4 | getInitialState: function() { 5 | return { 6 | defaultValue: { 7 | id: "", 8 | name: "" 9 | } 10 | }; 11 | }, 12 | handleChange: function(e) { 13 | var value = e.target.value; 14 | this.props.updateValue(value); 15 | this.setState({ 16 | defaultValue: { 17 | id: value 18 | } 19 | }); 20 | }, 21 | componentWillReceiveProps: function(nextProps) { 22 | this.setState({ 23 | defaultValue: nextProps.value || {} 24 | }); 25 | }, 26 | componentWillMount: function() { 27 | this.setState({ 28 | defaultValue: this.props.value || {} 29 | }); 30 | }, 31 | render: function() { 32 | 33 | if(!this.props.referenceData) { 34 | this.props.referenceData = []; 35 | } 36 | 37 | var options = this.props.referenceData.map(function(option) { 38 | return ( 39 | 40 | ) 41 | }); 42 | 43 | return ( 44 | 47 | ) 48 | } 49 | }); 50 | 51 | return NgReactGridSelectFieldComponent; 52 | 53 | })(); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var react = require('gulp-react'); 3 | var concat = require('gulp-concat'); 4 | var gulpFilter = require('gulp-filter'); 5 | var uglify = require('gulp-uglify'); 6 | var rename = require('gulp-rename'); 7 | var replace = require('gulp-replace'); 8 | var browserify = require('gulp-browserify'); 9 | var packageJSON = require('./package.json'); 10 | 11 | gulp.task('css', function () { 12 | return gulp.src('./src/css/**.css') 13 | .pipe(concat('ngReactGrid.css')) 14 | .pipe(gulp.dest('./build/css')); 15 | }); 16 | 17 | gulp.task('img', function () { 18 | return gulp.src('./src/img/**.png') 19 | .pipe(gulp.dest('./build/img')); 20 | }); 21 | 22 | gulp.task('build-grid', function () { 23 | var jsxFilter = gulpFilter('**/*.jsx'); 24 | var jsFilter = gulpFilter("**/*.js"); 25 | return gulp.src(['./src/js/main.js', './src/jsx/**.jsx']) 26 | .pipe(jsFilter) 27 | .pipe(browserify()) 28 | .pipe(jsFilter.restore()) 29 | .pipe(jsxFilter) 30 | .pipe(react()) 31 | .pipe(jsxFilter.restore()) 32 | .pipe(concat('ngReactGrid.js')) 33 | .pipe(replace(/{\$version}/g, packageJSON.version)) 34 | .pipe(gulp.dest('./build/js/')) 35 | }); 36 | 37 | gulp.task('uglify-build', ['build-grid'], function () { 38 | return gulp.src(['./build/js/ngReactGrid.js']) 39 | .pipe(uglify({ 40 | preserveComments: 'some' 41 | })) 42 | .pipe(rename('ngReactGrid.min.js')) 43 | .pipe(gulp.dest('./build/js')) 44 | }); 45 | 46 | gulp.task('build', ['build-grid', 'uglify-build', 'css', 'img']); 47 | 48 | gulp.task('default', ['build'], function () { 49 | gulp.watch('./src/**', ['build']); 50 | }); 51 | -------------------------------------------------------------------------------- /src/js/factories/ngReactGridSelectFieldFactory.js: -------------------------------------------------------------------------------- 1 | var NgReactGridReactManager = require("../classes/NgReactGridReactManager"); 2 | 3 | var ngReactGridSelectFieldFactory = function($rootScope) { 4 | 5 | var ngReactGridSelectField = function(record, field, referenceData, updateNotification) { 6 | this.record = record; 7 | this.field = field; 8 | this.updateNotification = updateNotification; 9 | this.referenceData = referenceData; 10 | 11 | var value = NgReactGridReactManager.getObjectPropertyByString(this.record, this.field); 12 | 13 | var ngReactGridSelectFieldElement = React.createFactory(NgReactGridSelectFieldComponent); 14 | 15 | return ngReactGridSelectFieldElement({value: value, updateValue: this.updateValue.bind(this), referenceData: (referenceData || [])}); 16 | }; 17 | 18 | ngReactGridSelectField.prototype.updateValue = function(newValue) { 19 | 20 | var updateValue = {}; 21 | 22 | for(var i in this.referenceData) { 23 | var option = this.referenceData[i]; 24 | 25 | if(option.id == newValue) { 26 | updateValue = option; 27 | } 28 | } 29 | 30 | NgReactGridReactManager.updateObjectPropertyByString(this.record, this.field, updateValue); 31 | 32 | if(this.updateNotification) { 33 | if($rootScope.$$phase) { 34 | this.updateNotification(this.record); 35 | } else { 36 | $rootScope.$apply(function () { 37 | this.updateNotification(this.record); 38 | }.bind(this)); 39 | } 40 | } 41 | }; 42 | 43 | return ngReactGridSelectField; 44 | 45 | }; 46 | 47 | module.exports = ngReactGridSelectFieldFactory; -------------------------------------------------------------------------------- /src/js/classes/NgReactGridEditManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class manages the editing/saving/reverting functionality to ngReactGrid 3 | * @param ngReactGrid 4 | * @constructor 5 | */ 6 | var NgReactGridEditManager = function(ngReactGrid) { 7 | this.ngReactGrid = ngReactGrid; 8 | this.dataCopy = []; 9 | }; 10 | 11 | /** 12 | * This function is used to add the edit/save/cancel API to the grid object created by the user. 13 | * @param gridObject 14 | */ 15 | NgReactGridEditManager.prototype.mixinAPI = function(gridObject) { 16 | var self = this; 17 | 18 | /** 19 | * This is the function that puts the grid into edit mode 20 | */ 21 | gridObject.edit = function() { 22 | return self.edit.call(self); 23 | }; 24 | 25 | /** 26 | * This is the function that will persist the modified data to the original model 27 | */ 28 | gridObject.save = function() { 29 | return self.save.call(self); 30 | }; 31 | 32 | /** 33 | * This function is called whenever the modifications need to be reverted 34 | */ 35 | gridObject.cancel = function() { 36 | return self.cancel.call(self); 37 | }; 38 | 39 | /** 40 | * This function is called whenever the modifications need to be reverted 41 | */ 42 | gridObject.getEditedData = function() { 43 | return self.getEditedData.call(self); 44 | }; 45 | 46 | }; 47 | 48 | /** 49 | * This is the function that puts the grid into edit mode 50 | */ 51 | NgReactGridEditManager.prototype.getEditedData = function() { 52 | return this.ngReactGrid.react.originalData; 53 | }; 54 | 55 | /** 56 | * This is the function that puts the grid into edit mode 57 | */ 58 | NgReactGridEditManager.prototype.edit = function() { 59 | this.ngReactGrid.editing = true; 60 | this.dataCopy = this.copyData(this.ngReactGrid.react.originalData); 61 | this.ngReactGrid.render(); 62 | }; 63 | 64 | /** 65 | * This is the function that will persist the modified data to the original model 66 | */ 67 | NgReactGridEditManager.prototype.save = function() { 68 | this.ngReactGrid.editing = false; 69 | 70 | this.ngReactGrid.update(this.ngReactGrid.events.DATA, { 71 | data: this.ngReactGrid.react.originalData 72 | }); 73 | 74 | return this.ngReactGrid.react.originalData; 75 | }; 76 | 77 | /** 78 | * This function is called whenever the modifications need to be reverted 79 | */ 80 | NgReactGridEditManager.prototype.cancel = function() { 81 | this.ngReactGrid.editing = false; 82 | 83 | this.ngReactGrid.update(this.ngReactGrid.events.DATA, { 84 | data: this.dataCopy 85 | }); 86 | }; 87 | 88 | NgReactGridEditManager.prototype.copyData = function(data) { 89 | return JSON.parse(JSON.stringify(data)); 90 | }; 91 | 92 | module.exports = NgReactGridEditManager; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ngReactGrid 2 | =========== 3 | 4 | NOTE: Active development of this project has stopped. All new development is being done on the https://github.com/josebalius/react-grid project which will contain most of ngReactGrid's functionality with adapters for Angular 1.x, 2.x and KnockoutJS. 5 | 6 | 7 | ngReactGrid is an Angular directive that can be used to render an enhanced HTML table or grid of data very fast using React as the rendering engine. 8 | 9 | The API of the grid is similar to that of ng-grid's, and the table architecture (3 tables per grid) is similar to that of jQuery DataTables. 10 | 11 | Please refer to: http://josebalius.github.io/ngReactGrid/ for documentation. 12 | 13 | Bower 14 | ----- 15 | 16 | ``` 17 | bower install ngReactGrid 18 | ``` 19 | 20 | Features 21 | -------- 22 | * Fast, awesome performance 23 | * Fixed headers 24 | * Server side hooks 25 | * Sorting 26 | * Pagination 27 | * Page size 28 | * Search 29 | * Horizontal scrolling 30 | * Custom width / height 31 | * Custom cell rendering 32 | * Checkbox selection column 33 | 34 | Todo 35 | ---- 36 | * Editable cells - In Progress 37 | * Resizeable columns - In Progress 38 | * Column Filtering - In Progress 39 | * Column pinning 40 | * Don't see your feature? I am accepting pull requests. Please contribute. 41 | 42 | Develop 43 | ------- 44 | 45 | ```bash 46 | # Clone this repo (or your fork). 47 | git clone https://github.com/josebalius/ngReactGrid.git 48 | cd ngReactGrid 49 | 50 | # Install all the the dev dependencies 51 | npm install 52 | 53 | # Run gulp inside the ngReactGrid to watch your files and build 54 | npm run gulp 55 | ``` 56 | 57 | I use examples/basic.html to implement features, it is my "sandbox" environment. This file however is always changing (with whatever it is that I am working on) so beware. I suggest you copy this file and set it up your way. I will be creating more examples when I have some time. 58 | 59 | Please remember that there is also a documentation site: http://josebalius.github.io/ngReactGrid/ 60 | 61 | Good luck! 62 | 63 | License 64 | ---------- 65 | The MIT License (MIT) 66 | 67 | Copyright (c) 2014 Jose Garcia 68 | 69 | Permission is hereby granted, free of charge, to any person obtaining a copy 70 | of this software and associated documentation files (the "Software"), to deal 71 | in the Software without restriction, including without limitation the rights 72 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 73 | copies of the Software, and to permit persons to whom the Software is 74 | furnished to do so, subject to the following conditions: 75 | 76 | The above copyright notice and this permission notice shall be included in all 77 | copies or substantial portions of the Software. 78 | 79 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 80 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 81 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 82 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 83 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 84 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 85 | SOFTWARE. 86 | 87 | [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/c9197bf5c6addea6996a8a242645fe48 "githalytics.com")](http://githalytics.com/josebalius/ngReactGrid) 88 | -------------------------------------------------------------------------------- /src/jsx/reactGridCheckbox.jsx: -------------------------------------------------------------------------------- 1 | var NgReactGridCheckboxComponent = (function() { 2 | var NgReactGridCheckboxComponent = React.createClass({ 3 | getInitialState: function() { 4 | var disableCheckboxField = this.props.options.disableCheckboxField; 5 | var disableCheckboxFieldValue = this.props.utils.getObjectPropertyByStringFn(this.props.row, disableCheckboxField); 6 | return { 7 | checked: false, 8 | disabled: disableCheckboxFieldValue ? disableCheckboxFieldValue : false 9 | } 10 | }, 11 | 12 | handleClick: function(e) { 13 | var checkedStateValue = this.state.checked ? false : true; 14 | this.setState({ 15 | checked: checkedStateValue 16 | }); 17 | this.props.handleToggle(e, checkedStateValue); 18 | }, 19 | setNgReactGridCheckboxStateFromEvent: function(e) { 20 | if (!this.state.disabled) { 21 | // Target rows with specified field value 22 | if (e.detail.targetCheckboxes.key) { 23 | var checkedStateValue = this.state.checked; 24 | var fieldValue = 25 | this.props.utils.getObjectPropertyByStringFn( 26 | this.props.row, 27 | e.detail.targetCheckboxes.key 28 | ); 29 | if (fieldValue && fieldValue === e.detail.targetCheckboxes.value) { 30 | checkedStateValue = e.detail.checked; 31 | } 32 | this.setState({ 33 | checked: checkedStateValue 34 | }); 35 | this.props.handleToggle(e, checkedStateValue); 36 | } else { // Target all rows 37 | this.setState({ 38 | checked: e.detail.checked 39 | }); 40 | this.props.handleToggle(e, e.detail.checked); 41 | } 42 | } 43 | }, 44 | componentWillReceiveProps: function(nextProps) { 45 | var disableCheckboxField = nextProps.options.disableCheckboxField; 46 | var disableCheckboxFieldValue = nextProps.utils.getObjectPropertyByStringFn(nextProps.row, disableCheckboxField); 47 | this.setState({ 48 | checked: (nextProps.selectionTarget.indexOf(nextProps.row) === -1) ? false : true, 49 | disabled: disableCheckboxFieldValue ? disableCheckboxFieldValue : false 50 | }); 51 | }, 52 | componentDidMount: function() { 53 | window.addEventListener("setNgReactGridCheckboxStateFromEvent", this.setNgReactGridCheckboxStateFromEvent); 54 | }, 55 | componentWillUnmount: function() { 56 | window.removeEventListener("setNgReactGridCheckboxStateFromEvent", this.setNgReactGridCheckboxStateFromEvent); 57 | }, 58 | render: function() { 59 | var hideDisabledCheckboxField = this.props.options.hideDisabledCheckboxField; 60 | 61 | if (this.state.disabled && hideDisabledCheckboxField) { 62 | return ( 63 |
64 | ) 65 | } else { 66 | return ( 67 |
68 | 69 |
70 | ) 71 | } 72 | } 73 | }); 74 | 75 | return NgReactGridCheckboxComponent; 76 | })(); 77 | -------------------------------------------------------------------------------- /src/js/factories/ngReactGridCheckboxFactory.js: -------------------------------------------------------------------------------- 1 | var _ = require('../vendors/miniUnderscore'); 2 | var NgReactGridReactManager = require("../classes/NgReactGridReactManager"); 3 | 4 | var ngReactGridCheckboxFactory = function($rootScope) { 5 | var ngReactGridCheckbox = function(selectionTarget, options) { 6 | var defaultOptions = { 7 | disableCheckboxField: '', 8 | hideDisabledCheckboxField: false, 9 | batchToggle: false, 10 | headerStyle: { 11 | textAlign: "center" 12 | } 13 | }; 14 | var _options = _.extend({}, defaultOptions, options); 15 | var utils = { 16 | getObjectPropertyByStringFn: NgReactGridReactManager.getObjectPropertyByString, 17 | }; 18 | 19 | return { 20 | field: "", 21 | fieldName: "", 22 | displayName: "", 23 | title: "Select/Deselect All", 24 | options: _options, 25 | utils: utils, 26 | setAllCheckboxStates: this.setAllCheckboxStates, 27 | setHeaderCheckboxState: this.setHeaderCheckboxState, 28 | setVisibleCheckboxState: this.setVisibleCheckboxState, 29 | inputType: (_options.batchToggle) ? "checkbox" : undefined, 30 | handleHeaderClick: function(checkedValue, data) { 31 | this.setVisibleCheckboxState(checkedValue); 32 | 33 | // Empties bounded selected target or populates with 34 | // non-disabled checkbox rows data 35 | $rootScope.$apply(function() { 36 | while (selectionTarget.length) {selectionTarget.pop();} 37 | if (checkedValue) { 38 | data.forEach(function(row) { 39 | if (!utils.getObjectPropertyByStringFn(row, _options.disableCheckboxField)) { 40 | selectionTarget.push(row); 41 | } 42 | }); 43 | } 44 | }); 45 | }, 46 | render: function(row) { 47 | var handleToggle = (function(e, checkedValue) { 48 | e.stopPropagation(); 49 | 50 | // Sends event to uncheck header 'batch toggle' checkbox 51 | this.setHeaderCheckboxState(false); 52 | 53 | var index = selectionTarget.indexOf(row); 54 | if(index === -1) { 55 | if (checkedValue) {selectionTarget.push(row);} 56 | } else { 57 | if (!checkedValue) {selectionTarget.splice(index, 1);} 58 | } 59 | }).bind(this); 60 | var ngReactGridCheckboxElement = React.createFactory(NgReactGridCheckboxComponent); 61 | return ngReactGridCheckboxElement({selectionTarget: selectionTarget, handleToggle: handleToggle, row: row, utils: this.utils, options: this.options});; 62 | }, 63 | sort: false, 64 | width: 1 65 | } 66 | }; 67 | 68 | ngReactGridCheckbox.prototype.setHeaderCheckboxState = function(checkedValue) { 69 | window.dispatchEvent(new CustomEvent("setNgReactGridCheckboxHeaderStateFromEvent", {detail: {checked: checkedValue}})); 70 | }; 71 | 72 | ngReactGridCheckbox.prototype.setVisibleCheckboxState = function(checkedValue, options) { 73 | var defaultOptions = { 74 | checked: checkedValue, 75 | targetCheckboxes: { 76 | key: null, 77 | value: null 78 | } 79 | }; 80 | var _options = _.extend({}, defaultOptions, options); 81 | window.dispatchEvent(new CustomEvent("setNgReactGridCheckboxStateFromEvent", {detail: _options})); 82 | }; 83 | 84 | return ngReactGridCheckbox; 85 | }; 86 | 87 | module.exports = ngReactGridCheckboxFactory; 88 | -------------------------------------------------------------------------------- /examples/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ngReactGrid Basic Example 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 |
15 | Selections: {{selections}}
16 | Clicked On Record: {{clickedOnRecord}} 17 |
18 | 19 | 21 | 22 | 23 | 24 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/css/ngReactGrid.css: -------------------------------------------------------------------------------- 1 | .ngReactGrid { 2 | font-size: 12px; 3 | font-family: "Open Sans", "Helvetica Neue", "Helvetica", "Arial", "Droid Arabic Kufi","Droid Sans"; 4 | padding: 5px; 5 | } 6 | 7 | .ngReactGrid table { 8 | position: relative; 9 | table-layout: fixed; 10 | background-color: #FFF; 11 | margin: 0; 12 | padding: 0; 13 | color: #555555; 14 | display: table; 15 | border: 1px solid #CCC; 16 | border-spacing: 0; 17 | width: 100%; 18 | } 19 | 20 | .ngReactGrid .ngReactGridViewPort { 21 | overflow-y: scroll; 22 | overflow-x: scroll; 23 | } 24 | 25 | .ngReactGrid .ngReactGridHeader { 26 | overflow-x: hidden; 27 | position: relative; 28 | overflow-y: hidden; 29 | } 30 | 31 | .ngReactGrid .ngGridHeaderCellText { 32 | display:inline-block; 33 | width: 90%; 34 | float: left; 35 | -webkit-touch-callout: none; 36 | -webkit-user-select: none; 37 | -khtml-user-select: none; 38 | -moz-user-select: none; 39 | -ms-user-select: none; 40 | user-select: none; 41 | } 42 | 43 | .ngReactGrid .ngGridHeaderCellResize { 44 | width: 5%; 45 | float: left; 46 | text-align: right; 47 | } 48 | 49 | .ngReactGrid .ngReactGridHeaderToolbarWrapper { 50 | overflow: auto; 51 | } 52 | 53 | .ngReactGrid .ngReactGridShowPerPage { 54 | float: left; 55 | width: 50%; 56 | } 57 | 58 | .ngReactGrid .ngReactGridSearch { 59 | float: left; 60 | width: 50%; 61 | text-align: right; 62 | } 63 | 64 | .ngReactGrid .ngReactGridSearch input { 65 | width: 50%; 66 | border-radius: 15px; 67 | border: 1px solid #CCC; 68 | padding: 5px; 69 | padding-left: 9px; 70 | outline: none; 71 | } 72 | 73 | .ngReactGrid .ngReactGridHeaderWrapper { 74 | margin-top: 5px; 75 | } 76 | 77 | .ngReactGrid .ngReactGridHeaderInner { 78 | overflow-x: hidden; 79 | overflow-y: hidden; 80 | } 81 | 82 | .ngReactGrid .ngReactGridHeaderInner table { 83 | line-height: 15px; 84 | } 85 | 86 | .ngReactGrid .ngReactGridHeaderInner table thead { 87 | font-style: normal; 88 | } 89 | 90 | .ngReactGrid .ngReactGridBody table { 91 | border-top: none; 92 | border-bottom: none; 93 | } 94 | 95 | .ngReactGrid table tr { 96 | border-collapse: collapse; 97 | -webkit-box-sizing: border-box; 98 | -moz-box-sizing: border-box; 99 | -ms-box-sizing: border-box; 100 | box-sizing: border-box; 101 | -webkit-transition: all .1s ease-out; 102 | -moz-transition: all .1s ease-out; 103 | transition: all .1s ease-out; 104 | } 105 | 106 | .ngReactGrid table td, .ngReactGrid table th { 107 | border-left: 1px solid #CCC; 108 | vertical-align: top; 109 | } 110 | 111 | .ngReactGrid table th { 112 | cursor: auto; 113 | text-align: left; 114 | color: rgba(0,0,0,.8); 115 | padding: 0px; 116 | padding: 5px; 117 | display: table-cell; 118 | } 119 | 120 | .ngReactGrid table th div { 121 | white-space: nowrap; 122 | overflow: hidden; 123 | text-overflow: ellipsis; 124 | } 125 | 126 | .ngReactGrid table td { 127 | padding: 0px; 128 | vertical-align: middle; 129 | text-align: left; 130 | padding: 5px; 131 | display: table-cell; 132 | word-wrap: break-word; 133 | } 134 | 135 | .ngReactGrid table tr:nth-child(odd) td { 136 | background: #f5f5f5; 137 | } 138 | 139 | .ngReactGrid table tr:last-child td { 140 | border-bottom: 1px solid #CCC; 141 | } 142 | 143 | .ngReactGrid table tr td:first-child, .ngReactGrid table tr th:first-child { 144 | border-left: none; 145 | } 146 | 147 | .ngReactGrid .ngReactGridFooter, .ngReactGrid table th, .ngReactGrid h1, .ngReactGrid .ngReactGridHeaderWrapper { 148 | background: #ffffff; /* Old browsers */ 149 | background: -moz-linear-gradient(top, #ffffff 0%, #eeeeee 100%, #7db9e8 100%); /* FF3.6+ */ 150 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#eeeeee), color-stop(100%,#7db9e8)); /* Chrome,Safari4+ */ 151 | background: -webkit-linear-gradient(top, #ffffff 0%,#eeeeee 100%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */ 152 | background: -o-linear-gradient(top, #ffffff 0%,#eeeeee 100%,#7db9e8 100%); /* Opera 11.10+ */ 153 | background: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 100%,#7db9e8 100%); /* IE10+ */ 154 | background: linear-gradient(to bottom, #ffffff 0%,#eeeeee 100%,#7db9e8 100%); /* W3C */ 155 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#7db9e8',GradientType=0 ); /* IE6-9 */ 156 | } 157 | 158 | .ngReactGrid .ngReactGridFooter { 159 | border: 1px solid #CCC; 160 | padding: 5px; 161 | font-size: 11px; 162 | overflow: auto; 163 | } 164 | 165 | .icon-arrows { 166 | display: inline-block; 167 | margin-top: 1px; 168 | line-height: 14px; 169 | vertical-align: text-top; 170 | background-image: url("../img/glyphicons-halflings.png"); 171 | background-repeat: no-repeat; 172 | background-image: url('../img/arrow_icons.png'); 173 | background-repeat: no-repeat; 174 | width: 7px; 175 | height: 10px; 176 | } 177 | 178 | .icon-both { 179 | background-position: -128px 2px; 180 | } 181 | 182 | .icon-asc { 183 | background-position: 0 0; 184 | } 185 | 186 | .icon-desc { 187 | background-position: -65px 0; 188 | } 189 | 190 | .ngReactGrid .ngReactGridStatus { 191 | float: left; 192 | width: 50%; 193 | padding-top: 4px; 194 | } 195 | 196 | .ngReactGrid .ngReactGridPagination { 197 | float: left; 198 | width: 50%; 199 | } 200 | 201 | .ngReactGridPagination ul { 202 | display: inline-block; 203 | padding-left: 0; 204 | margin: 0; 205 | border-radius: 4px; 206 | float: right; 207 | } 208 | 209 | .ngReactGridPagination ul li { 210 | display: inline; 211 | } 212 | 213 | .ngReactGridPagination ul li:hover a { 214 | background: #EEE; 215 | } 216 | 217 | .ngReactGridPagination ul li.active a { 218 | background: #428bca; 219 | color: #FFF; 220 | } 221 | 222 | .ngReactGridPagination ul li a { 223 | position: relative; 224 | float: left; 225 | padding: 3px 9px; 226 | line-height: 1.42857143; 227 | text-decoration: none; 228 | color: #428bca; 229 | background-color: #fff; 230 | border: 1px solid #ddd; 231 | margin-left: -1px; 232 | font-size:11px; 233 | } 234 | 235 | .ngReactTextField { 236 | margin:0; 237 | width: calc(90% - 4px); 238 | outline: none; 239 | padding: 4px; 240 | } 241 | 242 | .ngReactGridSelectField { 243 | width: calc(100% - 4px); 244 | } 245 | -------------------------------------------------------------------------------- /src/js/classes/NgReactGridReactManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This class is the bridge between the ngReactGrid class and React 3 | * @param ngReactGrid 4 | * @constructor 5 | */ 6 | var NgReactGridReactManager = function (ngReactGrid) { 7 | /** 8 | * Reference to the ngReactGrid main class 9 | */ 10 | this.ngReactGrid = ngReactGrid; 11 | 12 | /** 13 | * How many records we are currently showing with filters, search, pageSize and pagination applied 14 | * @type {number} 15 | */ 16 | this.showingRecords = 0; 17 | 18 | /** 19 | * The starting index by which we are filtering the local data 20 | * @type {number} 21 | */ 22 | this.startIndex = 0; 23 | 24 | /** 25 | * The end index by which we are filtering local data 26 | * @type {number} 27 | */ 28 | this.endIndex = 0; 29 | 30 | /** 31 | * This is a copy of the data given to ngReactGrid (local data only) 32 | * @type {Array} 33 | */ 34 | this.originalData = []; 35 | 36 | /** 37 | * This is a copy of the data given to ngReactGrid whenever it is filtered (local data only) 38 | * @type {Array} 39 | */ 40 | this.filteredData = []; 41 | 42 | /** 43 | * Values of all filter fields 44 | * @type {Object} 45 | */ 46 | this.filterValues = {}; 47 | 48 | /** 49 | * This is a copy of the pagination-independent viewable data in table that 50 | * can be affected by filter and sort 51 | * @type {Array} 52 | */ 53 | this.filteredAndSortedData = []; 54 | 55 | /** 56 | * Loading indicator 57 | * @type {boolean} 58 | */ 59 | this.loading = false; 60 | 61 | /** 62 | * Instance pointer to a static function 63 | * @type {Function} 64 | */ 65 | this.getObjectPropertyByString = NgReactGridReactManager.getObjectPropertyByString; 66 | }; 67 | 68 | /** 69 | * This function is used to add API to the grid object created by the user. 70 | * @param gridObject 71 | */ 72 | NgReactGridReactManager.prototype.mixinAPI = function(gridObject) { 73 | var self = this; 74 | 75 | /** 76 | * Get filtered and sorted data 77 | */ 78 | gridObject.getFilteredAndSortedData = function() { 79 | return self.getFilteredAndSortedData.call(self); 80 | }; 81 | }; 82 | 83 | /** 84 | * Get table data wrapper 85 | */ 86 | NgReactGridReactManager.prototype.getFilteredAndSortedData = function() { 87 | return this.filteredAndSortedData; 88 | }; 89 | 90 | /** 91 | * Page size setter, this is called for the NgReactGridComponent (React class) 92 | * @param pageSize 93 | */ 94 | NgReactGridReactManager.prototype.setPageSize = function (pageSize) { 95 | 96 | var update = { 97 | pageSize: pageSize, 98 | currentPage: 1 99 | }; 100 | 101 | /* 102 | * Is there a search in place 103 | */ 104 | if (this.ngReactGrid.isSearching()) { 105 | update.data = this.filteredData; 106 | } 107 | 108 | /** 109 | * Send the update event to the main class 110 | */ 111 | this.ngReactGrid.update(this.ngReactGrid.events.PAGESIZE, update); 112 | 113 | /** 114 | * If we are in server mode, call getData 115 | */ 116 | if (this.ngReactGrid.isServerMode()) { 117 | this.ngReactGrid.getData(); 118 | } 119 | }; 120 | 121 | /** 122 | * Sorting callback, this is called from the NgReactGridComponent whenever a header cell is clicked (and is sortable) 123 | * @param field 124 | */ 125 | NgReactGridReactManager.prototype.setSortField = function (field) { 126 | 127 | /** 128 | * The initial update to the grid 129 | * @type {{sortInfo: {field: string, dir: string}}} 130 | */ 131 | var update = { 132 | sortInfo: { 133 | field: field, 134 | dir: "" 135 | } 136 | }; 137 | 138 | /** 139 | * Are we sorting on a new field 140 | */ 141 | if (this.ngReactGrid.sortInfo.field !== field) { 142 | update.sortInfo.dir = "asc"; 143 | } else { 144 | /** 145 | * Switch the sorting direction 146 | */ 147 | if (this.ngReactGrid.sortInfo.dir === "asc") { 148 | update.sortInfo.dir = "desc"; 149 | } else { 150 | update.sortInfo.dir = "asc"; 151 | } 152 | 153 | } 154 | 155 | /** 156 | * Call getData for Server Mode or perform a local sort 157 | */ 158 | if (this.ngReactGrid.isServerMode()) { 159 | this.ngReactGrid.update(this.ngReactGrid.events.SORTING, update); 160 | this.ngReactGrid.getData(); 161 | } else { 162 | this.performLocalSort(update); 163 | } 164 | }; 165 | 166 | /** 167 | * Simple asc -> desc, desc -> asc sorting, used for local data, resets the current page to 1 168 | * @param update 169 | */ 170 | NgReactGridReactManager.prototype.performLocalSort = function (update) { 171 | var copy; 172 | 173 | if (this.ngReactGrid.isSearching()) { 174 | copy = this.filteredData; 175 | } else { 176 | copy = this.originalData.slice(0); 177 | } 178 | 179 | var isAsc = update.sortInfo.dir === "asc"; 180 | 181 | copy.sort(function (a, b) { 182 | var aField = this.getObjectPropertyByString(a, update.sortInfo.field); 183 | var bField = this.getObjectPropertyByString(b, update.sortInfo.field); 184 | 185 | if (isAsc) { 186 | return aField <= bField ? -1 : 1; 187 | } else { 188 | return aField >= bField ? -1 : 1; 189 | } 190 | }.bind(this)); 191 | 192 | update.data = copy; 193 | update.currentPage = 1; 194 | 195 | this.ngReactGrid.update(this.ngReactGrid.events.SORTING, update); 196 | }; 197 | 198 | /** 199 | * This is a recursive search function that will transverse an object searching for an index of a string 200 | * @param obj 201 | * @param search 202 | * @param (Optional) column 203 | * @returns {boolean} 204 | */ 205 | NgReactGridReactManager.prototype.deepSearch = function(obj, search, column) { 206 | var found = false; 207 | 208 | if (obj) { 209 | for (var i in obj) { 210 | if (obj.hasOwnProperty(i)) { 211 | 212 | var prop = obj[i]; 213 | 214 | if (typeof prop === "object") { 215 | found = this.deepSearch(prop, search, column); 216 | if (found === true) break; 217 | } else { 218 | if (column && column !== '_global') { 219 | if (i !== column.split('.').pop()) continue; 220 | } 221 | if (String(obj[i]).toLowerCase().indexOf(search.toLowerCase()) !== -1) { 222 | found = true; 223 | break; 224 | } 225 | } 226 | 227 | 228 | } 229 | } 230 | } 231 | 232 | return found; 233 | }; 234 | 235 | /** 236 | * Search callback for everytime the user updates the search box. 237 | * Supports local mode and server mode; local mode only for column search. 238 | * @param search 239 | * @param (Optional) column 240 | */ 241 | NgReactGridReactManager.prototype.setSearch = function (search, column) { 242 | var column = column ? column : '_global'; 243 | this.filterValues[column] = search; 244 | 245 | var update = { 246 | search: search 247 | }; 248 | 249 | if (this.ngReactGrid.isLocalMode()) { 250 | this.filteredData = this.originalData.slice(0); 251 | for (var column in this.filterValues) { 252 | if (this.filterValues.hasOwnProperty(column)) { 253 | this.filteredData = this.filteredData.filter(function (obj) { 254 | var found = false; 255 | found = this.deepSearch(obj, this.filterValues[column], column); 256 | return found; 257 | }.bind(this)); 258 | } 259 | } 260 | 261 | update.data = this.filteredData; 262 | update.currentPage = 1; 263 | 264 | this.ngReactGrid.update(this.ngReactGrid.events.SEARCH, update); 265 | } else { 266 | this.ngReactGrid.search = search; 267 | this.ngReactGrid.getData(); 268 | } 269 | }; 270 | 271 | /** 272 | * Pagination call back, called every time a pagination change is made 273 | * @param page 274 | */ 275 | NgReactGridReactManager.prototype.goToPage = function (page) { 276 | 277 | var update = { 278 | currentPage: page 279 | }; 280 | 281 | this.ngReactGrid.update(this.ngReactGrid.events.PAGINATION, update); 282 | 283 | if (this.ngReactGrid.isServerMode()) { 284 | this.ngReactGrid.getData(); 285 | } 286 | }; 287 | 288 | /** 289 | * Row click callback 290 | * @param row 291 | */ 292 | NgReactGridReactManager.prototype.rowClick = function(row) { 293 | this.ngReactGrid.rowClick(row); 294 | }; 295 | 296 | /** 297 | * This function is called from React to make sure that any callbacks being passed into react cell components, update the 298 | * angular scope 299 | * @param cell 300 | * @returns {*} 301 | */ 302 | NgReactGridReactManager.prototype.wrapFunctionsInAngular = function (cell) { 303 | for (var key in cell.props) { 304 | if (cell.props.hasOwnProperty(key)) { 305 | if (key === "children" && cell.props[key]) { 306 | this.wrapFunctionsInAngular(cell.props[key]); 307 | } else if (typeof cell.props[key] === 'function') { 308 | cell.props[key] = this.wrapWithRootScope(cell.props[key]); 309 | } 310 | } 311 | 312 | } 313 | return cell; 314 | }; 315 | 316 | /** 317 | * This is the wrapping function on all callbacks passed into the React cell components for ngReactGrid 318 | * @param func 319 | * @returns {Function} 320 | */ 321 | NgReactGridReactManager.prototype.wrapWithRootScope = function (func) { 322 | var self = this; 323 | return function () { 324 | var args = arguments; 325 | var phase = self.ngReactGrid.rootScope.$$phase; 326 | 327 | if (phase == '$apply' || phase == '$digest') { 328 | func.apply(null, args); 329 | } else { 330 | self.ngReactGrid.rootScope.$apply(function () { 331 | func.apply(null, args); 332 | }); 333 | } 334 | }; 335 | }; 336 | 337 | /** 338 | * This function allows you to get a property from any object, no matter how many levels deep it is 339 | * MOVE THIS FUNCTION INTO ITS OWN CLASS 340 | * @param object 341 | * @param str 342 | * @static 343 | * @returns {*} 344 | */ 345 | NgReactGridReactManager.getObjectPropertyByString = function (object, str) { 346 | 347 | /** 348 | * Convert indexes to properties 349 | */ 350 | str = str.replace(/\[(\w+)\]/g, '.$1'); 351 | 352 | /** 353 | * Strip a leading dot 354 | */ 355 | str = str.replace(/^\./, ''); 356 | var a = str.split('.'); 357 | while (a.length) { 358 | var n = a.shift(); 359 | if (object != null && n in object) { 360 | object = object[n]; 361 | } else { 362 | return; 363 | } 364 | } 365 | return object; 366 | }; 367 | 368 | /** 369 | * Updates an object property given a specified path, it will create the object if it doesn't exist 370 | * @static 371 | * @param obj 372 | * @param path 373 | * @param value 374 | */ 375 | NgReactGridReactManager.updateObjectPropertyByString = function(obj, path, value) { 376 | var a = path.split('.'); 377 | var o = obj; 378 | for (var i = 0; i < a.length - 1; i++) { 379 | var n = a[i]; 380 | if (n in o) { 381 | o = o[n]; 382 | } else { 383 | o[n] = {}; 384 | o = o[n]; 385 | } 386 | } 387 | o[a[a.length - 1]] = value; 388 | }; 389 | 390 | module.exports = NgReactGridReactManager; 391 | -------------------------------------------------------------------------------- /src/js/classes/ngReactGrid.js: -------------------------------------------------------------------------------- 1 | var _ = require('../vendors/miniUnderscore'); 2 | var NgReactGridReactManager = require("./NgReactGridReactManager"); 3 | var NgReactGridEditManager = require("./NgReactGridEditManager"); 4 | var NO_GET_DATA_CALLBACK_ERROR = "localMode is false, please implement the getData function on the grid object"; 5 | 6 | /** 7 | * NgReactGrid - Main class 8 | * @param scope 9 | * @param element 10 | * @param attrs 11 | * @param $rootScope 12 | * @constructor 13 | */ 14 | var NgReactGrid = function (scope, element, attrs, $rootScope) { 15 | this.columnDefs = scope.grid.columnDefs || []; 16 | this.data = []; 17 | this.height = 400; 18 | this.localMode = true; 19 | this.editing = false; 20 | this.singleLineCell = false; 21 | this.totalCount = 0; 22 | this.totalPages = 0; 23 | this.currentPage = 1; 24 | this.rowClick = function() {}; 25 | this.pageSize = 25; 26 | this.pageSizes = [25, 50, 100, 500]; 27 | this.sortInfo = {field: "", dir: ""}; 28 | this.showGridSearch = true; 29 | this.showGridShowPerPage = true; 30 | this.search = ""; 31 | this.horizontalScroll = false; 32 | this.scrollbarWidth = this.getScrollbarWidth(); 33 | this.scope = scope; 34 | this.element = element; 35 | this.attrs = attrs; 36 | this.rootScope = $rootScope; 37 | 38 | /** 39 | * Initialize the NgReactGridReact class 40 | */ 41 | this.react = new NgReactGridReactManager(this); 42 | this.editManager = new NgReactGridEditManager(this); 43 | 44 | /** 45 | * Initialize events 46 | */ 47 | this.setupUpdateEvents(); 48 | 49 | /** 50 | * Initialize scope watchers 51 | */ 52 | this.initWatchers(); 53 | 54 | /** 55 | * Init the grid 56 | */ 57 | this.init(); 58 | }; 59 | 60 | /** 61 | * Init function for NgReactGrid, decides whether to getData or render with local data 62 | */ 63 | NgReactGrid.prototype.init = function () { 64 | 65 | /** 66 | * Check if getData is set, override with our own and keep a private copy 67 | */ 68 | if (typeof this.scope.grid.localMode && this.scope.grid.localMode === false) { 69 | if (this.scope.grid.getData) { 70 | this._getData = this.scope.grid.getData; 71 | delete this.scope.grid.getData; 72 | } else { 73 | throw new Error(NO_GET_DATA_CALLBACK_ERROR); 74 | } 75 | } 76 | 77 | _.extend(this, this.scope.grid); 78 | 79 | /** 80 | * Provide API interfaces 81 | */ 82 | this.react.mixinAPI(this.scope.grid); 83 | this.editManager.mixinAPI(this.scope.grid); 84 | 85 | /** 86 | * If we are in server mode, perform the first call to load the data, and add refresh API 87 | */ 88 | if (this.isServerMode()) { 89 | this.getData(); 90 | this.addRefreshAPI(); 91 | } else { 92 | this.updateData({ 93 | data: this.data 94 | }); 95 | } 96 | 97 | this.render(); 98 | 99 | }; 100 | 101 | /** 102 | * Get data wrapper, at the moment it doesn't do much but expect some hooks and functionality being added in the future 103 | */ 104 | NgReactGrid.prototype.getData = function () { 105 | this.react.loading = true; 106 | this._getData(this); 107 | this.render(); 108 | }; 109 | 110 | /** 111 | * This function mixes in the "refresh" API method that can be used in server mode grids. 112 | */ 113 | NgReactGrid.prototype.addRefreshAPI = function () { 114 | var self = this; 115 | 116 | this.scope.grid.refresh = function () { 117 | self.getData.call(self); 118 | }; 119 | }; 120 | 121 | /** 122 | * This is called once during initialization to figure out the width of the scrollbars 123 | * @returns {number} 124 | */ 125 | NgReactGrid.prototype.getScrollbarWidth = function () { 126 | var outer = document.createElement("div"); 127 | outer.style.visibility = "hidden"; 128 | outer.style.width = "100px"; 129 | 130 | /** 131 | * Needed for WinJS apps 132 | * @type {string} 133 | */ 134 | outer.style.msOverflowStyle = "scrollbar"; 135 | 136 | document.body.appendChild(outer); 137 | 138 | var widthNoScroll = outer.offsetWidth; 139 | 140 | /* 141 | * Force scroll bars 142 | */ 143 | outer.style.overflow = "scroll"; 144 | 145 | /* 146 | * Add innerDiv 147 | */ 148 | var inner = document.createElement("div"); 149 | inner.style.width = "100%"; 150 | outer.appendChild(inner); 151 | 152 | var widthWithScroll = inner.offsetWidth; 153 | 154 | /** 155 | * Remove divs 156 | */ 157 | outer.parentNode.removeChild(outer); 158 | 159 | return widthNoScroll - widthWithScroll; 160 | }; 161 | 162 | /** 163 | * Returns whether there is an active search on the grid 164 | * @returns {string|boolean} 165 | */ 166 | NgReactGrid.prototype.isSearching = function () { 167 | return this.search && this.search.length > 0; 168 | }; 169 | 170 | /** 171 | * Returns whether the grid is in local mode 172 | * @returns {boolean|*} 173 | */ 174 | NgReactGrid.prototype.isLocalMode = function () { 175 | return this.localMode; 176 | }; 177 | 178 | /** 179 | * Returns whether the grid is in server mode 180 | * @returns {boolean} 181 | */ 182 | NgReactGrid.prototype.isServerMode = function () { 183 | return !this.localMode; 184 | }; 185 | 186 | /** 187 | * Manages the different events that can update the grid 188 | */ 189 | NgReactGrid.prototype.setupUpdateEvents = function () { 190 | this.events = { 191 | COLUMN_DEF: "COLUMN_DEF", 192 | PAGESIZE: "PAGESIZE", 193 | SORTING: "SORTING", 194 | SEARCH: "SEARCH", 195 | PAGINATION: "PAGINATION", 196 | DATA: "DATA", 197 | TOTALCOUNT: "TOTALCOUNT", 198 | COLUMNS: "COLUMNS" 199 | }; 200 | }; 201 | 202 | /** 203 | * Initializes the scope watchers needed for the grid 204 | */ 205 | NgReactGrid.prototype.initWatchers = function () { 206 | this.scope.$watchCollection("grid.data", function (newValue, oldValue) { 207 | if (newValue !== oldValue) { 208 | if (this.isServerMode() && this.react.loading) { 209 | this.react.loading = false; 210 | } 211 | 212 | this.update(this.events.DATA, { 213 | data: newValue 214 | }); 215 | } 216 | }.bind(this)); 217 | 218 | this.scope.$watchCollection("grid.columnDefs", function (newValue, oldValue) { 219 | if (newValue !== oldValue) { 220 | this.update(this.events.COLUMN_DEF, { 221 | // Resets column filter fields 222 | filterValues: {} 223 | }); 224 | this.update(this.events.COLUMNS, {columnDefs: newValue}); 225 | } 226 | }.bind(this), true); 227 | 228 | this.scope.$watch("grid.totalCount", function (newValue) { 229 | if (newValue) { 230 | this.update(this.events.TOTALCOUNT, {totalCount: newValue}); 231 | } 232 | }.bind(this)); 233 | }; 234 | 235 | /** 236 | * Updates the grid model, re-renders the react component 237 | * @param updateEvent 238 | * @param updates 239 | */ 240 | NgReactGrid.prototype.update = function (updateEvent, updates) { 241 | switch (updateEvent) { 242 | case this.events.COLUMN_DEF: 243 | this.updateColumnDef(updates); 244 | break; 245 | 246 | case this.events.DATA: 247 | this.updateData(updates); 248 | break; 249 | 250 | case this.events.PAGESIZE: 251 | this.updatePageSize(updates); 252 | break; 253 | 254 | case this.events.PAGINATION: 255 | this.updatePagination(updates); 256 | break; 257 | 258 | case this.events.SEARCH: 259 | this.updateSearch(updates); 260 | break; 261 | 262 | case this.events.SORTING: 263 | this.updateSorting(updates); 264 | break; 265 | 266 | case this.events.TOTALCOUNT: 267 | this.updateTotalCount(updates); 268 | break; 269 | 270 | case this.events.COLUMNS: 271 | this.updateColumns(updates); 272 | break; 273 | } 274 | 275 | this.render(); 276 | 277 | }; 278 | 279 | /** 280 | * This function updates the necessary properties for a successful column def update 281 | * @param updates 282 | */ 283 | NgReactGrid.prototype.updateColumnDef = function (updates) { 284 | this.react.filterValues = updates.filterValues; 285 | }; 286 | 287 | /** 288 | * This function takes care of updating all data related properties. The second param will not the update the originalData 289 | * property in the react manager 290 | * @param updates 291 | * @param updateContainsData 292 | */ 293 | NgReactGrid.prototype.updateData = function (updates, updateContainsData) { 294 | 295 | this.react.startIndex = (this.currentPage - 1) * this.pageSize; 296 | this.react.endIndex = (this.pageSize * this.currentPage); 297 | 298 | if (this.isLocalMode()) { 299 | if (updateContainsData) { 300 | 301 | this.data = updates.data.slice(this.react.startIndex, this.react.endIndex); 302 | this.react.filteredAndSortedData = updates.data.slice(0); 303 | this.totalCount = updates.data.length; 304 | 305 | } else { 306 | this.react.originalData = updates.data.slice(0); 307 | this.totalCount = this.react.originalData.length; 308 | this.data = this.react.originalData.slice(this.react.startIndex, this.react.endIndex); 309 | this.react.filteredAndSortedData = this.react.originalData.slice(0); 310 | } 311 | 312 | } else { 313 | this.data = updates.data; 314 | this.react.filteredAndSortedData = this.data.slice(0); 315 | } 316 | 317 | this.react.showingRecords = this.data.length; 318 | 319 | this.totalPages = Math.ceil(this.totalCount / this.pageSize); 320 | }; 321 | 322 | /** 323 | * This function updates the necessary properties for a successful page size update 324 | * @param updates 325 | */ 326 | NgReactGrid.prototype.updatePageSize = function (updates) { 327 | this.pageSize = updates.pageSize; 328 | this.currentPage = updates.currentPage; 329 | this.updateData({ 330 | data: this.react.filteredAndSortedData ? this.react.filteredAndSortedData : this.react.originalData 331 | }, true); 332 | }; 333 | 334 | /** 335 | * This function updates the necessary properties for a successful pagination update 336 | * @param updates 337 | */ 338 | NgReactGrid.prototype.updatePagination = function (updates) { 339 | this.currentPage = updates.currentPage; 340 | this.updateData({ 341 | data: this.react.filteredAndSortedData ? this.react.filteredAndSortedData : this.react.originalData 342 | }, true); 343 | }; 344 | 345 | /** 346 | * This function updates the necessary properties for a successful search update 347 | * @param updates 348 | */ 349 | NgReactGrid.prototype.updateSearch = function (updates) { 350 | this.search = updates.search; 351 | this.currentPage = 1; 352 | this.updateData({ 353 | data: updates.data 354 | }, true); 355 | }; 356 | 357 | /** 358 | * This function updates the necessary properties for a successful sorting update 359 | * @param updates 360 | */ 361 | NgReactGrid.prototype.updateSorting = function (updates) { 362 | this.sortInfo = updates.sortInfo; 363 | 364 | if (updates.data) { 365 | this.currentPage = 1; 366 | this.updateData({ 367 | data: updates.data 368 | }, true); 369 | } 370 | }; 371 | 372 | /** 373 | * This function updates the necessary properties for a successful total count update 374 | * @param updates 375 | */ 376 | NgReactGrid.prototype.updateTotalCount = function (updates) { 377 | this.totalCount = updates.totalCount; 378 | this.totalPages = Math.ceil(this.totalCount / this.pageSize); 379 | }; 380 | 381 | /** 382 | * This function updates requested visible columns ( columnDefs object ) 383 | * @param updates 384 | */ 385 | NgReactGrid.prototype.updateColumns = function (updates) { 386 | this.columnDefs = updates.columnDefs; 387 | }; 388 | 389 | /** 390 | * Calls React to render the grid component on the given element 391 | */ 392 | NgReactGrid.prototype.render = function () { 393 | // React.renderComponent(ngReactGridComponent({grid: this}), this.element[0]); 394 | var ngReactGridElement = React.createFactory(NgReactGridComponent); 395 | React.render(ngReactGridElement({grid: this}), this.element[0]); 396 | }; 397 | 398 | module.exports = NgReactGrid; 399 | -------------------------------------------------------------------------------- /src/jsx/reactGrid.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * NgReactGridComponent - React Component 3 | **/ 4 | var NgReactGridComponent = (function() { 5 | var windowInnerWidth = window.innerWidth, windowInnerHeight = window.innerHeight; 6 | 7 | var setCellWidthPixels = function(cell) { 8 | 9 | var width = String(cell.width).replace("px", ""); 10 | var isPercent = width.indexOf("%") !== -1; 11 | 12 | if(isPercent) { 13 | 14 | var widthInPixels = Math.floor((parseInt(width) * windowInnerWidth) / 100); 15 | cell.width = widthInPixels; 16 | 17 | } 18 | 19 | }; 20 | 21 | var setCellWidth = function(grid, cell, cellStyle, isLast, bodyCell) { 22 | 23 | if(!cell.width) { 24 | cell.width = "10%"; 25 | } 26 | 27 | if(grid.horizontalScroll) { 28 | setCellWidthPixels(cell); 29 | } 30 | 31 | cellStyle.width = cell.width; 32 | }; 33 | 34 | var NgReactGridHeader = (function() { 35 | var hasColumnFilter = function(grid) { 36 | return grid.columnDefs.some(function(cell) { 37 | return cell.columnFilter; 38 | }); 39 | }; 40 | 41 | var NgGridColumnFilterCell = React.createClass({ 42 | handleSearchInputChange: function() { 43 | this.props.onSearchInput(this.refs[this.props.cell.field].getDOMNode().value, 44 | this.props.cell.field); 45 | }, 46 | render: function() { 47 | return ( 48 | 49 | 53 | 54 | ) 55 | } 56 | }); 57 | 58 | // For input in header. Expandable to additional types. 59 | var NgGridHeaderCellInput = React.createClass({ 60 | getInitialState: function() { 61 | return { 62 | checked: false 63 | }; 64 | }, 65 | setNgReactGridCheckboxHeaderStateFromEvent: function(e) { 66 | this.setState({ 67 | checked: e.detail.checked 68 | }); 69 | }, 70 | componentDidMount: function() { 71 | window.addEventListener("setNgReactGridCheckboxHeaderStateFromEvent", this.setNgReactGridCheckboxHeaderStateFromEvent); 72 | }, 73 | componentWillUnmount: function() { 74 | window.removeEventListener("setNgReactGridCheckboxHeaderStateFromEvent", this.setNgReactGridCheckboxHeaderStateFromEvent); 75 | }, 76 | handleCheckboxClick: function(e) { 77 | e.stopPropagation(); 78 | var newCheckedValue = (this.state.checked) ? false : true; 79 | this.props.cell.handleHeaderClick(newCheckedValue, this.props.grid.react.getFilteredAndSortedData()); 80 | this.setState({ 81 | checked: newCheckedValue 82 | }); 83 | }, 84 | render: function() { 85 | var headerStyle = this.props.cell.options ? 86 | (this.props.cell.options.headerStyle || {}) : {}; 87 | if (this.props.cell.inputType !== undefined) { 88 | switch (this.props.cell.inputType) { 89 | case "checkbox": 90 | return ( 91 |
92 | 93 |
94 | ); 95 | break; 96 | default: 97 | return (
); 98 | } 99 | } else { 100 | return (
); 101 | } 102 | } 103 | }); 104 | 105 | var NgGridHeaderCell = React.createClass({ 106 | getInitialState: function() { 107 | return { 108 | width: 0 109 | }; 110 | }, 111 | cellStyle: {}, 112 | handleClick: function() { 113 | if (this.props.cell.sort !== false) { 114 | this.props.grid.react.setSortField(this.props.cell.field); 115 | } 116 | }, 117 | componentWillReceiveProps: function() { 118 | setCellWidth(this.props.grid, this.props.cell, this.cellStyle, this.props.last); 119 | this.setState({ 120 | width: this.cellStyle.width 121 | }); 122 | }, 123 | componentWillMount: function() { 124 | setCellWidth(this.props.grid, this.props.cell, this.cellStyle, this.props.last); 125 | this.setState({ 126 | width: this.cellStyle.width 127 | }); 128 | }, 129 | resize: function(delta) { 130 | // resize functionality coming soon 131 | }, 132 | componentDidMount: function() { 133 | // resize functionality coming soon 134 | }, 135 | render: function() { 136 | this.cellStyle.cursor = (this.props.cell.sort !== false) ? "pointer" : "default"; 137 | var cellStyle = this.cellStyle; 138 | 139 | var sortStyle = { 140 | cursor: "pointer", 141 | width: "8%", 142 | "float": "left", 143 | textAlign: "right", 144 | display: (this.props.cell.sort === false) ? "none": "inline-block", 145 | overflow: "visible" 146 | }; 147 | 148 | var arrowStyle = { 149 | marginTop: 2 150 | }; 151 | 152 | var sortClassName = "icon-arrows"; 153 | 154 | if(this.props.grid.sortInfo.field === this.props.cell.field) { 155 | if(this.props.grid.sortInfo.dir === "asc") { 156 | sortClassName += " icon-asc"; 157 | } else { 158 | sortClassName += " icon-desc"; 159 | } 160 | 161 | arrowStyle.marginTop = 5; 162 | } else { 163 | sortClassName += " icon-both"; 164 | } 165 | 166 | var resizeStyle = { 167 | height: "21px", 168 | marginTop: "-4px", 169 | width: "1px", 170 | background: "#999999", 171 | borderRight: "1px solid #FFF", 172 | "float": "right" 173 | }; 174 | 175 | var resizeWrapperStyle = { 176 | width: "2%", 177 | cursor: "col-resize", 178 | display: "none" 179 | }; 180 | 181 | return ( 182 | 183 |
184 | {this.props.cell.displayName} 185 |
186 | 187 |
188 |
189 |
190 |
191 | 192 | ) 193 | } 194 | }); 195 | 196 | var NgReactGridShowPerPage = React.createClass({ 197 | handleChange: function() { 198 | this.props.grid.react.setPageSize(this.refs.showPerPage.getDOMNode().value); 199 | }, 200 | render: function() { 201 | 202 | var options = this.props.grid.pageSizes.map(function(pageSize, key) { 203 | return () 204 | }.bind(this)); 205 | 206 | if (this.props.grid.showGridShowPerPage) { 207 | return ( 208 |
209 | Show entries 210 |
211 | ) 212 | } else { 213 | return (
) 214 | } 215 | } 216 | }); 217 | 218 | var NgReactGridSearch = React.createClass({ 219 | handleSearch: function() { 220 | this.props.grid.react.setSearch(this.refs.searchField.getDOMNode().value); 221 | }, 222 | render: function() { 223 | if (this.props.grid.showGridSearch) { 224 | return ( 225 |
226 | 227 |
228 | ) 229 | } else { 230 | return (
) 231 | } 232 | } 233 | }); 234 | 235 | var NgReactGridColumnFilter = React.createClass({ 236 | handleSearch: function(search, column) { 237 | this.props.grid.react.setSearch(search, column); 238 | }, 239 | render: function() { 240 | if (hasColumnFilter(this.props.grid) && this.props.grid.localMode) { 241 | var cells = this.props.grid.columnDefs.map(function(cell, key) { 242 | if (cell.columnFilter) { 243 | return () 244 | } else { 245 | return () 246 | } 247 | }.bind(this)); 248 | 249 | return ( 250 | 251 | {cells} 252 | 253 | ) 254 | } else { 255 | return () 256 | } 257 | } 258 | }); 259 | 260 | var NgReactGridHeader = React.createClass({ 261 | render: function() { 262 | 263 | var columnsLength = this.props.grid.columnDefs.length; 264 | var cells = this.props.grid.columnDefs.map(function(cell, key) { 265 | var last = (columnsLength - 1) === key; 266 | return () 267 | }.bind(this)); 268 | 269 | var tableStyle = { 270 | width: "calc(100% - " + this.props.grid.scrollbarWidth + "px)" 271 | }; 272 | 273 | var ngReactGridHeader = { 274 | paddingRight: (this.props.grid.horizontalScroll) ? this.props.grid.scrollbarWidth : 0, 275 | height: hasColumnFilter(this.props.grid) ? "auto" : "27px" 276 | }; 277 | 278 | return ( 279 |
280 |
281 | 282 | 283 |
284 |
285 |
286 |
287 | 288 | 289 | 290 | {cells} 291 | 292 | 293 | 294 |
295 |
296 |
297 |
298 |
299 | ); 300 | } 301 | }); 302 | 303 | return NgReactGridHeader; 304 | })(); 305 | 306 | var NgReactGridBody = (function() { 307 | 308 | var NgReactGridBodyRowCell = React.createClass({ 309 | cell: function(cellText, cellStyle) { 310 | cellTextType = typeof cellText; 311 | 312 | if(cellTextType === 'string') { 313 | return ({cellText}) 314 | } else if(cellTextType === 'object') { 315 | 316 | cellText = this.props.grid.react.wrapFunctionsInAngular(cellText); 317 | 318 | return ( 319 | 320 | {cellText} 321 | 322 | ); 323 | } else { 324 | return this.defaultCell; 325 | } 326 | }, 327 | render: function() { 328 | var cellText = this.props.grid.react.getObjectPropertyByString(this.props.row, this.props.cell.field); 329 | var cellStyle = {}; 330 | setCellWidth(this.props.grid, this.props.cell, cellStyle, this.props.last, true); 331 | 332 | if(this.props.grid.singleLineCell) { 333 | cellStyle.overflow = "hidden"; 334 | cellStyle.textOverflow = "ellipsis"; 335 | cellStyle.whiteSpace = "nowrap"; 336 | } 337 | 338 | if (cellText === null || typeof cellText == 'undefined') { 339 | cellText = ''; 340 | } 341 | 342 | this.defaultCell = ( 343 | 344 |
{String(cellText)}
345 | 346 | ); 347 | 348 | if(this.props.grid.editing && this.props.cell.edit) { 349 | cellText = this.props.cell.edit(this.props.row); 350 | return this.cell(cellText, cellStyle); 351 | } else if(this.props.cell.render) { 352 | cellText = this.props.cell.render(this.props.row); 353 | return this.cell(cellText, cellStyle); 354 | } else { 355 | return this.defaultCell; 356 | } 357 | 358 | 359 | } 360 | }); 361 | 362 | var NgReactGridBodyRow = React.createClass({ 363 | handleClick: function(e) { 364 | // Prevents triggering 'rowClick' event when toggling checkboxes 365 | if (e.target.type !== 'checkbox') { 366 | this.props.grid.react.rowClick(this.props.row); 367 | } 368 | }, 369 | render: function() { 370 | 371 | var columnsLength = this.props.grid.columnDefs.length; 372 | var cells = this.props.grid.columnDefs.map(function(cell, key) { 373 | var last = (columnsLength - 1) === key; 374 | return 375 | }.bind(this)); 376 | 377 | return ( 378 | 379 | {cells} 380 | 381 | ) 382 | } 383 | }); 384 | 385 | 386 | var NgReactGridBody = React.createClass({ 387 | getInitialState: function() { 388 | return { 389 | fullRender: false, 390 | needsUpdate: false 391 | } 392 | }, 393 | calculateIfNeedsUpdate: function() { 394 | if(this.props.grid.data.length > 100) { 395 | this.setState({ 396 | needsUpdate: true 397 | }); 398 | } 399 | }, 400 | performFullRender: function() { 401 | if(this.state.needsUpdate) { 402 | setTimeout(function() { 403 | this.setState({ 404 | fullRender: true, 405 | needsUpdate: false 406 | }); 407 | }.bind(this), 0); 408 | } 409 | }, 410 | componentWillMount: function() { 411 | this.calculateIfNeedsUpdate(); 412 | }, 413 | componentWillReceiveProps: function() { 414 | this.calculateIfNeedsUpdate(); 415 | }, 416 | componentDidMount: function() { 417 | var domNode = this.getDOMNode(); 418 | var domContainer = domNode.parentNode; 419 | var header = domContainer.querySelector(".ngReactGridHeaderInner"); 420 | var viewPort = domContainer.querySelector(".ngReactGridViewPort"); 421 | 422 | domNode.firstChild.addEventListener('scroll', function(e) { 423 | header.scrollLeft = viewPort.scrollLeft; 424 | }); 425 | 426 | this.performFullRender(); 427 | }, 428 | componentDidUpdate: function() { 429 | this.performFullRender(); 430 | }, 431 | render: function() { 432 | 433 | var mapRows = function(row, index) { 434 | return 435 | }.bind(this); 436 | 437 | var rows; 438 | 439 | if(this.props.grid.react.loading) { 440 | 441 | var loadingStyle = { 442 | textAlign: "center" 443 | }; 444 | 445 | rows = ( 446 | 447 | 448 | Loading... 449 | 450 | 451 | ) 452 | } else { 453 | if(!this.state.fullRender) { 454 | rows = this.props.grid.data.slice(0, 100).map(mapRows); 455 | } else { 456 | rows = this.props.grid.data.map(mapRows); 457 | } 458 | 459 | if(this.props.grid.react.showingRecords === 0) { 460 | var noDataStyle = { 461 | textAlign: "center" 462 | }; 463 | 464 | rows = ( 465 | 466 | 467 | No records found 468 | 469 | 470 | ) 471 | } 472 | } 473 | 474 | 475 | var ngReactGridViewPortStyle = { 476 | maxHeight: this.props.grid.height, 477 | minHeight: this.props.grid.height 478 | }; 479 | 480 | var tableStyle = {}; 481 | 482 | if(!this.props.grid.horizontalScroll) { 483 | ngReactGridViewPortStyle.overflowX = "hidden"; 484 | } else { 485 | tableStyle.width = "calc(100% - " + this.props.grid.scrollbarWidth + "px)"; 486 | } 487 | 488 | return ( 489 |
490 |
491 |
492 | 493 | 494 | {rows} 495 | 496 |
497 |
498 |
499 |
500 | ); 501 | } 502 | }); 503 | 504 | return NgReactGridBody; 505 | })(); 506 | 507 | var NgReactGridFooter = (function() { 508 | 509 | var NgReactGridStatus = React.createClass({ 510 | render: function() { 511 | 512 | return ( 513 |
514 |
Page {this.props.grid.currentPage} of {this.props.grid.totalPages} - Showing {this.props.grid.react.showingRecords} of {this.props.grid.totalCount} records
515 |
516 | ) 517 | } 518 | }); 519 | 520 | var NgReactGridPagination = React.createClass({ 521 | goToPage: function(page) { 522 | this.props.grid.react.goToPage(page); 523 | }, 524 | goToLastPage: function() { 525 | this.goToPage(this.props.grid.totalPages); 526 | }, 527 | goToFirstPage: function() { 528 | this.goToPage(1); 529 | }, 530 | goToNextPage: function() { 531 | var nextPage = (this.props.grid.currentPage + 1); 532 | var diff = this.props.grid.totalPages - nextPage; 533 | 534 | if(diff >= 0) { 535 | this.goToPage(nextPage); 536 | } 537 | }, 538 | goToPrevPage: function() { 539 | var prevPage = (this.props.grid.currentPage - 1); 540 | if(prevPage > 0) { 541 | this.goToPage(prevPage); 542 | } 543 | }, 544 | render: function() { 545 | 546 | var pagerNum = 2; 547 | var totalPages = this.props.grid.totalPages; 548 | var currentPage = this.props.grid.currentPage; 549 | var indexStart = (currentPage - pagerNum) <= 0 ? 1 : (currentPage - pagerNum); 550 | var indexFinish = (currentPage + pagerNum) >= totalPages ? totalPages : (currentPage + pagerNum); 551 | var pages = []; 552 | 553 | for(var i = indexStart; i <= indexFinish; i++) { 554 | pages.push(i); 555 | } 556 | 557 | pages = pages.map(function(page, key) { 558 | var pageClass = (page === this.props.grid.currentPage) ? "active" : ""; 559 | return
  • {page}
  • ; 560 | }.bind(this)); 561 | 562 | return ( 563 |
    564 | 571 |
    572 | ) 573 | } 574 | }); 575 | 576 | var NgReactGridFooter = React.createClass({ 577 | render: function() { 578 | if (this.props.grid.totalCount == 0) { 579 | return null; 580 | } 581 | return ( 582 |
    583 | 584 | 585 |
    586 | ) 587 | } 588 | }); 589 | 590 | return NgReactGridFooter; 591 | })(); 592 | 593 | var NgReactGrid = React.createClass({ 594 | render: function() { 595 | return ( 596 |
    597 | 598 | 599 | 600 |
    601 | ) 602 | } 603 | }); 604 | 605 | return NgReactGrid; 606 | })(); 607 | -------------------------------------------------------------------------------- /examples/dataSet.js: -------------------------------------------------------------------------------- 1 | var dataSet = [{"firstName":"Jose0","lastName":"Garcia0","city":"New York0","state":"New York0","zip":"192030","country":"United States0","phone":"123-455-67530","email":"test@gmail.com0"},{"firstName":"Jose1","lastName":"Garcia1","city":"New York1","state":"New York1","zip":"192031","country":"United States1","phone":"123-455-67531","email":"test@gmail.com1"},{"firstName":"Jose2","lastName":"Garcia2","city":"New York2","state":"New York2","zip":"192032","country":"United States2","phone":"123-455-67532","email":"test@gmail.com2"},{"firstName":"Jose3","lastName":"Garcia3","city":"New York3","state":"New York3","zip":"192033","country":"United States3","phone":"123-455-67533","email":"test@gmail.com3"},{"firstName":"Jose4","lastName":"Garcia4","city":"New York4","state":"New York4","zip":"192034","country":"United States4","phone":"123-455-67534","email":"test@gmail.com4"},{"firstName":"Jose5","lastName":"Garcia5","city":"New York5","state":"New York5","zip":"192035","country":"United States5","phone":"123-455-67535","email":"test@gmail.com5"},{"firstName":"Jose6","lastName":"Garcia6","city":"New York6","state":"New York6","zip":"192036","country":"United States6","phone":"123-455-67536","email":"test@gmail.com6"},{"firstName":"Jose7","lastName":"Garcia7","city":"New York7","state":"New York7","zip":"192037","country":"United States7","phone":"123-455-67537","email":"test@gmail.com7"},{"firstName":"Jose8","lastName":"Garcia8","city":"New York8","state":"New York8","zip":"192038","country":"United States8","phone":"123-455-67538","email":"test@gmail.com8"},{"firstName":"Jose9","lastName":"Garcia9","city":"New York9","state":"New York9","zip":"192039","country":"United States9","phone":"123-455-67539","email":"test@gmail.com9"},{"firstName":"Jose10","lastName":"Garcia10","city":"New York10","state":"New York10","zip":"1920310","country":"United States10","phone":"123-455-675310","email":"test@gmail.com10"},{"firstName":"Jose11","lastName":"Garcia11","city":"New York11","state":"New York11","zip":"1920311","country":"United States11","phone":"123-455-675311","email":"test@gmail.com11"},{"firstName":"Jose12","lastName":"Garcia12","city":"New York12","state":"New York12","zip":"1920312","country":"United States12","phone":"123-455-675312","email":"test@gmail.com12"},{"firstName":"Jose13","lastName":"Garcia13","city":"New York13","state":"New York13","zip":"1920313","country":"United States13","phone":"123-455-675313","email":"test@gmail.com13"},{"firstName":"Jose14","lastName":"Garcia14","city":"New York14","state":"New York14","zip":"1920314","country":"United States14","phone":"123-455-675314","email":"test@gmail.com14"},{"firstName":"Jose15","lastName":"Garcia15","city":"New York15","state":"New York15","zip":"1920315","country":"United States15","phone":"123-455-675315","email":"test@gmail.com15"},{"firstName":"Jose16","lastName":"Garcia16","city":"New York16","state":"New York16","zip":"1920316","country":"United States16","phone":"123-455-675316","email":"test@gmail.com16"},{"firstName":"Jose17","lastName":"Garcia17","city":"New York17","state":"New York17","zip":"1920317","country":"United States17","phone":"123-455-675317","email":"test@gmail.com17"},{"firstName":"Jose18","lastName":"Garcia18","city":"New York18","state":"New York18","zip":"1920318","country":"United States18","phone":"123-455-675318","email":"test@gmail.com18"},{"firstName":"Jose19","lastName":"Garcia19","city":"New York19","state":"New York19","zip":"1920319","country":"United States19","phone":"123-455-675319","email":"test@gmail.com19"},{"firstName":"Jose20","lastName":"Garcia20","city":"New York20","state":"New York20","zip":"1920320","country":"United States20","phone":"123-455-675320","email":"test@gmail.com20"},{"firstName":"Jose21","lastName":"Garcia21","city":"New York21","state":"New York21","zip":"1920321","country":"United States21","phone":"123-455-675321","email":"test@gmail.com21"},{"firstName":"Jose22","lastName":"Garcia22","city":"New York22","state":"New York22","zip":"1920322","country":"United States22","phone":"123-455-675322","email":"test@gmail.com22"},{"firstName":"Jose23","lastName":"Garcia23","city":"New York23","state":"New York23","zip":"1920323","country":"United States23","phone":"123-455-675323","email":"test@gmail.com23"},{"firstName":"Jose24","lastName":"Garcia24","city":"New York24","state":"New York24","zip":"1920324","country":"United States24","phone":"123-455-675324","email":"test@gmail.com24"},{"firstName":"Jose25","lastName":"Garcia25","city":"New York25","state":"New York25","zip":"1920325","country":"United States25","phone":"123-455-675325","email":"test@gmail.com25"},{"firstName":"Jose26","lastName":"Garcia26","city":"New York26","state":"New York26","zip":"1920326","country":"United States26","phone":"123-455-675326","email":"test@gmail.com26"},{"firstName":"Jose27","lastName":"Garcia27","city":"New York27","state":"New York27","zip":"1920327","country":"United States27","phone":"123-455-675327","email":"test@gmail.com27"},{"firstName":"Jose28","lastName":"Garcia28","city":"New York28","state":"New York28","zip":"1920328","country":"United States28","phone":"123-455-675328","email":"test@gmail.com28"},{"firstName":"Jose29","lastName":"Garcia29","city":"New York29","state":"New York29","zip":"1920329","country":"United States29","phone":"123-455-675329","email":"test@gmail.com29"},{"firstName":"Jose30","lastName":"Garcia30","city":"New York30","state":"New York30","zip":"1920330","country":"United States30","phone":"123-455-675330","email":"test@gmail.com30"},{"firstName":"Jose31","lastName":"Garcia31","city":"New York31","state":"New York31","zip":"1920331","country":"United States31","phone":"123-455-675331","email":"test@gmail.com31"},{"firstName":"Jose32","lastName":"Garcia32","city":"New York32","state":"New York32","zip":"1920332","country":"United States32","phone":"123-455-675332","email":"test@gmail.com32"},{"firstName":"Jose33","lastName":"Garcia33","city":"New York33","state":"New York33","zip":"1920333","country":"United States33","phone":"123-455-675333","email":"test@gmail.com33"},{"firstName":"Jose34","lastName":"Garcia34","city":"New York34","state":"New York34","zip":"1920334","country":"United States34","phone":"123-455-675334","email":"test@gmail.com34"},{"firstName":"Jose35","lastName":"Garcia35","city":"New York35","state":"New York35","zip":"1920335","country":"United States35","phone":"123-455-675335","email":"test@gmail.com35"},{"firstName":"Jose36","lastName":"Garcia36","city":"New York36","state":"New York36","zip":"1920336","country":"United States36","phone":"123-455-675336","email":"test@gmail.com36"},{"firstName":"Jose37","lastName":"Garcia37","city":"New York37","state":"New York37","zip":"1920337","country":"United States37","phone":"123-455-675337","email":"test@gmail.com37"},{"firstName":"Jose38","lastName":"Garcia38","city":"New York38","state":"New York38","zip":"1920338","country":"United States38","phone":"123-455-675338","email":"test@gmail.com38"},{"firstName":"Jose39","lastName":"Garcia39","city":"New York39","state":"New York39","zip":"1920339","country":"United States39","phone":"123-455-675339","email":"test@gmail.com39"},{"firstName":"Jose40","lastName":"Garcia40","city":"New York40","state":"New York40","zip":"1920340","country":"United States40","phone":"123-455-675340","email":"test@gmail.com40"},{"firstName":"Jose41","lastName":"Garcia41","city":"New York41","state":"New York41","zip":"1920341","country":"United States41","phone":"123-455-675341","email":"test@gmail.com41"},{"firstName":"Jose42","lastName":"Garcia42","city":"New York42","state":"New York42","zip":"1920342","country":"United States42","phone":"123-455-675342","email":"test@gmail.com42"},{"firstName":"Jose43","lastName":"Garcia43","city":"New York43","state":"New York43","zip":"1920343","country":"United States43","phone":"123-455-675343","email":"test@gmail.com43"},{"firstName":"Jose44","lastName":"Garcia44","city":"New York44","state":"New York44","zip":"1920344","country":"United States44","phone":"123-455-675344","email":"test@gmail.com44"},{"firstName":"Jose45","lastName":"Garcia45","city":"New York45","state":"New York45","zip":"1920345","country":"United States45","phone":"123-455-675345","email":"test@gmail.com45"},{"firstName":"Jose46","lastName":"Garcia46","city":"New York46","state":"New York46","zip":"1920346","country":"United States46","phone":"123-455-675346","email":"test@gmail.com46"},{"firstName":"Jose47","lastName":"Garcia47","city":"New York47","state":"New York47","zip":"1920347","country":"United States47","phone":"123-455-675347","email":"test@gmail.com47"},{"firstName":"Jose48","lastName":"Garcia48","city":"New York48","state":"New York48","zip":"1920348","country":"United States48","phone":"123-455-675348","email":"test@gmail.com48"},{"firstName":"Jose49","lastName":"Garcia49","city":"New York49","state":"New York49","zip":"1920349","country":"United States49","phone":"123-455-675349","email":"test@gmail.com49"},{"firstName":"Jose50","lastName":"Garcia50","city":"New York50","state":"New York50","zip":"1920350","country":"United States50","phone":"123-455-675350","email":"test@gmail.com50"},{"firstName":"Jose51","lastName":"Garcia51","city":"New York51","state":"New York51","zip":"1920351","country":"United States51","phone":"123-455-675351","email":"test@gmail.com51"},{"firstName":"Jose52","lastName":"Garcia52","city":"New York52","state":"New York52","zip":"1920352","country":"United States52","phone":"123-455-675352","email":"test@gmail.com52"},{"firstName":"Jose53","lastName":"Garcia53","city":"New York53","state":"New York53","zip":"1920353","country":"United States53","phone":"123-455-675353","email":"test@gmail.com53"},{"firstName":"Jose54","lastName":"Garcia54","city":"New York54","state":"New York54","zip":"1920354","country":"United States54","phone":"123-455-675354","email":"test@gmail.com54"},{"firstName":"Jose55","lastName":"Garcia55","city":"New York55","state":"New York55","zip":"1920355","country":"United States55","phone":"123-455-675355","email":"test@gmail.com55"},{"firstName":"Jose56","lastName":"Garcia56","city":"New York56","state":"New York56","zip":"1920356","country":"United States56","phone":"123-455-675356","email":"test@gmail.com56"},{"firstName":"Jose57","lastName":"Garcia57","city":"New York57","state":"New York57","zip":"1920357","country":"United States57","phone":"123-455-675357","email":"test@gmail.com57"},{"firstName":"Jose58","lastName":"Garcia58","city":"New York58","state":"New York58","zip":"1920358","country":"United States58","phone":"123-455-675358","email":"test@gmail.com58"},{"firstName":"Jose59","lastName":"Garcia59","city":"New York59","state":"New York59","zip":"1920359","country":"United States59","phone":"123-455-675359","email":"test@gmail.com59"},{"firstName":"Jose60","lastName":"Garcia60","city":"New York60","state":"New York60","zip":"1920360","country":"United States60","phone":"123-455-675360","email":"test@gmail.com60"},{"firstName":"Jose61","lastName":"Garcia61","city":"New York61","state":"New York61","zip":"1920361","country":"United States61","phone":"123-455-675361","email":"test@gmail.com61"},{"firstName":"Jose62","lastName":"Garcia62","city":"New York62","state":"New York62","zip":"1920362","country":"United States62","phone":"123-455-675362","email":"test@gmail.com62"},{"firstName":"Jose63","lastName":"Garcia63","city":"New York63","state":"New York63","zip":"1920363","country":"United States63","phone":"123-455-675363","email":"test@gmail.com63"},{"firstName":"Jose64","lastName":"Garcia64","city":"New York64","state":"New York64","zip":"1920364","country":"United States64","phone":"123-455-675364","email":"test@gmail.com64"},{"firstName":"Jose65","lastName":"Garcia65","city":"New York65","state":"New York65","zip":"1920365","country":"United States65","phone":"123-455-675365","email":"test@gmail.com65"},{"firstName":"Jose66","lastName":"Garcia66","city":"New York66","state":"New York66","zip":"1920366","country":"United States66","phone":"123-455-675366","email":"test@gmail.com66"},{"firstName":"Jose67","lastName":"Garcia67","city":"New York67","state":"New York67","zip":"1920367","country":"United States67","phone":"123-455-675367","email":"test@gmail.com67"},{"firstName":"Jose68","lastName":"Garcia68","city":"New York68","state":"New York68","zip":"1920368","country":"United States68","phone":"123-455-675368","email":"test@gmail.com68"},{"firstName":"Jose69","lastName":"Garcia69","city":"New York69","state":"New York69","zip":"1920369","country":"United States69","phone":"123-455-675369","email":"test@gmail.com69"},{"firstName":"Jose70","lastName":"Garcia70","city":"New York70","state":"New York70","zip":"1920370","country":"United States70","phone":"123-455-675370","email":"test@gmail.com70"},{"firstName":"Jose71","lastName":"Garcia71","city":"New York71","state":"New York71","zip":"1920371","country":"United States71","phone":"123-455-675371","email":"test@gmail.com71"},{"firstName":"Jose72","lastName":"Garcia72","city":"New York72","state":"New York72","zip":"1920372","country":"United States72","phone":"123-455-675372","email":"test@gmail.com72"},{"firstName":"Jose73","lastName":"Garcia73","city":"New York73","state":"New York73","zip":"1920373","country":"United States73","phone":"123-455-675373","email":"test@gmail.com73"},{"firstName":"Jose74","lastName":"Garcia74","city":"New York74","state":"New York74","zip":"1920374","country":"United States74","phone":"123-455-675374","email":"test@gmail.com74"},{"firstName":"Jose75","lastName":"Garcia75","city":"New York75","state":"New York75","zip":"1920375","country":"United States75","phone":"123-455-675375","email":"test@gmail.com75"},{"firstName":"Jose76","lastName":"Garcia76","city":"New York76","state":"New York76","zip":"1920376","country":"United States76","phone":"123-455-675376","email":"test@gmail.com76"},{"firstName":"Jose77","lastName":"Garcia77","city":"New York77","state":"New York77","zip":"1920377","country":"United States77","phone":"123-455-675377","email":"test@gmail.com77"},{"firstName":"Jose78","lastName":"Garcia78","city":"New York78","state":"New York78","zip":"1920378","country":"United States78","phone":"123-455-675378","email":"test@gmail.com78"},{"firstName":"Jose79","lastName":"Garcia79","city":"New York79","state":"New York79","zip":"1920379","country":"United States79","phone":"123-455-675379","email":"test@gmail.com79"},{"firstName":"Jose80","lastName":"Garcia80","city":"New York80","state":"New York80","zip":"1920380","country":"United States80","phone":"123-455-675380","email":"test@gmail.com80"},{"firstName":"Jose81","lastName":"Garcia81","city":"New York81","state":"New York81","zip":"1920381","country":"United States81","phone":"123-455-675381","email":"test@gmail.com81"},{"firstName":"Jose82","lastName":"Garcia82","city":"New York82","state":"New York82","zip":"1920382","country":"United States82","phone":"123-455-675382","email":"test@gmail.com82"},{"firstName":"Jose83","lastName":"Garcia83","city":"New York83","state":"New York83","zip":"1920383","country":"United States83","phone":"123-455-675383","email":"test@gmail.com83"},{"firstName":"Jose84","lastName":"Garcia84","city":"New York84","state":"New York84","zip":"1920384","country":"United States84","phone":"123-455-675384","email":"test@gmail.com84"},{"firstName":"Jose85","lastName":"Garcia85","city":"New York85","state":"New York85","zip":"1920385","country":"United States85","phone":"123-455-675385","email":"test@gmail.com85"},{"firstName":"Jose86","lastName":"Garcia86","city":"New York86","state":"New York86","zip":"1920386","country":"United States86","phone":"123-455-675386","email":"test@gmail.com86"},{"firstName":"Jose87","lastName":"Garcia87","city":"New York87","state":"New York87","zip":"1920387","country":"United States87","phone":"123-455-675387","email":"test@gmail.com87"},{"firstName":"Jose88","lastName":"Garcia88","city":"New York88","state":"New York88","zip":"1920388","country":"United States88","phone":"123-455-675388","email":"test@gmail.com88"},{"firstName":"Jose89","lastName":"Garcia89","city":"New York89","state":"New York89","zip":"1920389","country":"United States89","phone":"123-455-675389","email":"test@gmail.com89"},{"firstName":"Jose90","lastName":"Garcia90","city":"New York90","state":"New York90","zip":"1920390","country":"United States90","phone":"123-455-675390","email":"test@gmail.com90"},{"firstName":"Jose91","lastName":"Garcia91","city":"New York91","state":"New York91","zip":"1920391","country":"United States91","phone":"123-455-675391","email":"test@gmail.com91"},{"firstName":"Jose92","lastName":"Garcia92","city":"New York92","state":"New York92","zip":"1920392","country":"United States92","phone":"123-455-675392","email":"test@gmail.com92"},{"firstName":"Jose93","lastName":"Garcia93","city":"New York93","state":"New York93","zip":"1920393","country":"United States93","phone":"123-455-675393","email":"test@gmail.com93"},{"firstName":"Jose94","lastName":"Garcia94","city":"New York94","state":"New York94","zip":"1920394","country":"United States94","phone":"123-455-675394","email":"test@gmail.com94"},{"firstName":"Jose95","lastName":"Garcia95","city":"New York95","state":"New York95","zip":"1920395","country":"United States95","phone":"123-455-675395","email":"test@gmail.com95"},{"firstName":"Jose96","lastName":"Garcia96","city":"New York96","state":"New York96","zip":"1920396","country":"United States96","phone":"123-455-675396","email":"test@gmail.com96"},{"firstName":"Jose97","lastName":"Garcia97","city":"New York97","state":"New York97","zip":"1920397","country":"United States97","phone":"123-455-675397","email":"test@gmail.com97"},{"firstName":"Jose98","lastName":"Garcia98","city":"New York98","state":"New York98","zip":"1920398","country":"United States98","phone":"123-455-675398","email":"test@gmail.com98"},{"firstName":"Jose99","lastName":"Garcia99","city":"New York99","state":"New York99","zip":"1920399","country":"United States99","phone":"123-455-675399","email":"test@gmail.com99"},{"firstName":"Jose100","lastName":"Garcia100","city":"New York100","state":"New York100","zip":"19203100","country":"United States100","phone":"123-455-6753100","email":"test@gmail.com100"},{"firstName":"Jose101","lastName":"Garcia101","city":"New York101","state":"New York101","zip":"19203101","country":"United States101","phone":"123-455-6753101","email":"test@gmail.com101"},{"firstName":"Jose102","lastName":"Garcia102","city":"New York102","state":"New York102","zip":"19203102","country":"United States102","phone":"123-455-6753102","email":"test@gmail.com102"},{"firstName":"Jose103","lastName":"Garcia103","city":"New York103","state":"New York103","zip":"19203103","country":"United States103","phone":"123-455-6753103","email":"test@gmail.com103"},{"firstName":"Jose104","lastName":"Garcia104","city":"New York104","state":"New York104","zip":"19203104","country":"United States104","phone":"123-455-6753104","email":"test@gmail.com104"},{"firstName":"Jose105","lastName":"Garcia105","city":"New York105","state":"New York105","zip":"19203105","country":"United States105","phone":"123-455-6753105","email":"test@gmail.com105"},{"firstName":"Jose106","lastName":"Garcia106","city":"New York106","state":"New York106","zip":"19203106","country":"United States106","phone":"123-455-6753106","email":"test@gmail.com106"},{"firstName":"Jose107","lastName":"Garcia107","city":"New York107","state":"New York107","zip":"19203107","country":"United States107","phone":"123-455-6753107","email":"test@gmail.com107"},{"firstName":"Jose108","lastName":"Garcia108","city":"New York108","state":"New York108","zip":"19203108","country":"United States108","phone":"123-455-6753108","email":"test@gmail.com108"},{"firstName":"Jose109","lastName":"Garcia109","city":"New York109","state":"New York109","zip":"19203109","country":"United States109","phone":"123-455-6753109","email":"test@gmail.com109"},{"firstName":"Jose110","lastName":"Garcia110","city":"New York110","state":"New York110","zip":"19203110","country":"United States110","phone":"123-455-6753110","email":"test@gmail.com110"},{"firstName":"Jose111","lastName":"Garcia111","city":"New York111","state":"New York111","zip":"19203111","country":"United States111","phone":"123-455-6753111","email":"test@gmail.com111"},{"firstName":"Jose112","lastName":"Garcia112","city":"New York112","state":"New York112","zip":"19203112","country":"United States112","phone":"123-455-6753112","email":"test@gmail.com112"},{"firstName":"Jose113","lastName":"Garcia113","city":"New York113","state":"New York113","zip":"19203113","country":"United States113","phone":"123-455-6753113","email":"test@gmail.com113"},{"firstName":"Jose114","lastName":"Garcia114","city":"New York114","state":"New York114","zip":"19203114","country":"United States114","phone":"123-455-6753114","email":"test@gmail.com114"},{"firstName":"Jose115","lastName":"Garcia115","city":"New York115","state":"New York115","zip":"19203115","country":"United States115","phone":"123-455-6753115","email":"test@gmail.com115"},{"firstName":"Jose116","lastName":"Garcia116","city":"New York116","state":"New York116","zip":"19203116","country":"United States116","phone":"123-455-6753116","email":"test@gmail.com116"},{"firstName":"Jose117","lastName":"Garcia117","city":"New York117","state":"New York117","zip":"19203117","country":"United States117","phone":"123-455-6753117","email":"test@gmail.com117"},{"firstName":"Jose118","lastName":"Garcia118","city":"New York118","state":"New York118","zip":"19203118","country":"United States118","phone":"123-455-6753118","email":"test@gmail.com118"},{"firstName":"Jose119","lastName":"Garcia119","city":"New York119","state":"New York119","zip":"19203119","country":"United States119","phone":"123-455-6753119","email":"test@gmail.com119"},{"firstName":"Jose120","lastName":"Garcia120","city":"New York120","state":"New York120","zip":"19203120","country":"United States120","phone":"123-455-6753120","email":"test@gmail.com120"},{"firstName":"Jose121","lastName":"Garcia121","city":"New York121","state":"New York121","zip":"19203121","country":"United States121","phone":"123-455-6753121","email":"test@gmail.com121"},{"firstName":"Jose122","lastName":"Garcia122","city":"New York122","state":"New York122","zip":"19203122","country":"United States122","phone":"123-455-6753122","email":"test@gmail.com122"},{"firstName":"Jose123","lastName":"Garcia123","city":"New York123","state":"New York123","zip":"19203123","country":"United States123","phone":"123-455-6753123","email":"test@gmail.com123"},{"firstName":"Jose124","lastName":"Garcia124","city":"New York124","state":"New York124","zip":"19203124","country":"United States124","phone":"123-455-6753124","email":"test@gmail.com124"},{"firstName":"Jose125","lastName":"Garcia125","city":"New York125","state":"New York125","zip":"19203125","country":"United States125","phone":"123-455-6753125","email":"test@gmail.com125"},{"firstName":"Jose126","lastName":"Garcia126","city":"New York126","state":"New York126","zip":"19203126","country":"United States126","phone":"123-455-6753126","email":"test@gmail.com126"},{"firstName":"Jose127","lastName":"Garcia127","city":"New York127","state":"New York127","zip":"19203127","country":"United States127","phone":"123-455-6753127","email":"test@gmail.com127"},{"firstName":"Jose128","lastName":"Garcia128","city":"New York128","state":"New York128","zip":"19203128","country":"United States128","phone":"123-455-6753128","email":"test@gmail.com128"},{"firstName":"Jose129","lastName":"Garcia129","city":"New York129","state":"New York129","zip":"19203129","country":"United States129","phone":"123-455-6753129","email":"test@gmail.com129"},{"firstName":"Jose130","lastName":"Garcia130","city":"New York130","state":"New York130","zip":"19203130","country":"United States130","phone":"123-455-6753130","email":"test@gmail.com130"},{"firstName":"Jose131","lastName":"Garcia131","city":"New York131","state":"New York131","zip":"19203131","country":"United States131","phone":"123-455-6753131","email":"test@gmail.com131"},{"firstName":"Jose132","lastName":"Garcia132","city":"New York132","state":"New York132","zip":"19203132","country":"United States132","phone":"123-455-6753132","email":"test@gmail.com132"},{"firstName":"Jose133","lastName":"Garcia133","city":"New York133","state":"New York133","zip":"19203133","country":"United States133","phone":"123-455-6753133","email":"test@gmail.com133"},{"firstName":"Jose134","lastName":"Garcia134","city":"New York134","state":"New York134","zip":"19203134","country":"United States134","phone":"123-455-6753134","email":"test@gmail.com134"},{"firstName":"Jose135","lastName":"Garcia135","city":"New York135","state":"New York135","zip":"19203135","country":"United States135","phone":"123-455-6753135","email":"test@gmail.com135"},{"firstName":"Jose136","lastName":"Garcia136","city":"New York136","state":"New York136","zip":"19203136","country":"United States136","phone":"123-455-6753136","email":"test@gmail.com136"},{"firstName":"Jose137","lastName":"Garcia137","city":"New York137","state":"New York137","zip":"19203137","country":"United States137","phone":"123-455-6753137","email":"test@gmail.com137"},{"firstName":"Jose138","lastName":"Garcia138","city":"New York138","state":"New York138","zip":"19203138","country":"United States138","phone":"123-455-6753138","email":"test@gmail.com138"},{"firstName":"Jose139","lastName":"Garcia139","city":"New York139","state":"New York139","zip":"19203139","country":"United States139","phone":"123-455-6753139","email":"test@gmail.com139"},{"firstName":"Jose140","lastName":"Garcia140","city":"New York140","state":"New York140","zip":"19203140","country":"United States140","phone":"123-455-6753140","email":"test@gmail.com140"},{"firstName":"Jose141","lastName":"Garcia141","city":"New York141","state":"New York141","zip":"19203141","country":"United States141","phone":"123-455-6753141","email":"test@gmail.com141"},{"firstName":"Jose142","lastName":"Garcia142","city":"New York142","state":"New York142","zip":"19203142","country":"United States142","phone":"123-455-6753142","email":"test@gmail.com142"},{"firstName":"Jose143","lastName":"Garcia143","city":"New York143","state":"New York143","zip":"19203143","country":"United States143","phone":"123-455-6753143","email":"test@gmail.com143"},{"firstName":"Jose144","lastName":"Garcia144","city":"New York144","state":"New York144","zip":"19203144","country":"United States144","phone":"123-455-6753144","email":"test@gmail.com144"},{"firstName":"Jose145","lastName":"Garcia145","city":"New York145","state":"New York145","zip":"19203145","country":"United States145","phone":"123-455-6753145","email":"test@gmail.com145"},{"firstName":"Jose146","lastName":"Garcia146","city":"New York146","state":"New York146","zip":"19203146","country":"United States146","phone":"123-455-6753146","email":"test@gmail.com146"},{"firstName":"Jose147","lastName":"Garcia147","city":"New York147","state":"New York147","zip":"19203147","country":"United States147","phone":"123-455-6753147","email":"test@gmail.com147"},{"firstName":"Jose148","lastName":"Garcia148","city":"New York148","state":"New York148","zip":"19203148","country":"United States148","phone":"123-455-6753148","email":"test@gmail.com148"},{"firstName":"Jose149","lastName":"Garcia149","city":"New York149","state":"New York149","zip":"19203149","country":"United States149","phone":"123-455-6753149","email":"test@gmail.com149"},{"firstName":"Jose150","lastName":"Garcia150","city":"New York150","state":"New York150","zip":"19203150","country":"United States150","phone":"123-455-6753150","email":"test@gmail.com150"},{"firstName":"Jose151","lastName":"Garcia151","city":"New York151","state":"New York151","zip":"19203151","country":"United States151","phone":"123-455-6753151","email":"test@gmail.com151"},{"firstName":"Jose152","lastName":"Garcia152","city":"New York152","state":"New York152","zip":"19203152","country":"United States152","phone":"123-455-6753152","email":"test@gmail.com152"},{"firstName":"Jose153","lastName":"Garcia153","city":"New York153","state":"New York153","zip":"19203153","country":"United States153","phone":"123-455-6753153","email":"test@gmail.com153"},{"firstName":"Jose154","lastName":"Garcia154","city":"New York154","state":"New York154","zip":"19203154","country":"United States154","phone":"123-455-6753154","email":"test@gmail.com154"},{"firstName":"Jose155","lastName":"Garcia155","city":"New York155","state":"New York155","zip":"19203155","country":"United States155","phone":"123-455-6753155","email":"test@gmail.com155"},{"firstName":"Jose156","lastName":"Garcia156","city":"New York156","state":"New York156","zip":"19203156","country":"United States156","phone":"123-455-6753156","email":"test@gmail.com156"},{"firstName":"Jose157","lastName":"Garcia157","city":"New York157","state":"New York157","zip":"19203157","country":"United States157","phone":"123-455-6753157","email":"test@gmail.com157"},{"firstName":"Jose158","lastName":"Garcia158","city":"New York158","state":"New York158","zip":"19203158","country":"United States158","phone":"123-455-6753158","email":"test@gmail.com158"},{"firstName":"Jose159","lastName":"Garcia159","city":"New York159","state":"New York159","zip":"19203159","country":"United States159","phone":"123-455-6753159","email":"test@gmail.com159"},{"firstName":"Jose160","lastName":"Garcia160","city":"New York160","state":"New York160","zip":"19203160","country":"United States160","phone":"123-455-6753160","email":"test@gmail.com160"},{"firstName":"Jose161","lastName":"Garcia161","city":"New York161","state":"New York161","zip":"19203161","country":"United States161","phone":"123-455-6753161","email":"test@gmail.com161"},{"firstName":"Jose162","lastName":"Garcia162","city":"New York162","state":"New York162","zip":"19203162","country":"United States162","phone":"123-455-6753162","email":"test@gmail.com162"},{"firstName":"Jose163","lastName":"Garcia163","city":"New York163","state":"New York163","zip":"19203163","country":"United States163","phone":"123-455-6753163","email":"test@gmail.com163"},{"firstName":"Jose164","lastName":"Garcia164","city":"New York164","state":"New York164","zip":"19203164","country":"United States164","phone":"123-455-6753164","email":"test@gmail.com164"},{"firstName":"Jose165","lastName":"Garcia165","city":"New York165","state":"New York165","zip":"19203165","country":"United States165","phone":"123-455-6753165","email":"test@gmail.com165"},{"firstName":"Jose166","lastName":"Garcia166","city":"New York166","state":"New York166","zip":"19203166","country":"United States166","phone":"123-455-6753166","email":"test@gmail.com166"},{"firstName":"Jose167","lastName":"Garcia167","city":"New York167","state":"New York167","zip":"19203167","country":"United States167","phone":"123-455-6753167","email":"test@gmail.com167"},{"firstName":"Jose168","lastName":"Garcia168","city":"New York168","state":"New York168","zip":"19203168","country":"United States168","phone":"123-455-6753168","email":"test@gmail.com168"},{"firstName":"Jose169","lastName":"Garcia169","city":"New York169","state":"New York169","zip":"19203169","country":"United States169","phone":"123-455-6753169","email":"test@gmail.com169"},{"firstName":"Jose170","lastName":"Garcia170","city":"New York170","state":"New York170","zip":"19203170","country":"United States170","phone":"123-455-6753170","email":"test@gmail.com170"},{"firstName":"Jose171","lastName":"Garcia171","city":"New York171","state":"New York171","zip":"19203171","country":"United States171","phone":"123-455-6753171","email":"test@gmail.com171"},{"firstName":"Jose172","lastName":"Garcia172","city":"New York172","state":"New York172","zip":"19203172","country":"United States172","phone":"123-455-6753172","email":"test@gmail.com172"},{"firstName":"Jose173","lastName":"Garcia173","city":"New York173","state":"New York173","zip":"19203173","country":"United States173","phone":"123-455-6753173","email":"test@gmail.com173"},{"firstName":"Jose174","lastName":"Garcia174","city":"New York174","state":"New York174","zip":"19203174","country":"United States174","phone":"123-455-6753174","email":"test@gmail.com174"},{"firstName":"Jose175","lastName":"Garcia175","city":"New York175","state":"New York175","zip":"19203175","country":"United States175","phone":"123-455-6753175","email":"test@gmail.com175"},{"firstName":"Jose176","lastName":"Garcia176","city":"New York176","state":"New York176","zip":"19203176","country":"United States176","phone":"123-455-6753176","email":"test@gmail.com176"},{"firstName":"Jose177","lastName":"Garcia177","city":"New York177","state":"New York177","zip":"19203177","country":"United States177","phone":"123-455-6753177","email":"test@gmail.com177"},{"firstName":"Jose178","lastName":"Garcia178","city":"New York178","state":"New York178","zip":"19203178","country":"United States178","phone":"123-455-6753178","email":"test@gmail.com178"},{"firstName":"Jose179","lastName":"Garcia179","city":"New York179","state":"New York179","zip":"19203179","country":"United States179","phone":"123-455-6753179","email":"test@gmail.com179"},{"firstName":"Jose180","lastName":"Garcia180","city":"New York180","state":"New York180","zip":"19203180","country":"United States180","phone":"123-455-6753180","email":"test@gmail.com180"},{"firstName":"Jose181","lastName":"Garcia181","city":"New York181","state":"New York181","zip":"19203181","country":"United States181","phone":"123-455-6753181","email":"test@gmail.com181"},{"firstName":"Jose182","lastName":"Garcia182","city":"New York182","state":"New York182","zip":"19203182","country":"United States182","phone":"123-455-6753182","email":"test@gmail.com182"},{"firstName":"Jose183","lastName":"Garcia183","city":"New York183","state":"New York183","zip":"19203183","country":"United States183","phone":"123-455-6753183","email":"test@gmail.com183"},{"firstName":"Jose184","lastName":"Garcia184","city":"New York184","state":"New York184","zip":"19203184","country":"United States184","phone":"123-455-6753184","email":"test@gmail.com184"},{"firstName":"Jose185","lastName":"Garcia185","city":"New York185","state":"New York185","zip":"19203185","country":"United States185","phone":"123-455-6753185","email":"test@gmail.com185"},{"firstName":"Jose186","lastName":"Garcia186","city":"New York186","state":"New York186","zip":"19203186","country":"United States186","phone":"123-455-6753186","email":"test@gmail.com186"},{"firstName":"Jose187","lastName":"Garcia187","city":"New York187","state":"New York187","zip":"19203187","country":"United States187","phone":"123-455-6753187","email":"test@gmail.com187"},{"firstName":"Jose188","lastName":"Garcia188","city":"New York188","state":"New York188","zip":"19203188","country":"United States188","phone":"123-455-6753188","email":"test@gmail.com188"},{"firstName":"Jose189","lastName":"Garcia189","city":"New York189","state":"New York189","zip":"19203189","country":"United States189","phone":"123-455-6753189","email":"test@gmail.com189"},{"firstName":"Jose190","lastName":"Garcia190","city":"New York190","state":"New York190","zip":"19203190","country":"United States190","phone":"123-455-6753190","email":"test@gmail.com190"},{"firstName":"Jose191","lastName":"Garcia191","city":"New York191","state":"New York191","zip":"19203191","country":"United States191","phone":"123-455-6753191","email":"test@gmail.com191"},{"firstName":"Jose192","lastName":"Garcia192","city":"New York192","state":"New York192","zip":"19203192","country":"United States192","phone":"123-455-6753192","email":"test@gmail.com192"},{"firstName":"Jose193","lastName":"Garcia193","city":"New York193","state":"New York193","zip":"19203193","country":"United States193","phone":"123-455-6753193","email":"test@gmail.com193"},{"firstName":"Jose194","lastName":"Garcia194","city":"New York194","state":"New York194","zip":"19203194","country":"United States194","phone":"123-455-6753194","email":"test@gmail.com194"},{"firstName":"Jose195","lastName":"Garcia195","city":"New York195","state":"New York195","zip":"19203195","country":"United States195","phone":"123-455-6753195","email":"test@gmail.com195"},{"firstName":"Jose196","lastName":"Garcia196","city":"New York196","state":"New York196","zip":"19203196","country":"United States196","phone":"123-455-6753196","email":"test@gmail.com196"},{"firstName":"Jose197","lastName":"Garcia197","city":"New York197","state":"New York197","zip":"19203197","country":"United States197","phone":"123-455-6753197","email":"test@gmail.com197"},{"firstName":"Jose198","lastName":"Garcia198","city":"New York198","state":"New York198","zip":"19203198","country":"United States198","phone":"123-455-6753198","email":"test@gmail.com198"},{"firstName":"Jose199","lastName":"Garcia199","city":"New York199","state":"New York199","zip":"19203199","country":"United States199","phone":"123-455-6753199","email":"test@gmail.com199"},{"firstName":"Jose200","lastName":"Garcia200","city":"New York200","state":"New York200","zip":"19203200","country":"United States200","phone":"123-455-6753200","email":"test@gmail.com200"},{"firstName":"Jose201","lastName":"Garcia201","city":"New York201","state":"New York201","zip":"19203201","country":"United States201","phone":"123-455-6753201","email":"test@gmail.com201"},{"firstName":"Jose202","lastName":"Garcia202","city":"New York202","state":"New York202","zip":"19203202","country":"United States202","phone":"123-455-6753202","email":"test@gmail.com202"},{"firstName":"Jose203","lastName":"Garcia203","city":"New York203","state":"New York203","zip":"19203203","country":"United States203","phone":"123-455-6753203","email":"test@gmail.com203"},{"firstName":"Jose204","lastName":"Garcia204","city":"New York204","state":"New York204","zip":"19203204","country":"United States204","phone":"123-455-6753204","email":"test@gmail.com204"},{"firstName":"Jose205","lastName":"Garcia205","city":"New York205","state":"New York205","zip":"19203205","country":"United States205","phone":"123-455-6753205","email":"test@gmail.com205"},{"firstName":"Jose206","lastName":"Garcia206","city":"New York206","state":"New York206","zip":"19203206","country":"United States206","phone":"123-455-6753206","email":"test@gmail.com206"},{"firstName":"Jose207","lastName":"Garcia207","city":"New York207","state":"New York207","zip":"19203207","country":"United States207","phone":"123-455-6753207","email":"test@gmail.com207"},{"firstName":"Jose208","lastName":"Garcia208","city":"New York208","state":"New York208","zip":"19203208","country":"United States208","phone":"123-455-6753208","email":"test@gmail.com208"},{"firstName":"Jose209","lastName":"Garcia209","city":"New York209","state":"New York209","zip":"19203209","country":"United States209","phone":"123-455-6753209","email":"test@gmail.com209"},{"firstName":"Jose210","lastName":"Garcia210","city":"New York210","state":"New York210","zip":"19203210","country":"United States210","phone":"123-455-6753210","email":"test@gmail.com210"},{"firstName":"Jose211","lastName":"Garcia211","city":"New York211","state":"New York211","zip":"19203211","country":"United States211","phone":"123-455-6753211","email":"test@gmail.com211"},{"firstName":"Jose212","lastName":"Garcia212","city":"New York212","state":"New York212","zip":"19203212","country":"United States212","phone":"123-455-6753212","email":"test@gmail.com212"},{"firstName":"Jose213","lastName":"Garcia213","city":"New York213","state":"New York213","zip":"19203213","country":"United States213","phone":"123-455-6753213","email":"test@gmail.com213"},{"firstName":"Jose214","lastName":"Garcia214","city":"New York214","state":"New York214","zip":"19203214","country":"United States214","phone":"123-455-6753214","email":"test@gmail.com214"},{"firstName":"Jose215","lastName":"Garcia215","city":"New York215","state":"New York215","zip":"19203215","country":"United States215","phone":"123-455-6753215","email":"test@gmail.com215"},{"firstName":"Jose216","lastName":"Garcia216","city":"New York216","state":"New York216","zip":"19203216","country":"United States216","phone":"123-455-6753216","email":"test@gmail.com216"},{"firstName":"Jose217","lastName":"Garcia217","city":"New York217","state":"New York217","zip":"19203217","country":"United States217","phone":"123-455-6753217","email":"test@gmail.com217"},{"firstName":"Jose218","lastName":"Garcia218","city":"New York218","state":"New York218","zip":"19203218","country":"United States218","phone":"123-455-6753218","email":"test@gmail.com218"},{"firstName":"Jose219","lastName":"Garcia219","city":"New York219","state":"New York219","zip":"19203219","country":"United States219","phone":"123-455-6753219","email":"test@gmail.com219"},{"firstName":"Jose220","lastName":"Garcia220","city":"New York220","state":"New York220","zip":"19203220","country":"United States220","phone":"123-455-6753220","email":"test@gmail.com220"},{"firstName":"Jose221","lastName":"Garcia221","city":"New York221","state":"New York221","zip":"19203221","country":"United States221","phone":"123-455-6753221","email":"test@gmail.com221"},{"firstName":"Jose222","lastName":"Garcia222","city":"New York222","state":"New York222","zip":"19203222","country":"United States222","phone":"123-455-6753222","email":"test@gmail.com222"},{"firstName":"Jose223","lastName":"Garcia223","city":"New York223","state":"New York223","zip":"19203223","country":"United States223","phone":"123-455-6753223","email":"test@gmail.com223"},{"firstName":"Jose224","lastName":"Garcia224","city":"New York224","state":"New York224","zip":"19203224","country":"United States224","phone":"123-455-6753224","email":"test@gmail.com224"},{"firstName":"Jose225","lastName":"Garcia225","city":"New York225","state":"New York225","zip":"19203225","country":"United States225","phone":"123-455-6753225","email":"test@gmail.com225"},{"firstName":"Jose226","lastName":"Garcia226","city":"New York226","state":"New York226","zip":"19203226","country":"United States226","phone":"123-455-6753226","email":"test@gmail.com226"},{"firstName":"Jose227","lastName":"Garcia227","city":"New York227","state":"New York227","zip":"19203227","country":"United States227","phone":"123-455-6753227","email":"test@gmail.com227"},{"firstName":"Jose228","lastName":"Garcia228","city":"New York228","state":"New York228","zip":"19203228","country":"United States228","phone":"123-455-6753228","email":"test@gmail.com228"},{"firstName":"Jose229","lastName":"Garcia229","city":"New York229","state":"New York229","zip":"19203229","country":"United States229","phone":"123-455-6753229","email":"test@gmail.com229"},{"firstName":"Jose230","lastName":"Garcia230","city":"New York230","state":"New York230","zip":"19203230","country":"United States230","phone":"123-455-6753230","email":"test@gmail.com230"},{"firstName":"Jose231","lastName":"Garcia231","city":"New York231","state":"New York231","zip":"19203231","country":"United States231","phone":"123-455-6753231","email":"test@gmail.com231"},{"firstName":"Jose232","lastName":"Garcia232","city":"New York232","state":"New York232","zip":"19203232","country":"United States232","phone":"123-455-6753232","email":"test@gmail.com232"},{"firstName":"Jose233","lastName":"Garcia233","city":"New York233","state":"New York233","zip":"19203233","country":"United States233","phone":"123-455-6753233","email":"test@gmail.com233"},{"firstName":"Jose234","lastName":"Garcia234","city":"New York234","state":"New York234","zip":"19203234","country":"United States234","phone":"123-455-6753234","email":"test@gmail.com234"},{"firstName":"Jose235","lastName":"Garcia235","city":"New York235","state":"New York235","zip":"19203235","country":"United States235","phone":"123-455-6753235","email":"test@gmail.com235"},{"firstName":"Jose236","lastName":"Garcia236","city":"New York236","state":"New York236","zip":"19203236","country":"United States236","phone":"123-455-6753236","email":"test@gmail.com236"},{"firstName":"Jose237","lastName":"Garcia237","city":"New York237","state":"New York237","zip":"19203237","country":"United States237","phone":"123-455-6753237","email":"test@gmail.com237"},{"firstName":"Jose238","lastName":"Garcia238","city":"New York238","state":"New York238","zip":"19203238","country":"United States238","phone":"123-455-6753238","email":"test@gmail.com238"},{"firstName":"Jose239","lastName":"Garcia239","city":"New York239","state":"New York239","zip":"19203239","country":"United States239","phone":"123-455-6753239","email":"test@gmail.com239"},{"firstName":"Jose240","lastName":"Garcia240","city":"New York240","state":"New York240","zip":"19203240","country":"United States240","phone":"123-455-6753240","email":"test@gmail.com240"},{"firstName":"Jose241","lastName":"Garcia241","city":"New York241","state":"New York241","zip":"19203241","country":"United States241","phone":"123-455-6753241","email":"test@gmail.com241"},{"firstName":"Jose242","lastName":"Garcia242","city":"New York242","state":"New York242","zip":"19203242","country":"United States242","phone":"123-455-6753242","email":"test@gmail.com242"},{"firstName":"Jose243","lastName":"Garcia243","city":"New York243","state":"New York243","zip":"19203243","country":"United States243","phone":"123-455-6753243","email":"test@gmail.com243"},{"firstName":"Jose244","lastName":"Garcia244","city":"New York244","state":"New York244","zip":"19203244","country":"United States244","phone":"123-455-6753244","email":"test@gmail.com244"},{"firstName":"Jose245","lastName":"Garcia245","city":"New York245","state":"New York245","zip":"19203245","country":"United States245","phone":"123-455-6753245","email":"test@gmail.com245"},{"firstName":"Jose246","lastName":"Garcia246","city":"New York246","state":"New York246","zip":"19203246","country":"United States246","phone":"123-455-6753246","email":"test@gmail.com246"},{"firstName":"Jose247","lastName":"Garcia247","city":"New York247","state":"New York247","zip":"19203247","country":"United States247","phone":"123-455-6753247","email":"test@gmail.com247"},{"firstName":"Jose248","lastName":"Garcia248","city":"New York248","state":"New York248","zip":"19203248","country":"United States248","phone":"123-455-6753248","email":"test@gmail.com248"},{"firstName":"Jose249","lastName":"Garcia249","city":"New York249","state":"New York249","zip":"19203249","country":"United States249","phone":"123-455-6753249","email":"test@gmail.com249"},{"firstName":"Jose250","lastName":"Garcia250","city":"New York250","state":"New York250","zip":"19203250","country":"United States250","phone":"123-455-6753250","email":"test@gmail.com250"},{"firstName":"Jose251","lastName":"Garcia251","city":"New York251","state":"New York251","zip":"19203251","country":"United States251","phone":"123-455-6753251","email":"test@gmail.com251"},{"firstName":"Jose252","lastName":"Garcia252","city":"New York252","state":"New York252","zip":"19203252","country":"United States252","phone":"123-455-6753252","email":"test@gmail.com252"},{"firstName":"Jose253","lastName":"Garcia253","city":"New York253","state":"New York253","zip":"19203253","country":"United States253","phone":"123-455-6753253","email":"test@gmail.com253"},{"firstName":"Jose254","lastName":"Garcia254","city":"New York254","state":"New York254","zip":"19203254","country":"United States254","phone":"123-455-6753254","email":"test@gmail.com254"},{"firstName":"Jose255","lastName":"Garcia255","city":"New York255","state":"New York255","zip":"19203255","country":"United States255","phone":"123-455-6753255","email":"test@gmail.com255"},{"firstName":"Jose256","lastName":"Garcia256","city":"New York256","state":"New York256","zip":"19203256","country":"United States256","phone":"123-455-6753256","email":"test@gmail.com256"},{"firstName":"Jose257","lastName":"Garcia257","city":"New York257","state":"New York257","zip":"19203257","country":"United States257","phone":"123-455-6753257","email":"test@gmail.com257"},{"firstName":"Jose258","lastName":"Garcia258","city":"New York258","state":"New York258","zip":"19203258","country":"United States258","phone":"123-455-6753258","email":"test@gmail.com258"},{"firstName":"Jose259","lastName":"Garcia259","city":"New York259","state":"New York259","zip":"19203259","country":"United States259","phone":"123-455-6753259","email":"test@gmail.com259"},{"firstName":"Jose260","lastName":"Garcia260","city":"New York260","state":"New York260","zip":"19203260","country":"United States260","phone":"123-455-6753260","email":"test@gmail.com260"},{"firstName":"Jose261","lastName":"Garcia261","city":"New York261","state":"New York261","zip":"19203261","country":"United States261","phone":"123-455-6753261","email":"test@gmail.com261"},{"firstName":"Jose262","lastName":"Garcia262","city":"New York262","state":"New York262","zip":"19203262","country":"United States262","phone":"123-455-6753262","email":"test@gmail.com262"},{"firstName":"Jose263","lastName":"Garcia263","city":"New York263","state":"New York263","zip":"19203263","country":"United States263","phone":"123-455-6753263","email":"test@gmail.com263"},{"firstName":"Jose264","lastName":"Garcia264","city":"New York264","state":"New York264","zip":"19203264","country":"United States264","phone":"123-455-6753264","email":"test@gmail.com264"},{"firstName":"Jose265","lastName":"Garcia265","city":"New York265","state":"New York265","zip":"19203265","country":"United States265","phone":"123-455-6753265","email":"test@gmail.com265"},{"firstName":"Jose266","lastName":"Garcia266","city":"New York266","state":"New York266","zip":"19203266","country":"United States266","phone":"123-455-6753266","email":"test@gmail.com266"},{"firstName":"Jose267","lastName":"Garcia267","city":"New York267","state":"New York267","zip":"19203267","country":"United States267","phone":"123-455-6753267","email":"test@gmail.com267"},{"firstName":"Jose268","lastName":"Garcia268","city":"New York268","state":"New York268","zip":"19203268","country":"United States268","phone":"123-455-6753268","email":"test@gmail.com268"},{"firstName":"Jose269","lastName":"Garcia269","city":"New York269","state":"New York269","zip":"19203269","country":"United States269","phone":"123-455-6753269","email":"test@gmail.com269"},{"firstName":"Jose270","lastName":"Garcia270","city":"New York270","state":"New York270","zip":"19203270","country":"United States270","phone":"123-455-6753270","email":"test@gmail.com270"},{"firstName":"Jose271","lastName":"Garcia271","city":"New York271","state":"New York271","zip":"19203271","country":"United States271","phone":"123-455-6753271","email":"test@gmail.com271"},{"firstName":"Jose272","lastName":"Garcia272","city":"New York272","state":"New York272","zip":"19203272","country":"United States272","phone":"123-455-6753272","email":"test@gmail.com272"},{"firstName":"Jose273","lastName":"Garcia273","city":"New York273","state":"New York273","zip":"19203273","country":"United States273","phone":"123-455-6753273","email":"test@gmail.com273"},{"firstName":"Jose274","lastName":"Garcia274","city":"New York274","state":"New York274","zip":"19203274","country":"United States274","phone":"123-455-6753274","email":"test@gmail.com274"},{"firstName":"Jose275","lastName":"Garcia275","city":"New York275","state":"New York275","zip":"19203275","country":"United States275","phone":"123-455-6753275","email":"test@gmail.com275"},{"firstName":"Jose276","lastName":"Garcia276","city":"New York276","state":"New York276","zip":"19203276","country":"United States276","phone":"123-455-6753276","email":"test@gmail.com276"},{"firstName":"Jose277","lastName":"Garcia277","city":"New York277","state":"New York277","zip":"19203277","country":"United States277","phone":"123-455-6753277","email":"test@gmail.com277"},{"firstName":"Jose278","lastName":"Garcia278","city":"New York278","state":"New York278","zip":"19203278","country":"United States278","phone":"123-455-6753278","email":"test@gmail.com278"},{"firstName":"Jose279","lastName":"Garcia279","city":"New York279","state":"New York279","zip":"19203279","country":"United States279","phone":"123-455-6753279","email":"test@gmail.com279"},{"firstName":"Jose280","lastName":"Garcia280","city":"New York280","state":"New York280","zip":"19203280","country":"United States280","phone":"123-455-6753280","email":"test@gmail.com280"},{"firstName":"Jose281","lastName":"Garcia281","city":"New York281","state":"New York281","zip":"19203281","country":"United States281","phone":"123-455-6753281","email":"test@gmail.com281"},{"firstName":"Jose282","lastName":"Garcia282","city":"New York282","state":"New York282","zip":"19203282","country":"United States282","phone":"123-455-6753282","email":"test@gmail.com282"},{"firstName":"Jose283","lastName":"Garcia283","city":"New York283","state":"New York283","zip":"19203283","country":"United States283","phone":"123-455-6753283","email":"test@gmail.com283"},{"firstName":"Jose284","lastName":"Garcia284","city":"New York284","state":"New York284","zip":"19203284","country":"United States284","phone":"123-455-6753284","email":"test@gmail.com284"},{"firstName":"Jose285","lastName":"Garcia285","city":"New York285","state":"New York285","zip":"19203285","country":"United States285","phone":"123-455-6753285","email":"test@gmail.com285"},{"firstName":"Jose286","lastName":"Garcia286","city":"New York286","state":"New York286","zip":"19203286","country":"United States286","phone":"123-455-6753286","email":"test@gmail.com286"},{"firstName":"Jose287","lastName":"Garcia287","city":"New York287","state":"New York287","zip":"19203287","country":"United States287","phone":"123-455-6753287","email":"test@gmail.com287"},{"firstName":"Jose288","lastName":"Garcia288","city":"New York288","state":"New York288","zip":"19203288","country":"United States288","phone":"123-455-6753288","email":"test@gmail.com288"},{"firstName":"Jose289","lastName":"Garcia289","city":"New York289","state":"New York289","zip":"19203289","country":"United States289","phone":"123-455-6753289","email":"test@gmail.com289"},{"firstName":"Jose290","lastName":"Garcia290","city":"New York290","state":"New York290","zip":"19203290","country":"United States290","phone":"123-455-6753290","email":"test@gmail.com290"},{"firstName":"Jose291","lastName":"Garcia291","city":"New York291","state":"New York291","zip":"19203291","country":"United States291","phone":"123-455-6753291","email":"test@gmail.com291"},{"firstName":"Jose292","lastName":"Garcia292","city":"New York292","state":"New York292","zip":"19203292","country":"United States292","phone":"123-455-6753292","email":"test@gmail.com292"},{"firstName":"Jose293","lastName":"Garcia293","city":"New York293","state":"New York293","zip":"19203293","country":"United States293","phone":"123-455-6753293","email":"test@gmail.com293"},{"firstName":"Jose294","lastName":"Garcia294","city":"New York294","state":"New York294","zip":"19203294","country":"United States294","phone":"123-455-6753294","email":"test@gmail.com294"},{"firstName":"Jose295","lastName":"Garcia295","city":"New York295","state":"New York295","zip":"19203295","country":"United States295","phone":"123-455-6753295","email":"test@gmail.com295"},{"firstName":"Jose296","lastName":"Garcia296","city":"New York296","state":"New York296","zip":"19203296","country":"United States296","phone":"123-455-6753296","email":"test@gmail.com296"},{"firstName":"Jose297","lastName":"Garcia297","city":"New York297","state":"New York297","zip":"19203297","country":"United States297","phone":"123-455-6753297","email":"test@gmail.com297"},{"firstName":"Jose298","lastName":"Garcia298","city":"New York298","state":"New York298","zip":"19203298","country":"United States298","phone":"123-455-6753298","email":"test@gmail.com298"},{"firstName":"Jose299","lastName":"Garcia299","city":"New York299","state":"New York299","zip":"19203299","country":"United States299","phone":"123-455-6753299","email":"test@gmail.com299"},{"firstName":"Jose300","lastName":"Garcia300","city":"New York300","state":"New York300","zip":"19203300","country":"United States300","phone":"123-455-6753300","email":"test@gmail.com300"},{"firstName":"Jose301","lastName":"Garcia301","city":"New York301","state":"New York301","zip":"19203301","country":"United States301","phone":"123-455-6753301","email":"test@gmail.com301"},{"firstName":"Jose302","lastName":"Garcia302","city":"New York302","state":"New York302","zip":"19203302","country":"United States302","phone":"123-455-6753302","email":"test@gmail.com302"},{"firstName":"Jose303","lastName":"Garcia303","city":"New York303","state":"New York303","zip":"19203303","country":"United States303","phone":"123-455-6753303","email":"test@gmail.com303"},{"firstName":"Jose304","lastName":"Garcia304","city":"New York304","state":"New York304","zip":"19203304","country":"United States304","phone":"123-455-6753304","email":"test@gmail.com304"},{"firstName":"Jose305","lastName":"Garcia305","city":"New York305","state":"New York305","zip":"19203305","country":"United States305","phone":"123-455-6753305","email":"test@gmail.com305"},{"firstName":"Jose306","lastName":"Garcia306","city":"New York306","state":"New York306","zip":"19203306","country":"United States306","phone":"123-455-6753306","email":"test@gmail.com306"},{"firstName":"Jose307","lastName":"Garcia307","city":"New York307","state":"New York307","zip":"19203307","country":"United States307","phone":"123-455-6753307","email":"test@gmail.com307"},{"firstName":"Jose308","lastName":"Garcia308","city":"New York308","state":"New York308","zip":"19203308","country":"United States308","phone":"123-455-6753308","email":"test@gmail.com308"},{"firstName":"Jose309","lastName":"Garcia309","city":"New York309","state":"New York309","zip":"19203309","country":"United States309","phone":"123-455-6753309","email":"test@gmail.com309"},{"firstName":"Jose310","lastName":"Garcia310","city":"New York310","state":"New York310","zip":"19203310","country":"United States310","phone":"123-455-6753310","email":"test@gmail.com310"},{"firstName":"Jose311","lastName":"Garcia311","city":"New York311","state":"New York311","zip":"19203311","country":"United States311","phone":"123-455-6753311","email":"test@gmail.com311"},{"firstName":"Jose312","lastName":"Garcia312","city":"New York312","state":"New York312","zip":"19203312","country":"United States312","phone":"123-455-6753312","email":"test@gmail.com312"},{"firstName":"Jose313","lastName":"Garcia313","city":"New York313","state":"New York313","zip":"19203313","country":"United States313","phone":"123-455-6753313","email":"test@gmail.com313"},{"firstName":"Jose314","lastName":"Garcia314","city":"New York314","state":"New York314","zip":"19203314","country":"United States314","phone":"123-455-6753314","email":"test@gmail.com314"},{"firstName":"Jose315","lastName":"Garcia315","city":"New York315","state":"New York315","zip":"19203315","country":"United States315","phone":"123-455-6753315","email":"test@gmail.com315"},{"firstName":"Jose316","lastName":"Garcia316","city":"New York316","state":"New York316","zip":"19203316","country":"United States316","phone":"123-455-6753316","email":"test@gmail.com316"},{"firstName":"Jose317","lastName":"Garcia317","city":"New York317","state":"New York317","zip":"19203317","country":"United States317","phone":"123-455-6753317","email":"test@gmail.com317"},{"firstName":"Jose318","lastName":"Garcia318","city":"New York318","state":"New York318","zip":"19203318","country":"United States318","phone":"123-455-6753318","email":"test@gmail.com318"},{"firstName":"Jose319","lastName":"Garcia319","city":"New York319","state":"New York319","zip":"19203319","country":"United States319","phone":"123-455-6753319","email":"test@gmail.com319"},{"firstName":"Jose320","lastName":"Garcia320","city":"New York320","state":"New York320","zip":"19203320","country":"United States320","phone":"123-455-6753320","email":"test@gmail.com320"},{"firstName":"Jose321","lastName":"Garcia321","city":"New York321","state":"New York321","zip":"19203321","country":"United States321","phone":"123-455-6753321","email":"test@gmail.com321"},{"firstName":"Jose322","lastName":"Garcia322","city":"New York322","state":"New York322","zip":"19203322","country":"United States322","phone":"123-455-6753322","email":"test@gmail.com322"},{"firstName":"Jose323","lastName":"Garcia323","city":"New York323","state":"New York323","zip":"19203323","country":"United States323","phone":"123-455-6753323","email":"test@gmail.com323"},{"firstName":"Jose324","lastName":"Garcia324","city":"New York324","state":"New York324","zip":"19203324","country":"United States324","phone":"123-455-6753324","email":"test@gmail.com324"},{"firstName":"Jose325","lastName":"Garcia325","city":"New York325","state":"New York325","zip":"19203325","country":"United States325","phone":"123-455-6753325","email":"test@gmail.com325"},{"firstName":"Jose326","lastName":"Garcia326","city":"New York326","state":"New York326","zip":"19203326","country":"United States326","phone":"123-455-6753326","email":"test@gmail.com326"},{"firstName":"Jose327","lastName":"Garcia327","city":"New York327","state":"New York327","zip":"19203327","country":"United States327","phone":"123-455-6753327","email":"test@gmail.com327"},{"firstName":"Jose328","lastName":"Garcia328","city":"New York328","state":"New York328","zip":"19203328","country":"United States328","phone":"123-455-6753328","email":"test@gmail.com328"},{"firstName":"Jose329","lastName":"Garcia329","city":"New York329","state":"New York329","zip":"19203329","country":"United States329","phone":"123-455-6753329","email":"test@gmail.com329"},{"firstName":"Jose330","lastName":"Garcia330","city":"New York330","state":"New York330","zip":"19203330","country":"United States330","phone":"123-455-6753330","email":"test@gmail.com330"},{"firstName":"Jose331","lastName":"Garcia331","city":"New York331","state":"New York331","zip":"19203331","country":"United States331","phone":"123-455-6753331","email":"test@gmail.com331"},{"firstName":"Jose332","lastName":"Garcia332","city":"New York332","state":"New York332","zip":"19203332","country":"United States332","phone":"123-455-6753332","email":"test@gmail.com332"},{"firstName":"Jose333","lastName":"Garcia333","city":"New York333","state":"New York333","zip":"19203333","country":"United States333","phone":"123-455-6753333","email":"test@gmail.com333"},{"firstName":"Jose334","lastName":"Garcia334","city":"New York334","state":"New York334","zip":"19203334","country":"United States334","phone":"123-455-6753334","email":"test@gmail.com334"},{"firstName":"Jose335","lastName":"Garcia335","city":"New York335","state":"New York335","zip":"19203335","country":"United States335","phone":"123-455-6753335","email":"test@gmail.com335"},{"firstName":"Jose336","lastName":"Garcia336","city":"New York336","state":"New York336","zip":"19203336","country":"United States336","phone":"123-455-6753336","email":"test@gmail.com336"},{"firstName":"Jose337","lastName":"Garcia337","city":"New York337","state":"New York337","zip":"19203337","country":"United States337","phone":"123-455-6753337","email":"test@gmail.com337"},{"firstName":"Jose338","lastName":"Garcia338","city":"New York338","state":"New York338","zip":"19203338","country":"United States338","phone":"123-455-6753338","email":"test@gmail.com338"},{"firstName":"Jose339","lastName":"Garcia339","city":"New York339","state":"New York339","zip":"19203339","country":"United States339","phone":"123-455-6753339","email":"test@gmail.com339"},{"firstName":"Jose340","lastName":"Garcia340","city":"New York340","state":"New York340","zip":"19203340","country":"United States340","phone":"123-455-6753340","email":"test@gmail.com340"},{"firstName":"Jose341","lastName":"Garcia341","city":"New York341","state":"New York341","zip":"19203341","country":"United States341","phone":"123-455-6753341","email":"test@gmail.com341"},{"firstName":"Jose342","lastName":"Garcia342","city":"New York342","state":"New York342","zip":"19203342","country":"United States342","phone":"123-455-6753342","email":"test@gmail.com342"},{"firstName":"Jose343","lastName":"Garcia343","city":"New York343","state":"New York343","zip":"19203343","country":"United States343","phone":"123-455-6753343","email":"test@gmail.com343"},{"firstName":"Jose344","lastName":"Garcia344","city":"New York344","state":"New York344","zip":"19203344","country":"United States344","phone":"123-455-6753344","email":"test@gmail.com344"},{"firstName":"Jose345","lastName":"Garcia345","city":"New York345","state":"New York345","zip":"19203345","country":"United States345","phone":"123-455-6753345","email":"test@gmail.com345"},{"firstName":"Jose346","lastName":"Garcia346","city":"New York346","state":"New York346","zip":"19203346","country":"United States346","phone":"123-455-6753346","email":"test@gmail.com346"},{"firstName":"Jose347","lastName":"Garcia347","city":"New York347","state":"New York347","zip":"19203347","country":"United States347","phone":"123-455-6753347","email":"test@gmail.com347"},{"firstName":"Jose348","lastName":"Garcia348","city":"New York348","state":"New York348","zip":"19203348","country":"United States348","phone":"123-455-6753348","email":"test@gmail.com348"},{"firstName":"Jose349","lastName":"Garcia349","city":"New York349","state":"New York349","zip":"19203349","country":"United States349","phone":"123-455-6753349","email":"test@gmail.com349"},{"firstName":"Jose350","lastName":"Garcia350","city":"New York350","state":"New York350","zip":"19203350","country":"United States350","phone":"123-455-6753350","email":"test@gmail.com350"},{"firstName":"Jose351","lastName":"Garcia351","city":"New York351","state":"New York351","zip":"19203351","country":"United States351","phone":"123-455-6753351","email":"test@gmail.com351"},{"firstName":"Jose352","lastName":"Garcia352","city":"New York352","state":"New York352","zip":"19203352","country":"United States352","phone":"123-455-6753352","email":"test@gmail.com352"},{"firstName":"Jose353","lastName":"Garcia353","city":"New York353","state":"New York353","zip":"19203353","country":"United States353","phone":"123-455-6753353","email":"test@gmail.com353"},{"firstName":"Jose354","lastName":"Garcia354","city":"New York354","state":"New York354","zip":"19203354","country":"United States354","phone":"123-455-6753354","email":"test@gmail.com354"},{"firstName":"Jose355","lastName":"Garcia355","city":"New York355","state":"New York355","zip":"19203355","country":"United States355","phone":"123-455-6753355","email":"test@gmail.com355"},{"firstName":"Jose356","lastName":"Garcia356","city":"New York356","state":"New York356","zip":"19203356","country":"United States356","phone":"123-455-6753356","email":"test@gmail.com356"},{"firstName":"Jose357","lastName":"Garcia357","city":"New York357","state":"New York357","zip":"19203357","country":"United States357","phone":"123-455-6753357","email":"test@gmail.com357"},{"firstName":"Jose358","lastName":"Garcia358","city":"New York358","state":"New York358","zip":"19203358","country":"United States358","phone":"123-455-6753358","email":"test@gmail.com358"},{"firstName":"Jose359","lastName":"Garcia359","city":"New York359","state":"New York359","zip":"19203359","country":"United States359","phone":"123-455-6753359","email":"test@gmail.com359"},{"firstName":"Jose360","lastName":"Garcia360","city":"New York360","state":"New York360","zip":"19203360","country":"United States360","phone":"123-455-6753360","email":"test@gmail.com360"},{"firstName":"Jose361","lastName":"Garcia361","city":"New York361","state":"New York361","zip":"19203361","country":"United States361","phone":"123-455-6753361","email":"test@gmail.com361"},{"firstName":"Jose362","lastName":"Garcia362","city":"New York362","state":"New York362","zip":"19203362","country":"United States362","phone":"123-455-6753362","email":"test@gmail.com362"},{"firstName":"Jose363","lastName":"Garcia363","city":"New York363","state":"New York363","zip":"19203363","country":"United States363","phone":"123-455-6753363","email":"test@gmail.com363"},{"firstName":"Jose364","lastName":"Garcia364","city":"New York364","state":"New York364","zip":"19203364","country":"United States364","phone":"123-455-6753364","email":"test@gmail.com364"},{"firstName":"Jose365","lastName":"Garcia365","city":"New York365","state":"New York365","zip":"19203365","country":"United States365","phone":"123-455-6753365","email":"test@gmail.com365"},{"firstName":"Jose366","lastName":"Garcia366","city":"New York366","state":"New York366","zip":"19203366","country":"United States366","phone":"123-455-6753366","email":"test@gmail.com366"},{"firstName":"Jose367","lastName":"Garcia367","city":"New York367","state":"New York367","zip":"19203367","country":"United States367","phone":"123-455-6753367","email":"test@gmail.com367"},{"firstName":"Jose368","lastName":"Garcia368","city":"New York368","state":"New York368","zip":"19203368","country":"United States368","phone":"123-455-6753368","email":"test@gmail.com368"},{"firstName":"Jose369","lastName":"Garcia369","city":"New York369","state":"New York369","zip":"19203369","country":"United States369","phone":"123-455-6753369","email":"test@gmail.com369"},{"firstName":"Jose370","lastName":"Garcia370","city":"New York370","state":"New York370","zip":"19203370","country":"United States370","phone":"123-455-6753370","email":"test@gmail.com370"},{"firstName":"Jose371","lastName":"Garcia371","city":"New York371","state":"New York371","zip":"19203371","country":"United States371","phone":"123-455-6753371","email":"test@gmail.com371"},{"firstName":"Jose372","lastName":"Garcia372","city":"New York372","state":"New York372","zip":"19203372","country":"United States372","phone":"123-455-6753372","email":"test@gmail.com372"},{"firstName":"Jose373","lastName":"Garcia373","city":"New York373","state":"New York373","zip":"19203373","country":"United States373","phone":"123-455-6753373","email":"test@gmail.com373"},{"firstName":"Jose374","lastName":"Garcia374","city":"New York374","state":"New York374","zip":"19203374","country":"United States374","phone":"123-455-6753374","email":"test@gmail.com374"},{"firstName":"Jose375","lastName":"Garcia375","city":"New York375","state":"New York375","zip":"19203375","country":"United States375","phone":"123-455-6753375","email":"test@gmail.com375"},{"firstName":"Jose376","lastName":"Garcia376","city":"New York376","state":"New York376","zip":"19203376","country":"United States376","phone":"123-455-6753376","email":"test@gmail.com376"},{"firstName":"Jose377","lastName":"Garcia377","city":"New York377","state":"New York377","zip":"19203377","country":"United States377","phone":"123-455-6753377","email":"test@gmail.com377"},{"firstName":"Jose378","lastName":"Garcia378","city":"New York378","state":"New York378","zip":"19203378","country":"United States378","phone":"123-455-6753378","email":"test@gmail.com378"},{"firstName":"Jose379","lastName":"Garcia379","city":"New York379","state":"New York379","zip":"19203379","country":"United States379","phone":"123-455-6753379","email":"test@gmail.com379"},{"firstName":"Jose380","lastName":"Garcia380","city":"New York380","state":"New York380","zip":"19203380","country":"United States380","phone":"123-455-6753380","email":"test@gmail.com380"},{"firstName":"Jose381","lastName":"Garcia381","city":"New York381","state":"New York381","zip":"19203381","country":"United States381","phone":"123-455-6753381","email":"test@gmail.com381"},{"firstName":"Jose382","lastName":"Garcia382","city":"New York382","state":"New York382","zip":"19203382","country":"United States382","phone":"123-455-6753382","email":"test@gmail.com382"},{"firstName":"Jose383","lastName":"Garcia383","city":"New York383","state":"New York383","zip":"19203383","country":"United States383","phone":"123-455-6753383","email":"test@gmail.com383"},{"firstName":"Jose384","lastName":"Garcia384","city":"New York384","state":"New York384","zip":"19203384","country":"United States384","phone":"123-455-6753384","email":"test@gmail.com384"},{"firstName":"Jose385","lastName":"Garcia385","city":"New York385","state":"New York385","zip":"19203385","country":"United States385","phone":"123-455-6753385","email":"test@gmail.com385"},{"firstName":"Jose386","lastName":"Garcia386","city":"New York386","state":"New York386","zip":"19203386","country":"United States386","phone":"123-455-6753386","email":"test@gmail.com386"},{"firstName":"Jose387","lastName":"Garcia387","city":"New York387","state":"New York387","zip":"19203387","country":"United States387","phone":"123-455-6753387","email":"test@gmail.com387"},{"firstName":"Jose388","lastName":"Garcia388","city":"New York388","state":"New York388","zip":"19203388","country":"United States388","phone":"123-455-6753388","email":"test@gmail.com388"},{"firstName":"Jose389","lastName":"Garcia389","city":"New York389","state":"New York389","zip":"19203389","country":"United States389","phone":"123-455-6753389","email":"test@gmail.com389"},{"firstName":"Jose390","lastName":"Garcia390","city":"New York390","state":"New York390","zip":"19203390","country":"United States390","phone":"123-455-6753390","email":"test@gmail.com390"},{"firstName":"Jose391","lastName":"Garcia391","city":"New York391","state":"New York391","zip":"19203391","country":"United States391","phone":"123-455-6753391","email":"test@gmail.com391"},{"firstName":"Jose392","lastName":"Garcia392","city":"New York392","state":"New York392","zip":"19203392","country":"United States392","phone":"123-455-6753392","email":"test@gmail.com392"},{"firstName":"Jose393","lastName":"Garcia393","city":"New York393","state":"New York393","zip":"19203393","country":"United States393","phone":"123-455-6753393","email":"test@gmail.com393"},{"firstName":"Jose394","lastName":"Garcia394","city":"New York394","state":"New York394","zip":"19203394","country":"United States394","phone":"123-455-6753394","email":"test@gmail.com394"},{"firstName":"Jose395","lastName":"Garcia395","city":"New York395","state":"New York395","zip":"19203395","country":"United States395","phone":"123-455-6753395","email":"test@gmail.com395"},{"firstName":"Jose396","lastName":"Garcia396","city":"New York396","state":"New York396","zip":"19203396","country":"United States396","phone":"123-455-6753396","email":"test@gmail.com396"},{"firstName":"Jose397","lastName":"Garcia397","city":"New York397","state":"New York397","zip":"19203397","country":"United States397","phone":"123-455-6753397","email":"test@gmail.com397"},{"firstName":"Jose398","lastName":"Garcia398","city":"New York398","state":"New York398","zip":"19203398","country":"United States398","phone":"123-455-6753398","email":"test@gmail.com398"},{"firstName":"Jose399","lastName":"Garcia399","city":"New York399","state":"New York399","zip":"19203399","country":"United States399","phone":"123-455-6753399","email":"test@gmail.com399"},{"firstName":"Jose400","lastName":"Garcia400","city":"New York400","state":"New York400","zip":"19203400","country":"United States400","phone":"123-455-6753400","email":"test@gmail.com400"},{"firstName":"Jose401","lastName":"Garcia401","city":"New York401","state":"New York401","zip":"19203401","country":"United States401","phone":"123-455-6753401","email":"test@gmail.com401"},{"firstName":"Jose402","lastName":"Garcia402","city":"New York402","state":"New York402","zip":"19203402","country":"United States402","phone":"123-455-6753402","email":"test@gmail.com402"},{"firstName":"Jose403","lastName":"Garcia403","city":"New York403","state":"New York403","zip":"19203403","country":"United States403","phone":"123-455-6753403","email":"test@gmail.com403"},{"firstName":"Jose404","lastName":"Garcia404","city":"New York404","state":"New York404","zip":"19203404","country":"United States404","phone":"123-455-6753404","email":"test@gmail.com404"},{"firstName":"Jose405","lastName":"Garcia405","city":"New York405","state":"New York405","zip":"19203405","country":"United States405","phone":"123-455-6753405","email":"test@gmail.com405"},{"firstName":"Jose406","lastName":"Garcia406","city":"New York406","state":"New York406","zip":"19203406","country":"United States406","phone":"123-455-6753406","email":"test@gmail.com406"},{"firstName":"Jose407","lastName":"Garcia407","city":"New York407","state":"New York407","zip":"19203407","country":"United States407","phone":"123-455-6753407","email":"test@gmail.com407"},{"firstName":"Jose408","lastName":"Garcia408","city":"New York408","state":"New York408","zip":"19203408","country":"United States408","phone":"123-455-6753408","email":"test@gmail.com408"},{"firstName":"Jose409","lastName":"Garcia409","city":"New York409","state":"New York409","zip":"19203409","country":"United States409","phone":"123-455-6753409","email":"test@gmail.com409"},{"firstName":"Jose410","lastName":"Garcia410","city":"New York410","state":"New York410","zip":"19203410","country":"United States410","phone":"123-455-6753410","email":"test@gmail.com410"},{"firstName":"Jose411","lastName":"Garcia411","city":"New York411","state":"New York411","zip":"19203411","country":"United States411","phone":"123-455-6753411","email":"test@gmail.com411"},{"firstName":"Jose412","lastName":"Garcia412","city":"New York412","state":"New York412","zip":"19203412","country":"United States412","phone":"123-455-6753412","email":"test@gmail.com412"},{"firstName":"Jose413","lastName":"Garcia413","city":"New York413","state":"New York413","zip":"19203413","country":"United States413","phone":"123-455-6753413","email":"test@gmail.com413"},{"firstName":"Jose414","lastName":"Garcia414","city":"New York414","state":"New York414","zip":"19203414","country":"United States414","phone":"123-455-6753414","email":"test@gmail.com414"},{"firstName":"Jose415","lastName":"Garcia415","city":"New York415","state":"New York415","zip":"19203415","country":"United States415","phone":"123-455-6753415","email":"test@gmail.com415"},{"firstName":"Jose416","lastName":"Garcia416","city":"New York416","state":"New York416","zip":"19203416","country":"United States416","phone":"123-455-6753416","email":"test@gmail.com416"},{"firstName":"Jose417","lastName":"Garcia417","city":"New York417","state":"New York417","zip":"19203417","country":"United States417","phone":"123-455-6753417","email":"test@gmail.com417"},{"firstName":"Jose418","lastName":"Garcia418","city":"New York418","state":"New York418","zip":"19203418","country":"United States418","phone":"123-455-6753418","email":"test@gmail.com418"},{"firstName":"Jose419","lastName":"Garcia419","city":"New York419","state":"New York419","zip":"19203419","country":"United States419","phone":"123-455-6753419","email":"test@gmail.com419"},{"firstName":"Jose420","lastName":"Garcia420","city":"New York420","state":"New York420","zip":"19203420","country":"United States420","phone":"123-455-6753420","email":"test@gmail.com420"},{"firstName":"Jose421","lastName":"Garcia421","city":"New York421","state":"New York421","zip":"19203421","country":"United States421","phone":"123-455-6753421","email":"test@gmail.com421"},{"firstName":"Jose422","lastName":"Garcia422","city":"New York422","state":"New York422","zip":"19203422","country":"United States422","phone":"123-455-6753422","email":"test@gmail.com422"},{"firstName":"Jose423","lastName":"Garcia423","city":"New York423","state":"New York423","zip":"19203423","country":"United States423","phone":"123-455-6753423","email":"test@gmail.com423"},{"firstName":"Jose424","lastName":"Garcia424","city":"New York424","state":"New York424","zip":"19203424","country":"United States424","phone":"123-455-6753424","email":"test@gmail.com424"},{"firstName":"Jose425","lastName":"Garcia425","city":"New York425","state":"New York425","zip":"19203425","country":"United States425","phone":"123-455-6753425","email":"test@gmail.com425"},{"firstName":"Jose426","lastName":"Garcia426","city":"New York426","state":"New York426","zip":"19203426","country":"United States426","phone":"123-455-6753426","email":"test@gmail.com426"},{"firstName":"Jose427","lastName":"Garcia427","city":"New York427","state":"New York427","zip":"19203427","country":"United States427","phone":"123-455-6753427","email":"test@gmail.com427"},{"firstName":"Jose428","lastName":"Garcia428","city":"New York428","state":"New York428","zip":"19203428","country":"United States428","phone":"123-455-6753428","email":"test@gmail.com428"},{"firstName":"Jose429","lastName":"Garcia429","city":"New York429","state":"New York429","zip":"19203429","country":"United States429","phone":"123-455-6753429","email":"test@gmail.com429"},{"firstName":"Jose430","lastName":"Garcia430","city":"New York430","state":"New York430","zip":"19203430","country":"United States430","phone":"123-455-6753430","email":"test@gmail.com430"},{"firstName":"Jose431","lastName":"Garcia431","city":"New York431","state":"New York431","zip":"19203431","country":"United States431","phone":"123-455-6753431","email":"test@gmail.com431"},{"firstName":"Jose432","lastName":"Garcia432","city":"New York432","state":"New York432","zip":"19203432","country":"United States432","phone":"123-455-6753432","email":"test@gmail.com432"},{"firstName":"Jose433","lastName":"Garcia433","city":"New York433","state":"New York433","zip":"19203433","country":"United States433","phone":"123-455-6753433","email":"test@gmail.com433"},{"firstName":"Jose434","lastName":"Garcia434","city":"New York434","state":"New York434","zip":"19203434","country":"United States434","phone":"123-455-6753434","email":"test@gmail.com434"},{"firstName":"Jose435","lastName":"Garcia435","city":"New York435","state":"New York435","zip":"19203435","country":"United States435","phone":"123-455-6753435","email":"test@gmail.com435"},{"firstName":"Jose436","lastName":"Garcia436","city":"New York436","state":"New York436","zip":"19203436","country":"United States436","phone":"123-455-6753436","email":"test@gmail.com436"},{"firstName":"Jose437","lastName":"Garcia437","city":"New York437","state":"New York437","zip":"19203437","country":"United States437","phone":"123-455-6753437","email":"test@gmail.com437"},{"firstName":"Jose438","lastName":"Garcia438","city":"New York438","state":"New York438","zip":"19203438","country":"United States438","phone":"123-455-6753438","email":"test@gmail.com438"},{"firstName":"Jose439","lastName":"Garcia439","city":"New York439","state":"New York439","zip":"19203439","country":"United States439","phone":"123-455-6753439","email":"test@gmail.com439"},{"firstName":"Jose440","lastName":"Garcia440","city":"New York440","state":"New York440","zip":"19203440","country":"United States440","phone":"123-455-6753440","email":"test@gmail.com440"},{"firstName":"Jose441","lastName":"Garcia441","city":"New York441","state":"New York441","zip":"19203441","country":"United States441","phone":"123-455-6753441","email":"test@gmail.com441"},{"firstName":"Jose442","lastName":"Garcia442","city":"New York442","state":"New York442","zip":"19203442","country":"United States442","phone":"123-455-6753442","email":"test@gmail.com442"},{"firstName":"Jose443","lastName":"Garcia443","city":"New York443","state":"New York443","zip":"19203443","country":"United States443","phone":"123-455-6753443","email":"test@gmail.com443"},{"firstName":"Jose444","lastName":"Garcia444","city":"New York444","state":"New York444","zip":"19203444","country":"United States444","phone":"123-455-6753444","email":"test@gmail.com444"},{"firstName":"Jose445","lastName":"Garcia445","city":"New York445","state":"New York445","zip":"19203445","country":"United States445","phone":"123-455-6753445","email":"test@gmail.com445"},{"firstName":"Jose446","lastName":"Garcia446","city":"New York446","state":"New York446","zip":"19203446","country":"United States446","phone":"123-455-6753446","email":"test@gmail.com446"},{"firstName":"Jose447","lastName":"Garcia447","city":"New York447","state":"New York447","zip":"19203447","country":"United States447","phone":"123-455-6753447","email":"test@gmail.com447"},{"firstName":"Jose448","lastName":"Garcia448","city":"New York448","state":"New York448","zip":"19203448","country":"United States448","phone":"123-455-6753448","email":"test@gmail.com448"},{"firstName":"Jose449","lastName":"Garcia449","city":"New York449","state":"New York449","zip":"19203449","country":"United States449","phone":"123-455-6753449","email":"test@gmail.com449"},{"firstName":"Jose450","lastName":"Garcia450","city":"New York450","state":"New York450","zip":"19203450","country":"United States450","phone":"123-455-6753450","email":"test@gmail.com450"},{"firstName":"Jose451","lastName":"Garcia451","city":"New York451","state":"New York451","zip":"19203451","country":"United States451","phone":"123-455-6753451","email":"test@gmail.com451"},{"firstName":"Jose452","lastName":"Garcia452","city":"New York452","state":"New York452","zip":"19203452","country":"United States452","phone":"123-455-6753452","email":"test@gmail.com452"},{"firstName":"Jose453","lastName":"Garcia453","city":"New York453","state":"New York453","zip":"19203453","country":"United States453","phone":"123-455-6753453","email":"test@gmail.com453"},{"firstName":"Jose454","lastName":"Garcia454","city":"New York454","state":"New York454","zip":"19203454","country":"United States454","phone":"123-455-6753454","email":"test@gmail.com454"},{"firstName":"Jose455","lastName":"Garcia455","city":"New York455","state":"New York455","zip":"19203455","country":"United States455","phone":"123-455-6753455","email":"test@gmail.com455"},{"firstName":"Jose456","lastName":"Garcia456","city":"New York456","state":"New York456","zip":"19203456","country":"United States456","phone":"123-455-6753456","email":"test@gmail.com456"},{"firstName":"Jose457","lastName":"Garcia457","city":"New York457","state":"New York457","zip":"19203457","country":"United States457","phone":"123-455-6753457","email":"test@gmail.com457"},{"firstName":"Jose458","lastName":"Garcia458","city":"New York458","state":"New York458","zip":"19203458","country":"United States458","phone":"123-455-6753458","email":"test@gmail.com458"},{"firstName":"Jose459","lastName":"Garcia459","city":"New York459","state":"New York459","zip":"19203459","country":"United States459","phone":"123-455-6753459","email":"test@gmail.com459"},{"firstName":"Jose460","lastName":"Garcia460","city":"New York460","state":"New York460","zip":"19203460","country":"United States460","phone":"123-455-6753460","email":"test@gmail.com460"},{"firstName":"Jose461","lastName":"Garcia461","city":"New York461","state":"New York461","zip":"19203461","country":"United States461","phone":"123-455-6753461","email":"test@gmail.com461"},{"firstName":"Jose462","lastName":"Garcia462","city":"New York462","state":"New York462","zip":"19203462","country":"United States462","phone":"123-455-6753462","email":"test@gmail.com462"},{"firstName":"Jose463","lastName":"Garcia463","city":"New York463","state":"New York463","zip":"19203463","country":"United States463","phone":"123-455-6753463","email":"test@gmail.com463"},{"firstName":"Jose464","lastName":"Garcia464","city":"New York464","state":"New York464","zip":"19203464","country":"United States464","phone":"123-455-6753464","email":"test@gmail.com464"},{"firstName":"Jose465","lastName":"Garcia465","city":"New York465","state":"New York465","zip":"19203465","country":"United States465","phone":"123-455-6753465","email":"test@gmail.com465"},{"firstName":"Jose466","lastName":"Garcia466","city":"New York466","state":"New York466","zip":"19203466","country":"United States466","phone":"123-455-6753466","email":"test@gmail.com466"},{"firstName":"Jose467","lastName":"Garcia467","city":"New York467","state":"New York467","zip":"19203467","country":"United States467","phone":"123-455-6753467","email":"test@gmail.com467"},{"firstName":"Jose468","lastName":"Garcia468","city":"New York468","state":"New York468","zip":"19203468","country":"United States468","phone":"123-455-6753468","email":"test@gmail.com468"},{"firstName":"Jose469","lastName":"Garcia469","city":"New York469","state":"New York469","zip":"19203469","country":"United States469","phone":"123-455-6753469","email":"test@gmail.com469"},{"firstName":"Jose470","lastName":"Garcia470","city":"New York470","state":"New York470","zip":"19203470","country":"United States470","phone":"123-455-6753470","email":"test@gmail.com470"},{"firstName":"Jose471","lastName":"Garcia471","city":"New York471","state":"New York471","zip":"19203471","country":"United States471","phone":"123-455-6753471","email":"test@gmail.com471"},{"firstName":"Jose472","lastName":"Garcia472","city":"New York472","state":"New York472","zip":"19203472","country":"United States472","phone":"123-455-6753472","email":"test@gmail.com472"},{"firstName":"Jose473","lastName":"Garcia473","city":"New York473","state":"New York473","zip":"19203473","country":"United States473","phone":"123-455-6753473","email":"test@gmail.com473"},{"firstName":"Jose474","lastName":"Garcia474","city":"New York474","state":"New York474","zip":"19203474","country":"United States474","phone":"123-455-6753474","email":"test@gmail.com474"},{"firstName":"Jose475","lastName":"Garcia475","city":"New York475","state":"New York475","zip":"19203475","country":"United States475","phone":"123-455-6753475","email":"test@gmail.com475"},{"firstName":"Jose476","lastName":"Garcia476","city":"New York476","state":"New York476","zip":"19203476","country":"United States476","phone":"123-455-6753476","email":"test@gmail.com476"},{"firstName":"Jose477","lastName":"Garcia477","city":"New York477","state":"New York477","zip":"19203477","country":"United States477","phone":"123-455-6753477","email":"test@gmail.com477"},{"firstName":"Jose478","lastName":"Garcia478","city":"New York478","state":"New York478","zip":"19203478","country":"United States478","phone":"123-455-6753478","email":"test@gmail.com478"},{"firstName":"Jose479","lastName":"Garcia479","city":"New York479","state":"New York479","zip":"19203479","country":"United States479","phone":"123-455-6753479","email":"test@gmail.com479"},{"firstName":"Jose480","lastName":"Garcia480","city":"New York480","state":"New York480","zip":"19203480","country":"United States480","phone":"123-455-6753480","email":"test@gmail.com480"},{"firstName":"Jose481","lastName":"Garcia481","city":"New York481","state":"New York481","zip":"19203481","country":"United States481","phone":"123-455-6753481","email":"test@gmail.com481"},{"firstName":"Jose482","lastName":"Garcia482","city":"New York482","state":"New York482","zip":"19203482","country":"United States482","phone":"123-455-6753482","email":"test@gmail.com482"},{"firstName":"Jose483","lastName":"Garcia483","city":"New York483","state":"New York483","zip":"19203483","country":"United States483","phone":"123-455-6753483","email":"test@gmail.com483"},{"firstName":"Jose484","lastName":"Garcia484","city":"New York484","state":"New York484","zip":"19203484","country":"United States484","phone":"123-455-6753484","email":"test@gmail.com484"},{"firstName":"Jose485","lastName":"Garcia485","city":"New York485","state":"New York485","zip":"19203485","country":"United States485","phone":"123-455-6753485","email":"test@gmail.com485"},{"firstName":"Jose486","lastName":"Garcia486","city":"New York486","state":"New York486","zip":"19203486","country":"United States486","phone":"123-455-6753486","email":"test@gmail.com486"},{"firstName":"Jose487","lastName":"Garcia487","city":"New York487","state":"New York487","zip":"19203487","country":"United States487","phone":"123-455-6753487","email":"test@gmail.com487"},{"firstName":"Jose488","lastName":"Garcia488","city":"New York488","state":"New York488","zip":"19203488","country":"United States488","phone":"123-455-6753488","email":"test@gmail.com488"},{"firstName":"Jose489","lastName":"Garcia489","city":"New York489","state":"New York489","zip":"19203489","country":"United States489","phone":"123-455-6753489","email":"test@gmail.com489"},{"firstName":"Jose490","lastName":"Garcia490","city":"New York490","state":"New York490","zip":"19203490","country":"United States490","phone":"123-455-6753490","email":"test@gmail.com490"},{"firstName":"Jose491","lastName":"Garcia491","city":"New York491","state":"New York491","zip":"19203491","country":"United States491","phone":"123-455-6753491","email":"test@gmail.com491"},{"firstName":"Jose492","lastName":"Garcia492","city":"New York492","state":"New York492","zip":"19203492","country":"United States492","phone":"123-455-6753492","email":"test@gmail.com492"},{"firstName":"Jose493","lastName":"Garcia493","city":"New York493","state":"New York493","zip":"19203493","country":"United States493","phone":"123-455-6753493","email":"test@gmail.com493"},{"firstName":"Jose494","lastName":"Garcia494","city":"New York494","state":"New York494","zip":"19203494","country":"United States494","phone":"123-455-6753494","email":"test@gmail.com494"},{"firstName":"Jose495","lastName":"Garcia495","city":"New York495","state":"New York495","zip":"19203495","country":"United States495","phone":"123-455-6753495","email":"test@gmail.com495"},{"firstName":"Jose496","lastName":"Garcia496","city":"New York496","state":"New York496","zip":"19203496","country":"United States496","phone":"123-455-6753496","email":"test@gmail.com496"},{"firstName":"Jose497","lastName":"Garcia497","city":"New York497","state":"New York497","zip":"19203497","country":"United States497","phone":"123-455-6753497","email":"test@gmail.com497"},{"firstName":"Jose498","lastName":"Garcia498","city":"New York498","state":"New York498","zip":"19203498","country":"United States498","phone":"123-455-6753498","email":"test@gmail.com498"},{"firstName":"Jose499","lastName":"Garcia499","city":"New York499","state":"New York499","zip":"19203499","country":"United States499","phone":"123-455-6753499","email":"test@gmail.com499"}]; --------------------------------------------------------------------------------