Quickly calling this.$router.replace in a row causes race condition - vue.js

I have a filter setup in my VueJs 3 app. I am using the router to update the query, like this:
this.$router.replace({ path: window.location.pathname, query }).catch(err => { console.log(err); });
The query is generated by the value of some computed properties. When I want to "reset" the filter, I just set all these values to their default value. This will call the router replace method for each property change. This doesn't work, as it seems like there is a race between the calls to replace. Resulting in the query not looking as it should. Here is a console log screenshot, showing how to query value is not consistent between calls to replace.

Related

How to attach multiple parameters to an API request?

I built my own simple REST API with Express and now I'm consuming it from my client (Vue.js)
So in my page I access all the data from this endpoint: GET /api/books, and it works fine
Now I also have a "sort by" button where I want to get the data by the latest entries. I don't know if that's a good way or if I have to handle this in the backend but what I do is calling the same endpoint which is GET /api/books and sorting the data to get them the right way
For ex:
sortByLatest() {
axios
.get("/api/books")
.then(res => {
const books = res.data;
const sortedBooks = books.sort((a, b) => b.createdAt > a.createdAt ? 1 : -1
);
this.books = sortedBooks;
})
// catch block
}
I do that for everything. If I need a limited number of results or a specific property from the data I have to write some logic in the axios .then block to sort or filter what I want. Is this bad practice?
But that's not my actual problem
My problem is, in addition of sorting by the latest entries, I also want to filter the results by a specific property. The problem is when I click the A button it's gonna filter the books by a specific property, and when I click the B button it's gonna sort them buy the latest entries, but not both at the same time!
And what if I want additionnal things like limit the number of results to 10, filter by other properties etc... I want to be able to create requests that ask all those things at once. How can I do that? Do I have to build that in the backend?
I saw some websites using url parameters to filter stuff, like /genre=horror&sort=latest, is that the key of doing it?
Thank you for your time

firestore remove documents by field value

each of my docs in my firestore db contains 1 field {name: 'some value'}
I would like to loop through all the docs and then if the doc's fields value is equal to my param I would like to remove that doc
I'm trying to do it like so:
removeContact: function(name){
console.log('removing contact',name)
db.collection("contacts").forEach(doc=>{
if(doc.data().name === name){
doc.delete()
}
})
}
but I get the error that forEach() is not defined.
You need to use .get() following the collection or query to get a query snapshot promise, which you then handle accordingly. You can use forEach on the snapshot and delete each doc.
A better way, instead of searching through every document and using an if statement, would be to use a query like where('name', '==', name) and delete the document that way. Using a query would leave less for your function to do.
To delete a document, you need to know the full path to that document. And since you don't know the document IDs, that means you'll first need to read the documents.
The good news is that this means you can also perform a query to filter only the documents you're interesting in, instead of doing an client-side if.
db.collection("contacts").where("name", "==", name)
.get()
.then((querySnapshot) => {
querySnapshot.forEach(doc=>{
doc.ref.delete()
})
})

Express routes parameters

I am trying to create two routes in my express app. One route, without a parameter will give me a list of choices, the other one with a parameter will give me the choice related to the id.
router.get('/api/choice', choice_controller.get_choices);
router.get('/api/choice/:id', choice_controller.get_choice);
When I go to .../api/choice/?id=1 the api returns the list of choices, and therefore follows the route without the param (/api/choice). How do I make sure that the router does not omit the parameter?
Thanks in advance.
UPDATE
It seems that it does not fire the /api/choice/:id route. If I remove the one without the param, it gives a 404 so. Could someone explain to me why /api/choice/?id=1 is not getting picked up by /api/choice/:id?
Basically, your declared routes are documented in the Express documentation.
The second route is resolved by a URL like /api/choice/hello where 'hello' is mapped into the req object object as:
router.get('/api/choice/:id', function (req, res) {
console.log("choice id is " + req.params.id);
});
What you are actually trying is mapping query parameters.
A URL like /api/choice/?id=1 is resolved by the first router you provided.
Query parameters are easy to get mapped against the request as:
router.get('/api/choice', function (req, res) {
console.log('id: ' + req.query.id);
//get the whole query as!
const queryStuff = JSON.stringify(req.query);
console.log(queryStuff)
});

Ember Data Save method, Create vs update

I can't figure out how Ember determines if it should update or create a record. I would assume its based on the ID or on the Store entry, but it seems to be something else. The code example clarifies:
// this returns the user without making an api call
currentUser.get('store').find('user_detail', '49')
// this returns 49
currentUser.get('id')
// this returns true
currentUser.get('store').hasRecordForId('user_detail', 49)
// this issues a create to api/userDetails instead
// of updating /api/userDetails/49
currentUser.save()
// maybe this is a lead, not the 48 at the end
currentUser.toString()
// <EmberApp.UserDetail:ember461:48>
// it looks as though currentState is involved here
// http://emberjs.com/api/data/classes/DS.RootState.html
currentUser.currentState
// returns root.loaded.created.uncommitted
currentUser.get('currentState.stateName');
// also isNew is wrong and returns true
currentUser.get('isNew');
Let me explain why I have this issue. My app has a current user. If you logout I update the current user. So I set Ember.currentUser.setProperties(newUserData). I update the currentUser object so that ember automatically triggers updates throughout my app. If I would replace the currentUser Ember.currentUser = newUser; Nothing would update. If I cant solve the above problem an alternative solution for the swapping of the user object would also work.
This is how I handle the global user state
container.register('user:current', Ember.currentUser);
// and handle updates via Ember.currentUser.setProperties()
application.inject('controller', 'user', 'user:current');
application.inject('route', 'user', 'user:current');
A proper solution would replace Ember.currentUser, however doing that doesnt trigger updates.
A new model will have the isNew and isDirty properties set to true, an existing record that needs to be updated will only have isDirty set to true.
I'd recommend pushing your user one level deeper and not storing it on the Ember namespace, that way you can set it from anywhere else, yet still inject it during injection
var users = Em.Object.create({
current: currentUser
});
container.register('users:current', users, {instantiate: false});
// and handle updates via Ember.currentUser.setProperties()
application.inject('controller', 'users', 'users:current');
application.inject('route', 'users', 'users:current');
Then from any controller you can access/watch it on users.current, yet you can also set it using this.users.set('current', newUser) which would effect anyone watching that property on any controller or route.
Example: http://emberjs.jsbin.com/OxIDiVU/1145/edit
Additionally a lot of things you are doing are async calls and should use the promise pattern for viewing properties etc.

How to define complex routes with named parameters in express.js?

I want to set up some more complex routes that can include a number of optional parameters. Preferably, I would like to use named parameters for ease of access. Here is an example of what I'm trying to achieve:
// The following routes should be matched based on parameters provided:
// GET /books/:category/:author
// GET /books/:category/:author/limit/:limit
// GET /books/:category/:author/skip/:skip
// GET /books/:category/:author/limit/:limit/skip/:skip
// GET /books/:category/:author/sort/:sortby
// GET /books/:category/:author/sort/:sortby/limit/:limit
// GET /books/:category/:author/sort/:sortby/skip/:skip
// GET /books/:category/:author/sort/:sortby/limit/:limit/skip/:skip
app.get('/books/:category/:author/(sort/:sortby)?/(limit/:limit)?/(skip/:skip)?', myController.index);
As you can see, I'm trying to group the optional parameters with (paramKey/paramValue)?. That way I was hoping to be able to "mix and match" the optional parameters while still making use of the parameter naming. Unfortunately, this doesn't seem to work.
Is there any way to get this working without having to write straight regular expressions and adding additional logic to parse any resulting index-based parameter groups?
Basically, I'm looking for an easy way to parse key/value pairs from the route.
It looks like you want to re-implement the query string using the URL path. My guess is that if you really wanted that, yes, you would have to write your own parsing/interpreting logic. AFAIK express path parameters are positional, whereas the query string is not. Just use a query string and express will parse it for you automatically.
/books?category=sports&author=jack&limit=15?sortby=title
That will enable you to do
req.query.sortby
You may be able to get express to do 1/2 of the parsing for you with a regular expression path like (:key/:value)* or something along those lines (that will match multiple key/value pairs), but express isn't going to then further parse those results for you.
you can send data to view as follow:
//in the server side ...
app.get('/search/:qkey/:qvalue', function(req, res){
res.write(JSON.stringify({
qkey:req.params.qkey;
qvalue:req.params.qvalue;
}));
});
and in the client side... call to ajax
$.ajax({
type:"POST",
url:"/search/"+qkey+"/"+qvalue,
success: function(data){
var string = eval("(" + data + ")");
//you access to server response with
console.log(string.qkey+" and "+ string.qvalue);
}
});