Skip to content

Commit f271f4e

Browse files
committed
Merge branch 'master' of github.com:Urigo/angular-meteor
2 parents 04d5dcf + 248c372 commit f271f4e

File tree

11 files changed

+141
-42
lines changed

11 files changed

+141
-42
lines changed

.docs/angular-meteor/client/views/angular-2.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ <h4 class="sample-code">
165165
<div class="angular-2-option">
166166
<h2>Angular 2.0.0-alpha</h2>
167167
<p>
168-
An angualr2-meteor package with all the dependencies (TypeScript, System.js, etc...) so you can start writing Angular 2.0 code right away. written by - <a href="https://github.com/netanelgilad"><i class="fa fa-github"></i> @netanelgilad</a>.
168+
An angular2-meteor package with all the dependencies (TypeScript, System.js, etc...) so you can start writing Angular 2.0 code right away. written by - <a href="https://github.com/netanelgilad"><i class="fa fa-github"></i> @netanelgilad</a>.
169169
</p>
170170
</div>
171171
<div class="ctas">

.docs/angular-meteor/client/views/steps/tutorial.intro.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
No previous knowledge in Angular or Meteor is necessary.
2222

23-
We will walk you through building an Angular-Meteor app. Can't wait to see it? Here's the final version - [http://socially-step18.meteor.com/](http://socially-step18.meteor.com/). Don't forget to come back an go through this tutorial!
23+
We will walk you through building an Angular-Meteor app. Can't wait to see it? Here's the final version - [http://socially-step18.meteor.com/](http://socially-step18.meteor.com/). Don't forget to come back and go through this tutorial!
2424

2525
You can also participate in our free angular-meteor university and do the step by step exercises together with community members.
2626
Read more about the angular-meteor university [here](https://github.com/Urigo/meteor-angular-socially#angular-meteor-university-).

.docs/angular-meteor/client/views/steps/tutorial.step_00.html

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ <h1>Step 0 - Bootstrapping</h1>
5555

5656
So, as you can see, we have a full running app! which includes a server and a client.
5757

58-
But let's start from the beginning, please delete the following files:
58+
The default Meteor app starts life with three files, one 'js', one 'html' and one 'css' file. Each named with the application name you used in the 'create' command above, in our case this is 'socially'. We're going to add our own files for this tutorial. So let's start by deleting the following files:
5959

6060
socially.css socially.html socially.js
6161

@@ -72,7 +72,7 @@ <h1>Step 0 - Bootstrapping</h1>
7272
As you can see, there is no html tag, no head tag, very simple.
7373

7474

75-
The reason is the way Meteor structures and serves files to the client.
75+
The reason for this is the way Meteor structures and serves files to the client.
7676

7777
Meteor scans all the HTML files in your application and concatenates them together.
7878

@@ -120,53 +120,52 @@ <h1>Step 0 - Bootstrapping</h1>
120120
<div ng-include="'index.ng.html'"></div>
121121
</body>
122122

123-
But if you load this in your browser, you'll see nothing. That's because we still need to create the actual Angular app, which we'll do next.
123+
But if you load this in your browser, you won't see anything. That's because we still need to create the actual Angular app, which we'll do next.
124124

125-
* It's very important to note - all the paths are always absolute, not relative! so if 'index.ng.html' was inside a client folder, you would have to place the whole path from the route app, doesn't matter where you are
126-
calling the file from, like that:
125+
* It's very important to note - the paths are always absolute, not relative! so if 'index.ng.html' was inside a client folder, you would have to place the whole path from the route app, doesn't matter where you're calling the file from.
126+
127+
like this (e.g. if index.ng.html was in the 'client' folder):
127128

128129
<div ng-include="'client/index.ng.html'"></div>
129130

130131
# AngularJS app
131132

132-
AngularJS apps are actually individual modules so now we are going to create our app module.
133+
AngularJS apps are actually individual modules. So to start with lets create our app module.
133134

134-
Create a new app.js file. now you can see another example of Meteor's power and simplicity - no need to include this file anywhere. Meteor will take care of it by going through all the files in the folder and including them automatically.
135+
Create a new app.js file. Now you can see another example of Meteor's power and simplicity - no need to include this file anywhere. Meteor will take care of it by going through all the files in the folder and including them automatically.
135136

136-
But Meteor's goal is to break down the barrier between client and server, and the code you write runs everywhere! (more on that later).
137+
One of Meteor's goals is to break down the barrier between client and server, so the code you write can run everywhere! (more on that later).
137138
But we need Angular's power only in the client side, so how can we do that?
138139

139-
There are a few ways to tell Meteor to run a code only on the client/server/phone side, let's start with the simplest way - Meteor.isClient variable.
140+
There are a few ways to tell Meteor to run code only on the client/server/phone side, let's start with the simplest way - Meteor.isClient variable.
140141

141142
__`app.js`:__
142143

143144
if (Meteor.isClient) {
144145

145146
}
146147

147-
Now anything that will happen inside this if statement will run only on the client side.
148+
Now everything inside this 'if' statement will only run on the client side.
148149

149-
So let's continue with starting our AngularJS application, we will call it "socially":
150+
Let's continue defining our AngularJS application module, and give it the name "socially":
150151

151152
__`app.js`:__
152153

153154
if (Meteor.isClient) {
154155
angular.module('socially',['angular-meteor']);
155156
}
156157

157-
And name our application in the ng-app directive in index.html:
158+
And use the same application name in the ng-app directive in index.html:
158159

159160
<body ng-app="socially">
160161
<div ng-include="'index.ng.html'"></div>
161162
</body>
162163

163-
What we did here is to declare a new angular module named 'socially' and making it dependant on the 'angular-meteor' module (that we included in the first step).
164+
What we did here is to declare a new angular module named 'socially' and make it dependant on the 'angular-meteor' module (that we included in the first step).
164165

165166
Now run the app.
166167

167-
everything is the same.
168-
169-
and now inside our index.ng.html let's use Angular:
168+
Everything is the same, but now inside our index.ng.html let's use Angular:
170169

171170
<p>Nothing here {{dstache}} 'yet' + '!' }}</p>
172171

@@ -180,16 +179,16 @@ <h1>Step 0 - Bootstrapping</h1>
180179
* A binding, denoted by double curly braces {{dstache}} }}
181180
* a simple expression 'yet' + '!' used in this binding.
182181

183-
AngularJS finds those double curly braces, evaluates the expression and inserts the result into the DOM in place of the binding.
182+
AngularJS finds the double curly braces, evaluates the expression and inserts the result into the DOM in place of the binding.
184183
Rather than a one-time insert, as we'll see in the next steps, a binding will result in efficient continuous updates whenever the result of the expression evaluation changes.
185-
Inside in the client side, like a future smart browser would do.
184+
Inside in the client side code, like a future smart browser would do.
186185

187186

188-
> Why did use a new file extension file.ng.html ?
187+
> Why did we use the new file extension file.ng.html ?
189188
>
190-
> That is because Meteor templating system uses double-curlies. If we use them in our AngularJS view HTML, Meteor will override Angular.
189+
> That's because the Meteor templating system uses double-curlies. If we use them in our AngularJS view HTML, Meteor will override Angular.
191190
>
192-
> Fortunately, we created a new file extension to make Meteor not override our Angular expression.
191+
> Fortunately, we created a new file extension to stop Meteor overriding our Angular expression.
193192
>
194193
> If you still want to use HTML files without changing their extension, Angular (unlike Meteor...) gives us the [option to change the double-curlies to Double-square-brackets](http://stackoverflow.com/a/12923955/1426570)
195194

.docs/angular-meteor/client/views/steps/tutorial.step_05.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ <h1>
203203

204204
#### Common Mistakes
205205

206-
In case you won't enter the right absolute path (maybe by accident add a relative one), then you might be getting the folowwing error:
206+
In case you won't enter the right absolute path (maybe by accident add a relative one), then you might be getting the following error:
207207

208208
WARNING: Tried to load angular more than once.
209209

.docs/angular-meteor/client/views/steps/tutorial.step_08.html

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,10 @@ <h1>
9797
return userId && party.owner === userId;
9898
},
9999
update: function (userId, party, fields, modifier) {
100-
if (userId !== party.owner)
101-
return false;
102-
103-
return true;
100+
return userId && party.owner === userId;
104101
},
105102
remove: function (userId, party) {
106-
if (userId !== party.owner)
107-
return false;
108-
109-
return true;
103+
return userId && party.owner === userId;
110104
}
111105
});
112106

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 Uri Goldshtein
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.

lib/diff-array.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ var diffArray = function (lastSeqArray, seqArray, callbacks) {
9494
var newItem = seqArray[pos];
9595
var oldItem = lastSeqArray[posOld[idString]];
9696
var setDiff = diffObjectChanges(oldItem, newItem);
97-
var unsetDiff = diffObjectRemovals(oldItem, newItem);
97+
if (newItem)
98+
var unsetDiff = diffObjectRemovals(oldItem, newItem);
9899

99100
if (setDiff)
100101
setDiff._id = newItem._id;
@@ -139,6 +140,9 @@ var diffObjectChanges = function (oldItem, newItem) {
139140
if (oldItem && angular.equals(value, oldItem[key]))
140141
return;
141142

143+
if (key == '$$hashKey')
144+
return;
145+
142146
if (isActualObject(value)) {
143147
var diff = diffObjectChanges(oldItem[key], value);
144148
if (diff) result[key] = diff;
@@ -171,11 +175,15 @@ var diffObjectRemovals = function (oldItem, newItem) {
171175

172176
angular.forEach(oldItemKeys, function (key) {
173177
if (!_.contains(newItemKeys, key) ||
174-
angular.isUndefined(newItem[key]))
175-
result[key] = true;
178+
angular.isUndefined(newItem[key])){
179+
if (key != '$$hashKey')
180+
result[key] = true;
181+
}
176182
else if (isActualObject(oldItem[key])) {
177-
var diff = diffObjectRemovals(oldItem[key], newItem[key]);
178-
if (diff) result[key] = diff;
183+
if (key != '$$hashKey') {
184+
var diff = diffObjectRemovals(oldItem[key], newItem[key]);
185+
if (diff) result[key] = diff;
186+
}
179187
}
180188
});
181189

modules/angular-meteor-meteorCollection.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ angularMeteorCollections.factory('AngularMeteorCollection', ['$q', '$meteorSubsc
3030
var deferred = $q.defer();
3131

3232
// delete $$hashkey
33-
if (!(item instanceof File))
34-
item = $meteorUtils.stripDollarPrefixedKeys(item);
33+
item = $meteorUtils.stripDollarPrefixedKeys(item);
3534

3635
if (item._id) { // Performs an update if the _id property is set.
3736
var item_id = item._id; // Store the _id in temporary variable

modules/angular-meteor-utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ angularMeteorUtils.service('$meteorUtils', [ '$timeout',
2525
};
2626
// Borrowed from angularFire - https://github.com/firebase/angularfire/blob/master/src/utils.js#L445-L454
2727
this.stripDollarPrefixedKeys = function (data) {
28-
if( !angular.isObject(data) || data instanceof File || data instanceof Date) { return data; }
28+
if( !angular.isObject(data) || data instanceof File || (typeof FS === 'object' && data instanceof FS.File) || data instanceof Date) { return data; }
2929
var out = angular.isArray(data)? [] : {};
3030
angular.forEach(data, function(v,k) {
3131
if(typeof k !== 'string' || k.charAt(0) !== '$') {
3232
out[k] = self.stripDollarPrefixedKeys(v);
3333
}
3434
});
3535
return out;
36-
}
36+
};
3737
}]);
3838

3939
angularMeteorUtils.run(['$rootScope', '$meteorUtils',

tests/integration/angular-meteor-diff-array-spec.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('diffArray module', function() {
5050
}];
5151
var changedAtSpy = jasmine.createSpy('changedAt');
5252

53-
diffArray(oldCollection, newCollection, { changedAt: changedAtSpy });
53+
expect(function(){diffArray(oldCollection, newCollection, { changedAt: changedAtSpy })}).not.toThrow();
5454

5555
expect(changedAtSpy).toHaveBeenCalledWith(
5656
'a',
@@ -61,6 +61,39 @@ describe('diffArray module', function() {
6161
});
6262
});
6363

64+
describe('no exception on first compare and ignore $$hashkeys', function() {
65+
it('should notify callback with changedAt', function() {
66+
var oldCollection = [{
67+
_id: "a", date: new Date(1111, 1, 1), checked: true, $$hashKey: "object:4"
68+
},
69+
{
70+
_id: "b", date: new Date(2222, 2, 2), checked: true, $$hashKey: "object:6"
71+
},
72+
{
73+
_id: "c", date: new Date(2222, 2, 2), checked: true, $$hashKey: "object:8"
74+
}];
75+
var newCollection = [{
76+
_id: "a", date: new Date(1111, 1, 1), checked: true
77+
},
78+
{
79+
_id: "b", date: new Date(2222, 2, 2), checked: false
80+
},
81+
{
82+
_id: "c", date: new Date(2222, 2, 2), checked: true
83+
}];
84+
var changedAtSpy = jasmine.createSpy('changedAt');
85+
86+
expect(function(){diffArray(oldCollection, newCollection, { changedAt: changedAtSpy })}).not.toThrow();
87+
88+
expect(changedAtSpy).toHaveBeenCalledWith(
89+
'b',
90+
{checked: false, _id: "b"},
91+
undefined,
92+
1,
93+
jasmine.any(Object));
94+
});
95+
});
96+
6497
describe('deepCopyRemovals', function() {
6598
it('should handle fields that are false-y correctly', function() {
6699
var oldItem = {_id: 1, field : 0, another : 3};

0 commit comments

Comments
 (0)