├── .gitignore ├── .versions ├── README.md ├── ReactiveArray.js └── package.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.meteor/local 2 | /.git 3 | /.build 4 | /packages 5 | /c 6 | /p 7 | /*.iml 8 | /.idea 9 | /smart.lock -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | manuel:reactivearray@1.0.9 2 | meteor@1.8.2 3 | tracker@1.1.3 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reactive Array for Meteor 2 | 3 | This package provides a wrapper around the Array class to make it reactive. That means you can put your array inside a Tracker.autorun or a template helper and your app will be updated when items are added or removed from the array. 4 | 5 | ## Install 6 | 7 | ```bash 8 | meteor add manuel:reactivearray 9 | ``` 10 | 11 | ## Quick Usage 12 | 13 | ### Javascript 14 | 15 | ```js 16 | var blank = new ReactiveArray(); 17 | var names = new ReactiveArray(['Tom', 'Dick', 'Harry']); 18 | ``` 19 | 20 | ## List Example 21 | 22 | ![ReactiveArray list example](https://cloud.githubusercontent.com/assets/192261/17591107/f83fce54-5fb2-11e6-8469-9a499e0c5762.png) 23 | 24 | ### Code 25 | 26 | ```html 27 | 38 | ``` 39 | 40 | ```js 41 | var arr = new ReactiveArray(['Tom', 'Dick', 'Harry']); 42 | 43 | Template.listEx.helpers({ 44 | names: function() { 45 | return arr.list(); 46 | } 47 | }); 48 | 49 | Template.listEx.events({ 50 | 'click #listExAdd': function() { 51 | arr.push($('#listExName').val()); 52 | return $('#listExName').val(''); 53 | }, 54 | 'click .listExRemove': function() { 55 | return arr.remove(this.toString()); 56 | } 57 | }); 58 | ``` 59 | 60 | ## Native methods 61 | 62 | These functions are the reactive equivalent of the native Javascript array functions: 63 | 64 | - `concat(value1[, value2[, ...[, valueN]]])`
65 | Returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments. 66 | - `indexOf(searchElement[, fromIndex = 0])`
67 | Returns the first index at which a given element can be found in the array, or -1 if it is not present. 68 | - `join([separator = ','])`
69 | Joins all elements of an array into a string 70 | - `lastIndexOf(searchElement[, fromIndex = arr.length])`
71 | Returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards, starting at fromIndex. 72 | - `pop()`
73 | Removes the last element of an array, and returns that element 74 | - `push(element1, ..., elementN)`
75 | Adds new elements to the end of an array, and returns the new length 76 | - `reverse()`
77 | Reverses an array in place. The first array element becomes the last and the last becomes the first. 78 | - `shift()`
79 | Removes the first element from an array and returns that element. This method changes the length of the array. 80 | - `sort([compareFunction])`
81 | Sorts the elements of an array in place and returns the array. 82 | - `splice(index, howMany[, element1[, ...[, elementN]]])`
83 | Changes the content of an array, adding new elements while removing old elements. 84 | - `toString()`
85 | Returns a string representing the specified array and its elements. 86 | - `unshift([element1[, ...[, elementN]]])`
87 | Adds new elements to the beginning of an array and returns the new length. 88 | 89 | ## `.array()` method 90 | 91 | It returns all elements as a plain Javascript array. 92 | 93 | ```js 94 | reactiveArray.array() 95 | ``` 96 | 97 | #### Example 98 | 99 | ```js 100 | var names = new ReactiveArray(['John']); 101 | names.push('Jane'); 102 | names.array(); // ['John', 'Jane'] 103 | ``` 104 | 105 | ## `.list()` method 106 | 107 | It returns a reactive source of the array. An array variable isn't reactive by itself, you need to execute a function with `dependency.depend()` for Meteor to recognize it as a reactive source. The `.list()` method does just that. 108 | 109 | `.depend()` and `.list()` are synonyms. The reason for providing two methods that perform the same function is that sometimes it makes more sense to say "get me the (reactive) list of items in the array" and other times "this autorun depends on that array". 110 | 111 | ```js 112 | reactiveArray.list() 113 | ``` 114 | 115 | #### Example 116 | 117 | ```js 118 | var names = new ReactiveArray(['Tom', 'Dick', 'Harry']); 119 | 120 | Template.list.helpers({ 121 | names: function() { 122 | return names.list(); 123 | } 124 | }); 125 | ``` 126 | 127 | ## `.depend()` method 128 | 129 | It returns a reactive source of the array. An array variable isn't reactive by itself, you need to execute a function with `dependency.depend()` for Meteor to recognize it as a reactive source. The `.depend()` method does just that. 130 | 131 | `.depend()` and `.list()` are synonyms. The reason for providing two methods that perform the same function is that sometimes it makes more sense to say "get me the (reactive) list of items in the array" and other times "this autorun depends on that array". 132 | 133 | ```js 134 | reactiveArray.depend() 135 | ```` 136 | 137 | #### Example 138 | 139 | ```js 140 | var array = new ReactiveArray(); 141 | 142 | Tracker.autorun(function() { 143 | array.depend(); 144 | if (array.length > 0) { 145 | return console.log("The first item is: " + array[0]); 146 | } else { 147 | return console.log("The array is empty"); 148 | } 149 | }); 150 | 151 | array.push("car"); 152 | ``` 153 | 154 | ## `.clear()` method 155 | 156 | It removes all elements from the array. 157 | 158 | ```js 159 | array.clear() 160 | ``` 161 | 162 | #### Example 163 | 164 | ```js 165 | var array = new ReactiveArray(['a', 'b', 'c']); 166 | array.clear(); // [] 167 | ``` 168 | -------------------------------------------------------------------------------- /ReactiveArray.js: -------------------------------------------------------------------------------- 1 | ReactiveArray = function(p1, p2) { 2 | var _this = this; 3 | var dep, item, j, len, pause; 4 | dep = null; 5 | pause = false; 6 | _this = Array.apply(this, []); 7 | _this.changed = function() { 8 | if (dep && !pause) { 9 | return dep.changed(); 10 | } 11 | }; 12 | _this.depend = function() { 13 | return dep.depend(); 14 | }; 15 | if (p1 instanceof Array || Array.isArray(p1)) { 16 | for (j = 0, len = p1.length; j < len; j++) { 17 | item = p1[j]; 18 | _this.push(item); 19 | } 20 | dep = p2; 21 | } else { 22 | dep = p1; 23 | } 24 | if (!(dep instanceof Tracker.Dependency)) { 25 | dep = new Tracker.Dependency(); 26 | } 27 | _this.pause = function() { 28 | return (pause = true); 29 | }; 30 | _this.resume = function() { 31 | pause = false; 32 | return this.changed(); 33 | }; 34 | _this.array = function() { 35 | this.depend(); 36 | return Array.prototype.slice.call(this); 37 | }; 38 | _this.list = function() { 39 | this.depend(); 40 | return this; 41 | }; 42 | _this.push = function() { 43 | var item; 44 | item = Array.prototype.push.apply(this, arguments); 45 | this.changed(); 46 | return item; 47 | }; 48 | _this.unshift = function() { 49 | var item; 50 | item = Array.prototype.unshift.apply(this, arguments); 51 | this.changed(); 52 | return item; 53 | }; 54 | _this.pop = function() { 55 | var item; 56 | item = Array.prototype.pop.apply(this, arguments); 57 | this.changed(); 58 | return item; 59 | }; 60 | _this.shift = function() { 61 | var item; 62 | item = Array.prototype.shift.apply(this, arguments); 63 | this.changed(); 64 | return item; 65 | }; 66 | _this.remove = function(valueOrPredicate) { 67 | var i, predicate, removedValues, underlyingArray, value; 68 | underlyingArray = this; 69 | removedValues = []; 70 | predicate = 71 | typeof valueOrPredicate === "function" 72 | ? valueOrPredicate 73 | : function(value) { 74 | return value === valueOrPredicate; 75 | }; 76 | i = 0; 77 | while (i < underlyingArray.length) { 78 | value = underlyingArray[i]; 79 | if (predicate(value)) { 80 | removedValues.push(value); 81 | underlyingArray.splice(i, 1); 82 | i--; 83 | } 84 | i++; 85 | } 86 | return removedValues; 87 | }; 88 | _this.clear = function() { 89 | while (this.length) { 90 | this.pop(); 91 | } 92 | return this; 93 | }; 94 | _this.concat = function() { 95 | var a, j, len, ret; 96 | ret = this.array(); 97 | for (j = 0, len = arguments.length; j < len; j++) { 98 | a = arguments[j]; 99 | if (a instanceof ReactiveArray) { 100 | ret = ret.concat(a.array()); 101 | } else { 102 | ret = ret.concat(a); 103 | } 104 | } 105 | return new ReactiveArray(ret); 106 | }; 107 | _this.indexOf = function() { 108 | this.depend(); 109 | return Array.prototype.indexOf.apply(this, arguments); 110 | }; 111 | _this.join = function() { 112 | this.depend(); 113 | return Array.prototype.join.apply(this, arguments); 114 | }; 115 | _this.lastIndexOf = function() { 116 | this.depend(); 117 | return Array.prototype.lastIndexOf.apply(this, arguments); 118 | }; 119 | _this.reverse = function() { 120 | Array.prototype.reverse.apply(this, arguments); 121 | this.changed(); 122 | return this; 123 | }; 124 | _this.sort = function() { 125 | Array.prototype.sort.apply(this, arguments); 126 | this.changed(); 127 | return this; 128 | }; 129 | _this.splice = function() { 130 | var ret; 131 | ret = Array.prototype.splice.apply(this, arguments); 132 | this.changed(); 133 | return ret; 134 | }; 135 | return _this; 136 | }; 137 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: "manuel:reactivearray", 3 | summary: "Reactive Array for Meteor", 4 | version: "1.0.9", 5 | git: "https://github.com/ManuelDeLeon/ReactiveArray" 6 | }); 7 | 8 | Package.onUse(function(api) { 9 | api.versionsFrom("METEOR@1.6.1"); 10 | api.use(["tracker@1.1.3"]); 11 | api.addFiles(["ReactiveArray.js"], ["client", "server"]); 12 | api.export("ReactiveArray"); 13 | }); 14 | --------------------------------------------------------------------------------