Publish/Subscribe not working automatically when data added to the mongodb - angularjs

I have the following publisher and subscriber code.
It works for the first time when the app starts, but when I try to insert data directly into the Mongo database, it will not automatically update the user screen or I don't see the alert popping.
Am I missing something?
Publish
Meteor.publish('userConnections', function(){
if(!this.userId){
return;
}
return Connections.find({userId: this.userId});
})
Subscribe
$scope.$meteorSubscribe('userConnections').then(function () {
var userContacts = $scope.$meteorCollection(Connections);
alert("subscriber userConnections is called");
if (userContacts && userContacts[0]) {
....
}
}, false);

First off, if you are not using angular-meteor 1.3 you should be. The API has changed a lot. $meteorSubscribe has been deprecated!
To directly answer your question, $meteorSubscribe is a promise that gets resolved (only once) when the subscription is ready. So, it will only ever be called once. If you look at the documentation for subscribe you'll see how to make the binding "reactive", by assigning it to a scope variable. In your case it would be something like:
$scope.userContacts = $scope.$meteorCollection(Connections);
Doing it this way, when the collection gets updated, the $scope.userContacts should get updated as well.

Related

Meteor with query on publication is not reactive

I have a problem with a meteor publication not being reactive when using a query inside it.
Let's say I have many files, and each file has many projects, so I can go to the route:
http://localhost:3000/file/:file_id/projects
And I would like to both display the projects of the selected file and add new projects to it.
I am currently using angularjs, so the controller would look something like this:
class ProjectsCtrl {
//some setup
constructor($scope, $reactive, $stateParams){
'ngInject'
$reactive(this).attach($scope)
let ctrl = this
//retrieve current file id
ctrl.file_id = Number($stateParams.file)
//get info from DB and save it in a property of the controller
ctrl.subscribe('projects', function(){return [ctrl.file_id]}, function(){
ctrl.projects = Projects.find({file_id: ctrl.file_id}).fetch()
})
//function to add a new project
ctrl.addProject = function(){
if(ctrl.projectName){
Meteor.call('projects.insert', {name: ctrl.projectName, file_id: ctrl.file_id }, function(error, result){
if(error){
console.log(error)
}else{
console.log(result)
}
})
}
}
}
}
The publication looks something like this:
Meteor.publish('projects', function(file_id){
return Projects.find({file_id: file_id})
})
The problem is that, if I insert a new project to the DB the subscription doesn't run again, I mean the array stays the same instead of displaying the new projects I am adding.
I got many problems with this as I thought that meteor would work something like: "Oh there is a new project, let's re run the query and see if the publication change, if it does, let's return the new matching documents"... but no.
I have not found a problem similar to mine as every question regardind querys inside the publication is about how to reactively change the query (the file_id in this case) but that is not the problem here as I don't change the file_id unless I go to another route, and that triggers a new subscription.
My current solution is to expose the complete collection of projects and make the query using minimongo, but I don't know if it is a good workaround (many projects exposed uses too much memory of the browser, minimongo is not as fast as mongo... etc, I don't really know).
Your issue is that the Meteor.subscribe call doesn't know that file_id has changed. There's no reactive relationship between that argument and executing the subscription.
To fix this, whenever you are passing criteria in publish-subscribe, you must write a subscription of Collection inside a tracker.
To know more about trackers, Click here.
While I'm unsure how to do this in Angular, consider this simple Blaze template as an example:
Template.Name.onCreated(function(){
this.autorun(() => {
Meteor.subscribe('projects', file_id);
});
});
Whenever file_id changes, a new subscription is triggered, giving you the desired effect of auto pub-sub utility.
I hope this will give you some insight. It could be easily achieved via Angular JS as well.

NodeJS update user status dynamically with Angular

I have this little issue. I have a service that has a Subscription option. When an item in the DataBase is modified (i.e. customer order), I want the customer to see the change in real-time.
Once the user logs in, he is automatically subscribed to his order's status (or several orders, as the case may be). When the status changes, the service sends a POST to a URL that I designate and when that is done, I want to change the client's order status, however I have no idea how to modify Angular's model in order to change what the user sees.
module.exports = function (app) {
app.route('/api/machine')
.post(function (req, res) {
console.log(JSON.stringify(req.body));
return res.send("post returned " + JSON.stringify(req.body));
})
};
At the moment, I get the updates from the Service and print them out, but how do I update the view as well?
try use $watch() function.. when the value is modified, the view is updated.
$scope.$watch(function(scope) { return scope.data.myVar },
function(newValue, oldValue) {
document.getElementById("").innerHTML =
"" + newValue + "";
}
);
I dont know how you've constructed this project's structure, but if you're using a API, use http post to notify your front when changes are done.
the digest or watch, will make your controller do a function always the value has changed.
Angular Digest,Watch and Apply docs.
i hope this helps.
cya.

laravel angularjs update multiple rows

i have a sortable table and after successfully moving an item i want to update all the rows in the databasetable which are effected from sorting.
my problem is that i dont know what's the best way to update multiple rows in my database with eloquent and how to send the data correct with angularjs
in angularjs i did this
//creating the array which i want to send to the server
var update = [];
for (min; min <= max; min++){
...
var item = {"id": id, "position": position};
update.push(item);
...
}
//it doesn't work because its now a string ...
var promise = $http.put("/api/album/category/"+update);
//yeah i can read update in my controller in laraval, but i need the fakeid, because without
//i get an error back from laravel...
var promise = $http.put("/api/album/category/fakeid", update);
in laravel i have this, but is there an possibility to update the table with one call instead of looping
//my route
Route::resource('/api/album/category','CategoryController');
//controller
class CategoryController extends BaseController {
public function update()
{
$updates = Input::all();
for($i = 0; $i<count($updates); $i++){
Category::where('id','=', $updates[$i]["id"])
->update(array('position' => $updates[$i]["position"]));
}
}
}
and yes this works but i think there are better ways to solve the put request with the fakeid and the loop in my controller ;)
update
k routing is solved ;) i just added an extra route
//angularjs
var promise = $http.put("/api/album/category/positionUpdate", update);
//laravel
Route::put('/api/album/category/positionUpdate','CategoryController#positionUpdate');
Try post instead put.
var promise = $http.post("/api/album/category/fakeid", update);
PUT vs POST in REST
PUT implies putting a resource - completely replacing whatever is available at the given URL with a different thing. By definition, a PUT is idempotent. Do it as many times as you like, and the result is the same. x=5 is idempotent. You can PUT a resource whether it previously exists, or not (eg, to Create, or to Update)!
POST updates a resource, adds a subsidiary resource, or causes a change. A POST is not idempotent, in the way that x++ is not idempotent.
By this argument, PUT is for creating when you know the URL of the thing you will create. POST can be used to create when you know the URL of the "factory" or manager for the category of things you want to create.
so:
POST /expense-report
or:
PUT /expense-report/10929
I learned via using following
Laravel+Angular+Bootstrap https://github.com/silverbux/laravel-angular-admin
Laravel+Angular+Material https://github.com/jadjoubran/laravel5-angular-material-starter
Hope this help you understand how to utilize bootstrap & angular and speed up your develop by using starter. You will be able to understand how to pass API request to laravel and get callback response.

angular-meteor: notify client when new document inserted

I am implementing a notification system using angularjs and meteor.
In my publication code,
I have something like this:
var retVal = Notifications.find({recipient: userId});
var handle = retVal.observeChanges({
//when a new notification is added
added: function (doc, idx) {
count++;
if (!initializing){
console.log("A record was added");
self.changed("counts", userId, {count: count});
}
},
removed: function (doc, idx) {
count--;
self.changed("counts", userId, {count: count});
}
});
and in the end I return retVal.
In my controller, I subscribe to that publication.
The code seems fine and the server triggers the added function whenever a new document is added. But how do I notify the client (something like trigger a function in my controller) when a new document is added? The added function only triggers in the server.
I can't see your publication header, do you expect parameters there?
For binding a collection all you need to do is use the $meteorCollection service like that:
$scope.notifications = $meteorCollection(Notifications);
We just updated our API (version 0.6.0-alpha) and it does observeChanges internally to look for any change in the collection.
But don't forget to subscribe to that collection - you can do that in 2 ways:
$meteorSubscribe.subscribe("publicationName", parameters) - which returns a promise.
$scope.notifications = $meteorCollection(Notification).subscribe("publicationName", parameters); - which is shorter but doesn't return a promise.
If one of the parameters changes the publication, you should surround it with autorun like that:
$meteorUtils.autorun($scope, function(){
$meteorSubscribe.subscribe("publicationName", {
limit: parseInt($scope.getReactively('perPage')),
skip: (parseInt($scope.getReactively('page')) - 1) * parseInt($scope.getReactively('perPage')),
sort: $scope.getReactively('sort')
}));
});
$scope.getReactively is a new method we added that makes a regular $scope variable to a reactive one. this means that when it changes, that autorun will re-run.
Hope it helps, let me know how can I improve the answer and the documentation.
I think that you should replicate your observeChanges() on the client.
So, it will be able to observe the client side collection that is created and synchronized by the subscribe() function.

AngularFire equivalent to $setPristine?

I'm trying to understand the correct workflow to create a $setPristine equivalent with my Firebase data.
My workflow is as follows:
1) Create Firebase object (via the Angularfire Generator 'SyncData')
2) Form data modifies the $firebase object.
3) To update the remote model, I use myRef.$save()
All of that works well. Now, I'm trying to add a "reset" button on the form, so that the locally modified data will revert back to the remotely stored data.
So far, I'm running into problems. I've tried reinitializing the firebase reference eg myRef = syncData('/my/path') but not only does that now work, but it is destroying the remote data object!
What is the correct way to re-pull the remote data to use in my Angular model?
I know this is an old question, but I ran into this issue myself.
After some searching around I found this post: http://grokbase.com/t/gg/firebase-angular/1499haaq4j/editing-data-as-a-copy
Which led me to an outdated code snippet (2 months lol XD) from #Kato: https://gist.github.com/katowulf/8eaa39eab05a4d975cd9
I modified this to work with Firebase 2.3.1 and AngularFire 1.1.3:
app.factory('ResetFactory', function($firebaseArray) {
return $firebaseArray.$extend({
reset: function(itemOrIndex) {
var key, self;
self = this;
key = self.$keyAt(itemOrIndex);
self.$ref().child(key).once('value', function(snap) {
self.$$updated(snap);
});
}
});
});
Which can be called via:
var comments = new RevertFactory(ref.child('comments'));
# variable comment is for example an ng-repeat that's being edited
comments.reset(comment);

Resources