Mean js - display updates in real time - javascript

I'm new to meanjs, I just created a new module for adding products. These products are displayed in the home page. But the display in home page is not getting updated real time. I just added new product in one tab, and the products list in the other tab need to be refreshed to see the change. How can this be done at real time ?
Edit:
By updation I meant is, when ever a new record is been added to database, the product display should update in realtime. Now I need to refresh the page to see the newly added product.
My code is
Client
$http.get('/latestproducts').
success(function(data, status, headers, config) {
$scope.latestproducts = data;
})
Server
exports.getlatestProducts = function(req, res) {
Product.find().sort('-created').populate('user', 'displayName').exec(function(err, products) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(products);
}
});

If you mean browser tabs, mean.js won't do if fo you. You can use sockets to inform server that changes were made and then broadcast message to all active tabs to refresh data. You can also try window.blur/window.focus events to reload data.
If you have list of products and product form on the same page, you have 2 options:
add saved item to your local collection after you save poduct and recive success message from server.
Update local collection(get list of objects from the server) after you save poduct and recive success message from server.

I just released angular-socket-resource. Once you use a service instead of performing the http request manually, you can use that to automatically listen for socket.io updates that will update your local data.

Related

Is it a good approach to use firebase once method when retrieving all posts on ionViewWillEnter?

I am retrieving all posts (news) from firebase using the once method and showing it on the home tab (the first tab when the app is launched) :
get_all_posts(){
this.posts = [];
firebase.database().ref('/posts/').once('value').then(snapshot => {
.... //rest of the code
}
}
This will be fired in the ionViewWillEnter():
ionViewWillEnter(){
this.get_all_posts();
}
In this case, get_all_posts method will be fired everytime the "home" tab is pressed right? which will get all posts again from the DB or for the entire session (from opening the app till closing the app running on the phone)the news retrieved from the first time only will be displayed?
The news retrieved at first time with once() will fetch all the data from the reference you want to show, this will fetch the data just once and then detach the listener to the reference. When you press again your home button it will fetch again the data that belongs to that reference and will pull it from the database, if there is new content it will be displayed, if not, the first fetched data will be shown.
From your question
Is it a good approach to use firebase once method when retrieving all
posts on ionViewWillEnter?
Yes, in my opinion, it is a good practice to just ask for the data once and then display it to the user, because if you use on() you will be always listening for new data and your home screen might be updated with new content before the user can see the first fetched news.

Firebase custom claim how to set?

I'm struggling with firebase custom claims.
I have tested a lot of approaches nothing works. Obviously, I miss something important in the concept itself.
So I'm back to the root. This script from the google example should apply customs rule on a newly created user
exports.processSignUp = functions.auth.user().onCreate(event => {
const user = event.data; // The Firebase user.
const customClaims = {
param: true,
accessLevel: 9
};
// Set custom user claims on this newly created user.
return admin.auth().setCustomUserClaims(user.uid, customClaims)
});
Then on a client, I check the result with
firebase.auth().currentUser.getIdTokenResult()
.then((idTokenResult) => {
// Confirm the user is an Admin.
console.log(idTokenResult.claims)
if (!!idTokenResult.claims.param) {
// Show admin UI.
console.log("param")
} else {
// Show regular user UI.
console.log("no param")
}
})
.catch((error) => {
console.log(error);
});
Everything just a raw copy-paste still doesn't work. I've tested both from the local machine(there could be troubles with cors?) and deployed
This is a race situation. If the Function end first then, you will get the updated data.
The getIdTokenResult method does force refresh but if the custom claim is not ready then, it is pointless.
You need to set another data control structure to trigger the force refresh on the client. By example a real-time listener to the rtd;
root.child(`permissions/${uid}`).on..
And the logic inside the listener would be: if the value for that node exists and is a number greater than some threshold, then trigger the user auth refresh
During that time the ui can reflect a loading state if there is no datasnapshot or the not admin view if the datasnapshot exists but is a lower permission level.
In Functions you have to set the node after the claim is set:
..setCustomUserClaims(..).then(
ref.setValue(9)
);
I have a more detailed example on pastebin
The claims on the client are populated when the client gets an ID token from the server. The ID token is valid for an hour, after which the SDK automatically refreshes it.
By the time the Cloud Functions auth.user().onCreate gets called, the client has already gotten the ID token for the new user. This means that it can take up to an hour before the client sees the updated claims.
If you want the client to get the custom claims before that, you can force it to refresh the token. But in this video our security experts recommend (that you consider) using a different storage mechanism for claims that you want to be applied straight away.

Node-Craigslist syntax for details

Hello I am using the package node-craigslist https://github.com/brozeph/node-craigslist, and am hoping that someone can help me with some syntax with the details method.
In his documentation, he gives the example
client
.list()
.then((listings) => client.details(listings[0]))
.then((details) => {
console.log(details);
})
.catch((err) => {
console.error(err);
});
I currently have working the code to get the listings, but not the details. Below is my section of code where I retrieve the listings.
client
.list(options)
.then((listings) => {
listings.forEach((listing) => {
console.log(listing);
searchResults.title[counter] = listing.title;
searchResults.date[counter] = listing.date;
searchResults.location[counter] = listing.location;
searchResults.url[counter] = listing.url;
searchResults.price[counter] = listing.price;
counter++;
if(counter === listings.length) {
socket.emit('redirect'); //change to /results.ejs if done looping
};
});//end of listings foreach
});
I have been trying to incorporate the details into my own code unsuccessfully. Does anybody have any knowledge on how I can do this? Thanks.
You need to pass in a listing object into the method. In his example, he just grabs the most recent listings without any search options, then passes in the first listing from that array of listings. But you could obviously customize the search and the options.
client
.list()
.then((listings) => client.details(listings[0]))
.then((details) => {
console.log(details);
})
.catch((err) => {
console.error(err);
});
Depending on how the rest of your code is structured, you need to determine when to pass a specific listing. In my app that I built with this package, I make the initial search request that returns all the listings, and then when the user clicks on a listing for a search term, I make another request passing along that specific listing OBJECT and then it returns the details.
To be even more specific ...
On the client side the user searches, I emit that to the server then make the search request.
Once the request is finished I emit the results back to the client and then display the information to the user and store each listing object inside a custom data attribute inside each listing for later use.
Once the user clicks on a specific listing, I grab the object from the data-attribute and emit that to the server.
The server listens for that and makes the second DETAILS request using that listing object which is then emitted back to the clients browser.

App Maker delete items on table and update

I have an app that I would like to be able to take columns from a google spreadsheet and make a list on a table in my app. Also I would like to be able to remove items from this table.
As of now I am using the AMU library function AMU.deleteAll, all it does is
AMU.deleteAll = function(widget){
var records = widget.datasource.items;
records.forEach(function(record){
record._delete();
});
};
So what happens is that when I have a completely new and blank table my app can update from my spreadsheet when I use AMU.import.fromSpreadsheet (check here for full library goo.gl/RkeqZw) it will take all the items from my spreadsheet and place them properly in my table, after that I can use the delete function to remove all items on my table. Here is where things get all screwy, when I try to use the import function again the list gets populated with empty entries and if I try to use the delete function I get an error:
"Drive Table internal error. Record not found. Caused by: Execution Failed. More information: Object not found at path: camo0A_084fQ. (HTTP status code: 404) Error: Drive Table internal error. Record not found. at deleteAllData (ServerScript:232)"
I am not sure why this is happening, to me it seems like the data is being saved and the delete function only removes the value, and not the actual entry.
If you want to delete all items from your model you can make single server call (the code you quoted above does sever call for each individual item loaded on client):
// server script to delete all records from model
function deleteAllRecordsFromModel() {
var allRecords = app.models.MyModel.newQuery().run();
app.deleteRecords(allRecords);
}
// client script to call server function
google.script.run
.withSuccessHandler(function() {
// TODO: Handle success (optional)
})
.withFailureHandler(function() {
// TODO: Handle error (optional)
})
.deleteAllRecordsFromModel();

How to reload the model when using this.get('store').query?

I have a user model with attributes name and city, i am fetching 25 records at a time from server since there are lot of user records
so my routes has this
model(){
return this.get('store').query('user', {page:1}); }
which fetches me the first 25 records
Now in my template i have a button which on click hits the action to fetch the next 25 records ie
action:{
findMoreUsers(){
this.get('store').query('user', {page:2});
} }
Now in the browser, in the ember data the new records are loaded ie it shows 50 records
but when i try to do something like this.get('model'), it gives me the only the old records but not the newly loaded records
So how to to refersh the model so that it shows me all the old as well as new records(50 records)?
Thanks
This is because you haven't changed the model itself, which is just the result of a request to your server. I would recommend:
```
page: 0,
beforeModel() {
return this._findMoreUsers();
},
model() {
return this.get('store').findAll('users');
},
_findMoreUsers() {
this.get('store').query('user', { page: this.incrementProperty('page') });
}
```
Or something along those lines.
Then you can use this.store.peekAll('users') to retrieve all users that have been loaded into the store. If you need to change the model, you'll probably need to this.get('model').pushObjects(...).

Categories