Comments (11)
Have you looked at the new $methods service?
also the $subscribe service?
Can you also write a simple code of how would you want the service usage to look like?
from angular-meteor.
Unfortunately, due to an unrelated full-time day job, I just have not had the time to try angular-meteor in my own app yet. However, when I do, I think i will be following patterns I have seen other folk discuss for hooking up with other backend services, like this:
http://www.webdeveasy.com/angularjs-data-model/
and
Sorry - that's all I have right now....
from angular-meteor.
I've looked at the links you sent.
I think I understand.
So for example a user can create a 'Parties' service.
And then he can do Parties.add, Parties.remove, Parties.update, Parties.invite, Parties.rsvp
and inside it will encapsulate what is going on?
It fine. but I think that with angular-meteor there is less of a need for those then the other services.
you can directly manipulate the scope and that's it.. no need to worry about server
If you look for example at the PartyDetailsCtrl in the tutorial the only thing you need for changing the party is one line:
$collection(Parties).bindOne($scope, 'party', $stateParams.partyId, true, true);
that's it. no add, update etc..
If you want lets say to add the invite method, it is also one line:
$methods.call('invite', $scope.party._id, user._id);
But on the other way, we can change even that to like you suggested:
$scope.party = Parties.bindOne($stateParams.partyId);
$scope.party.invite($scope.party._id, user._id);
Yes, that might be a good idea..
Would love to hear more thoughts
from angular-meteor.
I'm thinking if to add it as a chapter after we did everything in the controller (might be simpler for people to understand and start) or start with that approach from the beginning of the tutorial...
from angular-meteor.
Yes, that would make sense. Personally, I think the best tutorials are those that tell a story from simple through to advanced/complex, so as to have the space to describe why the simpler solutions are not optimal for larger problem areas.
However, that said, imho, Meteor on its own seems a great fit for simpler problems without needing any of the structure or complexity (digest cycles, anyone?) of Angular. AngularJS is probably only worth the investment in learning and implementing when having to tackle a serious long-lifetime application, where the encapsulation of functionality, testing and separation of concerns across the MVC layers and beyond are essential to allow a large team to work on the same system. That's difficult to get across in a tutorial.
Maybe think about extending the tutorial application requirements for problems that require changing several Mongo - managed Collections from higher-level user actions. e.g. updating an activity stream (who did what to which party), automatically posting twitter messages via server-side method, all triggered from a number of different UI user actions. Basically, any scenario where access to the angular-meteor API and state needs to be shared across multiple pages / controllers.
That's a long-winded way of saying I agree with your approach!
from angular-meteor.
So your issue made me think more about the way we bind to a collection.
How about this type of usage:
Let's say we have a Parties service/provider:
angular.module("socially").controller("PartiesListCtrl", ['$scope', Parties,
function($scope, Parties){
$scope.parties = Parties.get();
$scope.remove = function(party){
$scope.parties.splice( $scope.parties.indexOf(party), 1 );
};
$scope.outstandingInvitations = function (party) {
Parties.getOutstandingInvitations(party);
};
$scope.rsvp = function(partyId, rsvp){
Parties.rsvp(partyId, rsvp).then(
function(data){
console.log('success responding', data);
},
function(err){
console.log('failed', err);
}
);
};
}]);
angular.module("socially").controller("PartyDetailsCtrl", ['$scope', '$stateParams', 'Parties',
function($scope, $stateParams, Parties){
$scope.party = Parties.get($stateParams.partyId)l
$scope.invite = function(user){
Parties.invite($scope.party._id, user._id).then(
function(data){
console.log('success inviting', data);
},
function(err){
console.log('failed', err);
}
);
};
$scope.canInvite = function () {
if (!$scope.party)
return false;
return !$scope.party.public &&
$scope.party.owner === $rootScope.currentUser._id;
};
}]);
And defining the Parties will be here:
angular.module('socially', []).config(function(Parties) {
Parties.setCollection(Parties);
});
My issue is binding the Parties collection with $scope.parties with this syntax:
$scope.parties = Parties.get();
Right now with the $collaction.bind function we watch the scope. I'm not sure how to do that with this syntax.. would love help and ideas about that
from angular-meteor.
I have set up my first angular-meteor project and spent a couple of hours playing around with this problem.
I tried out three solutions, described below with some code snippets. I hope this makes sense.
Use $collection.$bind in Controller
angular.module('myApp')
.controller('myController', ['$scope', '$collection', function($scope, $collection){
$collection(MyCollection).bind($scope, 'controllerBoundCollection', true, true);
This just works. But means all the Controllers need to directly use the angular-meteor $controller
service. This could be mitigated by having a top-level app-wide controller (attached to the body
DOM element), so all child scopes can access the $scope.controllerBoundCollection
property. This might also make the controllers more difficult to test, because you have to stub out the $controller.bind calls (which would need to include setting the $scope property to an expected value to enable the rest of the controller code to be tested properly)
Wrap $collection in a service
A service like this:
angular.module('myApp')
.factory('MyService', ['$collection', '$q', '$rootScope', function($collection, $q, $rootScope){
return {
/**
* Simply binds the Meteor $collection service query result to the given scopeProperty on the given scope
* Break separation of concerns between service and controller layer ... services should not use $scopes managed by view controllers
*/
bindCollectionToScope: function(scope, scopeProperty) {
$collection(MyCollection).bind(scope, scopeProperty, true, true);
}
};
}])
... is used by the controller like this:
angular.module('myApp')
.controller('MyController', ['$scope', 'MyService', function($scope, MyService){
// Here, we pass reference to this controller's $scope.
// The 'bindToScope' service method is a thin wrapper over $collection call
MyService.bindCollectionToScope($scope, 'serviceBoundCollection');
Here, we have encapsulated the knowledge of the Meteor-specific $collection
service in an application Service called myService
. We pass the $scope from the controller to the Service method, which is not great for separation of concerns ... ideally the $scope of the controller should stay entirely within the controller. I would then to stub out the myService.bindCollectionToScope
method when testing the controller.
Broadcast events from a service to inform controllers of operations on the collection
angular.module('myApp')
.factory('MyService', ['$collection', '$q', '$rootScope', function($collection, $q, $rootScope){
var numberObservers = 0;
var observerHandle;
return {
/**
* As an alternative to the above,
* set up a live query handle on a Meteor collection cursor, broadcasting events on changes
* See: http://www.bennadel.com/blog/2694-my-first-look-at-using-the-firebase-backend-as-a-service-baas-in-angularjs.htm for a similar example wrapped around firebase
* All clients share same collection query.
*/
startObserving: function () {
numberObservers++;
console.log("Increasing observer count to:"+numberObservers);
if (numberObservers > 1)
return; // Already observing
observerHandle = MyCollection.find()
.observe({
added: function (data) {
console.log('Object added:'+data);
$rootScope.$broadcast( "addedToMyCollection", data );
},
changed: function (newData, oldData) {
console.log('Data changed:'+data);
$rootScope.$broadcast( "changeToMyCollection", newData, oldData );
},
removed: function (oldData) {
console.log('Data removed:'+oldData);
$rootScope.$broadcast( "removedFromMyCollection", oldData );
},
movedTo: function (data, fromIndex, toIndex, before) {
console.log('Data moved:'+data);
// Do something here!
}
});
},
stopObserving: function () {
if (numberObservers == 0)
// No action if there are no observers left anyway
return;
numberObservers--;
console.log("Decreasing observer count to:"+numberObservers);
if (numberObservers == 0)
// if number of interested observers fell to zero, stop live query
observerHandle.stop();
},
};
}])
Then the controller listens to the broadcast events to update its $scope:
$scope.observedCollection = [];
var observerHandle;
// Set up live query of MyCollection
MyService.startObserving();
$scope.$on('addedToMyCollection', function (event, data) {
addDataToList(data);
});
$scope.$on('changeToMyCollection', function (event, newData, oldData) {
changeDataInList(newData);
});
$scope.$on('removedFromMyCollection', function (event, data) {
removeDataFromList(data);
});
$scope.$on('$destroy', function () {
// Call observer handle to stop querying and publishing any more events for this controller.
observerHandle.stop();
})
In this attempt, the MyService uses the find().observe() call from the Meteor cursor API, instead of the angular-meteor $collection
. This pattern is very similar to that sketched out in the firebase example I linked to in an earlier post on this thread.
The encapsulation is now complete:
- MyController has no knowledge of
$collection
. Its$scope
does not leak outside its boundary - MyService encapsulates the calls to the
$collection
angular-meteor service API.
I can test MyController by stubbing the MyService calls (but now much simpler as there is no action that directly impacts the controller), and generating $rootscope.broadcast
events. Similarly, I can test MyService by stubbing out the MyCollection global variable (edit: hmm, not sure how I would do that .. might need to wrap the MyCollection variable in a Angular Value provider, so I can inject it into MyService and therefore mock it out more easily).
I would be very interested in anyone's thoughts on this. Clearly, #3 needs a lot more boilerplate code to get the benefits of encapsulation and testability. $100,000 question, is when is this likely to be worth it?
from angular-meteor.
@rjsmith please have a look at the beginning of the work @asafdav is doing, we are just starting this approach but for me it looks like the right way to go:
5499030
from angular-meteor.
angular-meteor is brilliant ! Meteor alone , although a splendid piece of technology, will never get momentum for large enterprise apps. Angular even given the 1.3-->2 saga has trust.
Therefor, I believe that being able to isolate the client 'proxy' specific material in an angular service/factory is a extremely important feature.
from angular-meteor.
@rjsmith @paulvanbladel please take a look at the new version:
https://github.com/Urigo/angular-meteor/releases/tag/0.6.0-alpha
I think I've addressed this issue there
from angular-meteor.
Closing.
Please re-open if you think I haven't addressed everything here
from angular-meteor.
Related Issues (20)
- ReferenceError: angular is not defined
- Typescript compiler adds arrow function in web.browser.legacy js file causing error on IE11
- Angular Meteor Universal w/ AOT questions HOT 3
- Angular Meteor Universal w/ AOT config
- Problem when compiling project with MeteorCLI
- meteor build mobile app failed File to read not found or unreadable: HOT 1
- Infinite render loop for applications without a <base>
- Using angular-meteor with Meteor 1.8.2 HOT 3
- angular-meteor with Meteor 1.8.2 and ng-table
- HTML optimization during build process HOT 4
- upgrade to Meteor 1.9 fails HOT 19
- Error while compiling in AOT mode with Angular 9 HOT 15
- Client compiling twice every change/build HOT 2
- Upgrade to Meteor 1.10 fails HOT 2
- Bare example fails (with minor tweak) when upgraded to Meteor 1.8.2 HOT 2
- Server Side Rendering(SSR) in Angular CLI + Meteor project
- Testing your template :p
- Error: Cannot find module '/imports/app/app.module'
- `AOT=1 meteor` broken for Angular versions ≥ 13 HOT 3
- Are there any plans to upgrade this project to Angular 17?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from angular-meteor.