I am using angularfire with an array like this:
var ref = new Firebase(URL);
var sync = $firebase(ref);
$rootScope.list = sync.$asArray();
I want to know the difference between using angular's $watchCollection
on 'list' and using angularfire built-in $watch like this:
$rootScope.list.$watch(function(event) {
console.log(event);
});
Which one is faster and what are the use cases of each one?
You need to think about AngularFire as a service wrapper around the Firebase API. It augments and uses features of Angular, but ultimately is meant to help you integrate back to Firebase. That being said...
scope.$watchCollection() according to the spec "shallow watches the properties of an object and fires whenever any of the properties change". It works on arrays and object maps, but watches only those objects that are held by your client.
x.$watch in AngularFire is really more an abstraction of functions that enable the 'three way data bind' feature. Note that $watch is used for both $FirebaseObject and $FirebaseArray - it does different things in each context, but essentially enable you to keep your data in the client in sync with updates on your server/Firebase.
Considering the different roles, 'faster' is not really an appropriate question. If you are using $watch in AngularFire, you would not need to use $watchCollection on the same object. For what it's worth, AngularFire's $watch is actually pretty speedy.
Related
I am building an app with React + Redux + Immutable JS and am running into some architectural problems. To illustrate I will use my user record as an example. The user object is an Immutable Record, defined in the user reducer. Now I would like to define some methods for this user (for example, isCurrentUser(userId), which would return a boolean and can be called on any user instance). From what I gather, the state should simply be plain objects though (reference: How to put methods onto the objects in Redux state?)
However, since this method wouldn't change the state of the application it doesn't make sense to use the typical Redux flow either. Is it acceptable for me to define methods within my Immutable Records, or should I be defining some helper methods in a separate JS file. Or maybe there's something else I haven't thought of?
You can create a new layer called 'services' and put this methods inside it. So, you can have a services/UserSession that is used like.:
{ isCurrentUser } from './services/UserSession'
isCurrentUser(user)
Does it help you?
Namely, what are the advantages and disadvantages of the following approaches to building a server-side database API in Meteor?
Method-based
import Db from 'Db';
Meteor.method({"insert": (data) => {Db.insert(data)});
Subclass-based
import {Mongo} from "meteor/mongo";
class MyCollcetion extends Mongo.Collection {
insert: (data) => {super.insert(data);}
}
This problem has been solved below; there is a similar question for further reading: Meteor method vs. deny/allow rules
This is mainly a matter of ease vs control. Subclassing may be easier for simple things, and methods are more powerful.
This can also be affected by your state of mind (or affect it): CRUD vs. action-based mutation.
insert/update/remove go well with a CRUD state-of-mind, while you can associate methods with action-centric RPC mutators.
Eventually, this is a matter of personal preference, so I will try to give a short factual description and let the readers to decide based on their taste.
Subclassing
By default, Meteor automatically generates mutation methods (insert, update, remove) when a collection is instantiated.
Those methods are called behind the scenes when calling MyCollection.insert(mutator, cb) on the client side (outside client-side method code). When arriving to the server, the data are first passed through allow/deny rules and then executed.
When subclassing, you override those methods and get a 'hook' into the process.
Using methods
When defining a Meteor method you get full control of the process.
You set the parameters and the name of the method and you can perform the validation and authorization as you wish.
You can also create a method stub for client-side use, which generates optimistic UI until the results of the method server execution are received.
You can use something like a validatedMethod to get some extra validation logic and modularity to your method.
You can also prevent the creation of the default mutation methods by setting a false value for the defineMutationMethods option when instantiating the collection. You can also forbid direct mutation from the client by supplying the appropriate deny rules.
While subclassing allows you to use MyCollection.insert(...), etc. on the client, you need to call the method name with the arguments that you defined in order to mutate data.
I am using angular2-meteor.
When I try to pass a value between two components (when the value change in the first component, create an event in second component and use this new value), I have two ways right now:
One way is meteor way: using this.autorun and Session.get.
Another way is angular2 way: using Injectable service with EventEmitter.
Which way should be prior? Or is there any other better way? Thanks
Now I used angular2-meteor a while.
Although the angular2-meteor tutorial has no example so far about using or choosing Angular 2 service or Meteor Session.
But I feel angular 2 takes the lead in the front end, while meteor makes reactivity easier and also handle all back end things.
So I went with angular2 way using service to share between components. And service is very powerful like #todd-w-crone said.
If anyone has better answer, I will switch to accept that one.
I find it practical to create a new service called App.states.ts which is accessed globally and mimics Session (get / set).
I commonly import this service to all necessary components to get or set new value such as User.status, company.profile, lastProduct, etc.
Since this service is #injectable it can also make use of other services, in case a value hasn't been set already.
This allows me to ask for a variable in a component appState.getLastModifiedItem(), then in app.states.ts I'll write this function to pass this.modifiedItem or either:
Request another service item.service.ts to fetch data
Call another function with itemCollection.findOne({...}) and return such value.
You can configure Mongo queries as you want and either store static data in appState or keep subscription items in appState.
Do take into consideration that all subscriptions handled by an #injectable within a component are imported by such component. Be wary of conflicting subscriptions between components/services.
I am writing an application which communicates with an API and stores the response in a Meteor Collection so I can have the power of mongo to sort/filter.
I would like to clear the collection for every new result set. But a Meteor Collection is persistent.
What is the preferred way of clearing the collection? I know you can drop the meteor collection, but is that the preferred method?
Help appreciated. Thank you!
I would go about creating a local mongo collection which will be available on client side only. To create a client-side collection, just don't give it a name argument.
//This collection is client-only, and will not be sync with server
myCollection = new Mongo.Collection();
//To be more explicit, you can use `null` for the name:
myCollection = new Mongo.Collection(null);
Once you are done using the data empty the collection
myCollection.remove({});
myCollection.remove({}) is the syntax for removing all documents from a collection. This will only work on the server unless the collection is a client-side collection as per #Nakib's example. Otherwise documents can only be deleted by _id on the client side. Normally your allow/deny rules should block any attempt to delete anything on the client as it provides a great attack vector.
Not completely familiar with the Meteor best practice but if you were going to clear out an array in javascript the best practice would be to run the following.
myArrary.length = 0;
For more information I recommend this blog post by David Walsh where he details the reasoning behind zeroing out an array as follows:
Setting the length equal to zero empties the existing array, not
creating another array! This helps you to avoid pointer issues with
arrays as well.
I'm new to the Meteor framework, and am having problems accessing data from my collection, outside of a template.
I have a small mongo collection and can retrieve and present its data without problems by using a template. However, when I try to get a cursor or array to use more directly, I get no results returned.
In my script, using find
var dataFind = Fakedata.find();
console.log(dataFind);
console.log(dataFind.count());
gives a cursor object, but a count of zero.
var dataFetch = Fakedata.find().fetch();
console.log(dataFetch);
console.log(dataFetch.length);
gives an empty array, length of zero.
Using the same find() or fetch() from the JS console gives populated objects as I would expect the code above to do. Within a meteor template, everything seems to work fine as well, so the pub/sub seems to be correct.
Any clues as to what I'm doing wrong here?
It looks like your subscriptions aren't ready at the time you try to access your collection data, this is a common gotcha.
When you access your collection data via templates, it is most likely via the use of template helpers which happen to be reactive, so they will rerun when your collections are ready thus displaying the correct data.
When accessing your collections in a non-reactive script though, they will appear empty if the subscription is not yet ready.
You can try using this pattern in your script to execute code only when the subscription is ready :
Meteor.subscribe("mySubscription",function(){
// we are inside the ready callback here so collection date is available
console.log(Fakedata.find().fetch());
});
If you are looking for a more robust approach, try looking at iron:router waitOn mechanism.