const Variables not updating without window reload - javascript

I am trying to have my login page redirect to my main page.
I do this by using:
this.props.history.push("/userdashboard");
This works but on The main page there are const variables pulled in from Constants.js, which contains USER_ID, set from local storage:
let user_id = null;
try {
user_id =
window.localStorage.getItem("user_info") &&
JSON.parse(window.localStorage.getItem("user_info")).user_id;
} catch (err) {
console.error("Error Parsing user_info user_id");
}
const USER_ID = user_id;
export { USER_ID };
and then imported with
import { USER_ID} from "../constants/Constants";
The problem is that, these constants are still null and do not contain the new information until the page is reloaded.
I would like to be able to do this without using location.reload, as I want the user to be pushed into a specific page sometimes.
This is coming from my login page which waits for the action to finish then pushes
this.props.loginFunc(login_data).then(() => this.completeLogin());
completeLogin() {
this.props.history.push("/userdashboard");
}
I cannot figure out a way to refresh this const data. Also I am not entirely sure why these constants are used for getting the item from local storage every time, which is not expected, and is used in enough places that it would be a pain to refactor.

I'm not sure that const vs let (vs var, I guess) makes a difference, here. What is important that the localStorage is being read once. When is it supposed to be updated after the one initial reading? I don't see that piece of code.
Put this line
user_id = window.localStorage.getItem("user_info") && JSON.parse(window.localStorage.getItem("user_info")).user_id;
where the script should check for updates, if you expect updates at runtime.

The whole point of constants is that they cannot be reassigned. So each time the Constants.js is imported, it will always use the previous const value.
You've already got a let user_id variable, simply export that
let user_id = null
try {
user_id = window.localStorage.getItem("user_info") && JSON.parse(window.localStorage.getItem("user_info")).user_id
}
catch(err) {
console.error("Error Parsing user_info user_id")
}
export {
USER_ID: user_id,
}

Related

how to pass data consistently from page to page in Vue Js?

Currently I want to pass data from edit page to add page. So i pass the query using {path: '/test/admin/clinicvisit/add', query:{id:this.$route.params.id}}. I was able to pass the data to add page using the query however sometimes the data may not present when it refreshes a few times. Is there any possible way to make the data consistent stay in the add page ?
add.vue
async testRoute(){
let visitId = this.$route.query.id
if (visitId){
let clinicVisit = await this.api.medical.viewClinicVisit(visitId)
this.inputs = await this.api.medical.optionsClinicVisit()
this.$set(this.inputs.staff, "item_text", "username")
this.$set(this.inputs.staff, "item_value", "id")
this.$set(this.inputs.staff, "items", await this.api.profile.listStaff({}))
if(clinicVisit.staff){
this.$set(this.inputs.staff, "value", clinicVisit.staff)
this.$set(this.inputs.staff, "tmp_value", clinicVisit.staff_detail.name)
}
mounted()
{
this.testRoute()
}
This can be done in multiple ways.
Using a global store, You can use a library like Vuex to share the state between the components.
Using the Local Storage, if you want to preserve the data and keep saved after hard refreshing the page.
Using Session Storage, if you want to preserve the data and keep saved during the user session, but whenever the user close the browser tab it will be gone.
When you observe that the data is not present after a few refreshes, does it dissapear from the URL in your browser, or does it just not load?
If you want the data to stay more consistently, consider using localStorage
localStorage.setItem('item_text', 'username') //Save variable in browser data
let item_text = window.localStorage.getItem('item_text') //Get variable from browser data
EDIT:
If the URL is still present in the browser window, that sounds like a weird loading bug, where your code runs before the route is parsed by Vue.
You can try using a watcher instead of the "mounted" function:
watch: {
$route: {
immediate: true,
handler() {
this.testRoute()
}
}
}
I solved this error by setting a timeout function in my edit.vue.
handleCreate(event){
event.preventDefault();
this.$router.push({path: '/medical/admin/clinicvisit/add', query:{id:this.$route.params.id}},2000)
// now 'this' is referencing the Vue object and not the 'setTimeout' scope
this.loadClinicVisitData = true;
setTimeout(() => this.loadClinicVisitData = false,1000)
}

How to check if a container exists in cosmos DB using the node sdk?

I want to check if a container exists and if not, initialize it. I was hoping for something like the following:
const { endpoint, key, databaseId } = config;
const containerName = "container1"
const client = new CosmosClient({ endpoint ,key});
const containerDefinition = getContainerDefinition(containerName);
const db = await createDatabase(client, databaseId);
if (!db.containers.contains(containerName)
{
// Do something
}
The reason I'm not using "createIfNotExists" is because I would need to make a 2nd call to check if the container returned is populated with items or not. The container I'm creating is going to hold settings data which will be static once the container is initially created. This settings check is going to happen per request so I'd like to minimize the database calls and operations if possible.
I tried doing something like:
try
{
db.container(containerName).read();
}
catch(err)
{
if(err.message.contains("Resource Not Found"))
{
// do something
}
}
But that doesn't seem like the right way to do it.
Any help would be appreciated!
I'm not quite clear on why you would need to do this since typically you only need to do this sort of thing once for the life of your application instance. But I would not recommend doing it this way.
When you query Cosmos to test the existence of a database, container, etc., this hits the master partition for the account. The master partition is kind of like a tiny Cosmos database with all of your account meta data in it.
This master partition is allocated a small amount of the RU/s that manage the metadata operations. So if you app is designed to make these types of calls for every single request, it's quite likely you will get rate limited in your application.
If there is some way you can design this such that it doesn't have to query for the existence of a container then I would pursue that instead.
Interesting question. So i think you have few options
Just call const { container } = await database.containers.createIfNotExists({ id: "Container" }); it will be fast probably few milliseconds, since I went via code at looks like it will always try to read from cosmos :( If you want to still check if container exists sdk has methods(But again no real benefits ):
const iterator = database.containers.readAll();
const { resources: containersList } = await iterator.fetchAll();
Create singleton and first time just initialise all your containers so next time you dont call it, sure if you scale each instance will do the same
My favourite, use terraform/armtemplates/bicep to spin up infrastructure so you code wont need to handle that
You can try this code:
async function check_container_exist(databaseId,containerId) {
let exist = false;
const querySpec = {
query: "SELECT * FROM root r WHERE r.id = #container",
parameters: [
{name: "#container", value: containerId}
]
};
const response = await client.database(databaseId).containers.query(querySpec).fetchNext();
if(response.resources[0]){
exist = true;
}
return exist;
}

Refilling a form from a database

I'm so stuck on this I might not even be able to formulate a sensible question, but here goes...
I have a gigantic (and occasionally changing) form. I've found a reasonable way to get all the data from the form, turn it into an object, and save it to Firebase all at once. It looks like this, and is working fine (I think):
const incidentReport = document.getElementById('incident-report-form');
let irv = {};
// This works. All form data is saved to an object (as required by firebase), with the question as the name and the answer as the value.
incidentReport.addEventListener('submit', (e) => {
e.preventDefault();
[...incidentReport.elements].forEach((item) => {
let name = item.name;
let value = item.value;
irv = { ...irv, [name]: value };
});
// After all data is collected in one object, I send it to the database all at once.
db.collection('incident reports').add(irv);
});
Okay, so far so good... Now I want to get it back out of the database (I know how to do this) and repopulate the same form (no idea). I'm 100% stumped and I don't even know what to try.
Please forgive me if this is super easy and my brain is just shutting off... it's been a rough day.
Thanks in advance.
EDIT - This seems to work? I'm still very open to criticism and/or improvements.
// Get data from incident reports
//#TODO -> Need to create a list of incident reports, and then load the one //the user clicks on.
//Right now there is only one incident report in the database for testing.
db.collection('incident reports')
.get()
.then((snap) => {
snap.docs.forEach((element) => {
data = element.data(); //Previously declared but not included in this snippet, sorry.
});
for (let [key, value] of Object.entries(data)) {
let x = document.getElementsByName(key)[0];
if (x !== undefined) {
x.value = value;
}
}
});
If I understood it correctly, once you returned the data from your Firestore collection, you want to print them back in your HTML form. Considering that, it should not be very hard for you to achieve that.
Once you load the documents into an array, you should be able to assign the values to variables, that will be printed in the form. It should be something like this:
//Getting the collection and a specific document
var report = db.collection('incident reports').doc('<report>');
var getDoc = report.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
// Loading the values of the document into variables
var name = getDoc.data().name;
var value = getDoc.data().value;
...
// Other values loaded to other variables that you create
}
})
.catch(err => {
console.log('Error getting document', err);
});
Once you have loaded the values into variables, you just need to create a tag <script> that will be adding the values via Javascript into your HTML. Something that can look like this:
<script src="http://code.jquery.com/jquery-3.4.1.min.js"></script>
document.getElementById('<form item name>').innerHTML = name;
</script>
While this code is not tested, I believe it should be a good starting point for you, on what you need to do, to achieve your goal. It's only for one document, but since you are on tests right now and have only one document, you should be fine.
Besides that, you can find a good and full example on retrieving values from Firestore and priting in a page, in this other post here: How can I display all data from Firestore documents into html elements
Let me know if the information helped you!

Getting Last Active URL Prior to Logout in Angular 2 App

In my Angular 2 app I am trying to store the last active URL prior to a user logging out, so that that url can be re-loaded after the user re-logs in. However, this is proving problematic. Consider this logout function from my authenticationService:
logout()
{
let lastUrl = this.getActiveUrl();
console.log('Url before logout: ', lastUrl);
this.apiService.logout();
}
Notice here that "lastUrl", which calls this.getActiveUrl(), which looks like this:
getActiveUrl()
{
let activeUrl = this.router.routerState.snapshot['url'];
console.log('activeUrl: ', activeUrl);
return activeUrl;
}
...appears BEFORE this.apiService.logout(). But, nevertheless, what gets printed to the console for "lastUrl" is "/login". But that's the URL where I end up immediately after logging out.
So, help me understand this:
If this is synchronous, why doesn't the correct URL print here? What am I missing? And how can I get the active url immediately prior to logout firing and re-directing to '/login'?
EDIT: After a commenter's suggestion, I tried assigning to localStorage instead of a local variable, like so:
logout()
{
localStorage.setItem('returnUrl', JSON.stringify(this.router.routerState.snapshot['url']));
this.apiService.logout();
}
But when I dig that value out with localStorage.returnUrl, I still get "/login".
First off, many thanks to #Sam for the localStorage suggestion. I should have thought of that. So, in the end, all I needed to do was make use of RouterStateSnapshot from my canActivate() function in my AuthGuardService, and save that value to localStorage. Then I just retrieve that value to plugin in on re-authentication and re-login:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
{
// Get route content id
let contentId = Object.getPropertyValueAtPath(route, 'data.contentId');
// Store last active URL prior to logout, so user can be redirected on re-login
localStorage.setItem('returnUrl', JSON.stringify(state.url));
// DO OTHER STUFF...
}
In my login component I just get that value to pass in...
login(response)
{
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password, function (results)
{
if (results.data && results.ok === true)
{
this.returnUrl = JSON.parse(localStorage.getItem('returnUrl'));
this.router.navigate([this.returnUrl || '/']);
console.log('ReturnURL Value is: ', this.returnUrl);
this.reset();
}
else
{
this.alertService.error(null, response);
this.loading = false;
}
}.bind(this));
}
It is happening synchronously. However, you are logging an object pointer. By the time you look at the object in the console, it has changed because the route has changed.
I suggest using local storage to store the router snapshot. This will not have the same pointer issue that you see in the console.

delete incoming write event after calculations in firebase functions

I have an app that uses firebase, the whole stack pretty much, functions, database, storage, auth, messaging, the whole 9. I want to keep the client end very lightweight. So if a user comments on a post and "tags" another user, let's say using the typical "#username" style tagging, I moved all of the heavy lifting to the firebase functions. That way the client doesn't have to figure out the user ID based on the username, and do everything else. It is setup using triggers, so when the above scenario happens I write to a "table" called "create_notifications" with some data like
{
type: "comment",
post_id: postID,
from: user.getUid(),
comment_id: newCommentKey,
to: taggedUser
}
Where the taggedUser is the username, the postID is the active post, the newCommentKey is retrieved from .push() on the comments db reference, and the user.getUid() is from the firebase auth class.
Now in my firebase functions I have a "onWrite" trigger for that specific table that gets all of the relevant information and sends out a notification to the poster of the post with all the relevant details. All of that is complete, what I am trying to figure out is... how do I delete the incoming event, that way I don't need any sort of cron jobs to clear out this table. I can just grab the event, do my needed calculations and data gathering, send the message, then delete the incoming event so it never even really exists in the database except for the small amount of time it took to gather the data.
A simplified sample of the firebase functions trigger is...
exports.createNotification = functions.database.ref("/create_notifications/{notification_id}").onWrite(event => {
const from = event.data.val().from;
const toName = event.data.val().to;
const notificationType = event.data.val().type;
const post_id = event.data.val().post_id;
var comment_id, commentReference;
if(notificationType == "comment") {
comment_id = event.data.val().comment_id;
}
const toUser = admin.database().ref(`users`).orderByChild("username").equalTo(toName).once('value');
const fromUser = admin.database().ref(`/users/${from}`).once('value');
const referencePost = admin.database().ref(`posts/${post_id}`).once('value');
return Promise.all([toUser, fromUser, referencePost]).then(results => {
const toUserRef = results[0];
const fromUserRef = results[1];
const postRef = results[2];
var newNotification = {
type: notificationType,
post_id: post_id,
from: from,
sent: false,
create_on: Date.now()
}
if(notificationType == "comment") {
newNotification.comment_id = comment_id;
}
return admin.database().ref(`/user_notifications/${toUserRef.key}`).push().set(newNotification).then(() => {
//NEED TO DELETE THE INCOMING "event" HERE TO KEEP DB CLEAN
});
})
}
So in that function in the final "return" of it, after it writes the finalized data to the "/user_notifications" table, I need to delete the event that started the whole thing. Does anyone know how to do that? Thank you.
First off, use .onCreate instead of .onWrite. You only need to read each child when they are first written, so this will avoid undesirable side effects. See the documentation here for more information on the available triggers.
event.data.ref() holds the reference where the event occurred. You can call remove() on the reference to delete it:
return event.data.ref().remove()
The simplest way to achieve this is through calling the remove() function offered by the admin sdk,
you could get the reference to the notification_id through the event, i.e event.params.notification_id then remove it when need be with admin.database().ref('pass in the path').remove(); and you are good to go.
For newer versions of Firebase, use:
return change.after.ref.remove()

Categories

Resources