adding a query string to an URL - javascript

I'm working on a app in Node/Express/Jade environment.
Let's assume I start my app, and direct my browser to this URL:
/superadmin/?year=2012
On this page, i find a list with object, sorted in a default order. Here is also a link that will re-sort the list objects in another order. I jade this link look like:
a(href = '?sortAfter=company&ascending=1') Company
If i press this link, I will get the items sorted in the way I want, but the ?year=2012 from earlier query string will be lost.
Question: How do I re-write this link to add the new query strings, and not replace it.

Got the same problem, here's how I fixed it:
Installed https://npmjs.org/package/URIjs via npm install URIjs
Now, in your route :
var URI = require('URIjs');
app.get('/', function(req, res) {;
res.render('views/index.jade', {
urlHelper: function (key, value) {
return (new URI(req.url)).setQuery(key, value);
}
});
};
And in jade :
a(href=linkHelper('acesnding',1)) Company

I've come up with my own npm package for just this cause -> https://www.npmjs.com/package/qsm
Example:
var qsm = require('qsm');
app.get('/', (req, res) => {
res.render('views/index.jade', {
addQueryString: (key, value) => {
return qsm.add(window.location.href, [{ query: key, value }]);
}
});
});
and in jade
a(href= addQueryString('acesnding',1)) Company
Please refer the README in qsm and you'll see how easy it is to append querystring, remove specific querystrings and even parse and much more!
You can even clear, remove and replace querystrings. The best of all, it doesn't have to be a URL, it can be whatever string you can think of, but it will behave as that string is an url and append querystring to it: e.g: ?key=value or &key=value depending on what is already present.

Related

Let Strapi CMS create pages based on html template file

So probably my explanation is awful, but i really don’t know how to express my problem or what to search for.
I got a site (www.example.com/blog.html) showing all blog post entries created in a headless cms (Strapi). The site receives the posts by making an url request and parsing the resulting JSON data. This data also contains an unique url slug for each post serving as an identifier.
I want to create one page for each blog post created in the headless cms based on a „template“ html.
What I tried is passing the urlslug as a url parameter (www.example.com/blog/article.html?id=*URLSLUG*) and then using this url parameter to fetch the corresponding post data from the cms. I followed this guide: https://strapi.io/blog/build-an-editorial-website-with-vanilla-java-script-and-strapi
It works, but I don’t want to rely on url parameters for seo reasons. Instead I want something like www.example.com/blog/*URLSLUG*. In other words: I want to have one page for each blog post entry in my headless cms based on a „template“ html.
Any suggestions?
Code can be added if necessary
well there is few options here:
The first one is most reliable, and easy but seems not that fancy as you want:
https://market.strapi.io/plugins/strapi-plugin-slugify
The main reason to use this solution is that it handles slug creation when you create post via REST api. The uuid field needs extra work when post created not from admin panel.
So second option is do it yourself style:
/api/article/controller/article.js
module.exports = createCoreController('api::article.article', ({strapi}) => ({
findOne(ctx){
const { slug } = ctx.params;
return strapi.db.query('api::article.article').findOne({where: {slug});
}
});
then in the routes create routes.js file
/api/article/routes/routes.js
module.exports = {
routes: [
{
method: 'GET',
path: '/articles/:slug'
handler: 'article.findOne'
}
]
}
then if you want to create articles for outside of admin, create lifecycles.js in
/api/article/content-types/article/lifecycles.js
module.exports = {
async beforeCreate(event) {
// here you have to do something like
let slug = slugify(event.result.name);
let isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree)) // < not sure prolly need an empty object check
for (let i = 1; i < 9999 ; i++) {
slug = `${slug}-${i}`;
isNotFree = await strapi.db.query("api::article.article").findOne({where: {slug}});
if (Boolean(!isNotFree))
break;
}
event.result.slug = slug
}
}
pleas note the lifecycle code is just a first thing came to my mind, should be tested and optimized prolly
the implementation gives you the findOne controller, you gonna need to do it for each other update, delete, etc...

How to fix deleteOne() function of a mongoose model when it does not delete by req.params.id?

Firstly to be mentioned, I'm absolutely new to Node.Js and MongoDB.
I'm coding a back end API with Node.Js and MongoDB which will deal with GET, POST, DELETE requests from the front end, quite simple stuff.
I'm stuck while working with DELETE functionality.
Here is my posts.service.ts file contains this deletePost() function which sends the postId to the back end app.js file.
`
deletePost(postId: string) {
this.http.delete('http://localhost:3000/api/posts/' + postId)
.subscribe(() => {
console.log(postId);
console.log('Deleted');
});
}
`
I have added this console.log(postId) to check whether it is actually containing the actual postId and found that it does. I have also matched it with the real Id in MongoDB by checking through mongo shell.
Here is the delete() function in the back end app.js file that should do the actual task.
`
app.delete("/api/posts/:id", (req, res, next) => {
Post.deleteOne({ _id: req.params.id }).then(result => {
console.log(result);
res.status(200).json({message: "Post deleted"});
});
});
`
The console.log(result) line should print some result in the terminal, but it does not, so does not it delete the collection in the DB.
I`m running this on an Ubuntu 16.04 LTS pc.
Some clue would mean great help. Thank you very much for your kind effort.
deleteOne doesn't return the deleted document. It always deletes the first matching document and return the number of documents deleted with the boolean value.
From the mongodb docs deleteOne:
Returns:
A document containing: A boolean acknowledged as true if the operation ran with write concern or false if write concern was
disabled
deletedCount containing the number of deleted documents
From the mongoose docs
Deletes the first document that matches conditions from the
collection. Behaves like remove(), but deletes at most one document
regardless of the single option.
I was facing exactly the same, i solved returning the deleteOne promise object and then using the .then property of the promise.
Something like this:
Model.js
...
bicicleSchema.statics.deleteById= function(id, cb){
return this.deleteOne({code: id}, cb);
};
...
module.exports = mongoose.model('Bicicle', bicicleSchema);
Service.js
var Bicicle = require('../../../model/bicicle');
...
const id = req.params.id;
Bicicle.deleteById(id).then(()=>{
//your code
});
...

Passing client data into url express routes

I am new to Node/Express, but I am converting my jQuery/Bootstrap app into an app with a node backend for routing and other server side tasks. Currently when a user clicks on a link, it will pass data into the url that I then grab when I get to the new page. Like this:
$("#parking_icon").on("click", function() {
window.location = "_views/parkingLot.html?37.415912?-121.897520";
});
I then grab and use that data on my parkingLot.html page. Like this:
var urlQuery = window.location.search.substring(1);
var mapLatLon = urlQuery.split("?");
var centerCoords = [parseFloat(mapLatLon[1]), parseFloat(mapLatLon[0])];
Now that I am trying to convert to using express routes, I am not exactly sure how to accomplish this. (I have about 20 buttons similar to the one above that all pass different coordinates in). I know I could accomplish this by creating a separate route for each of them similar to this:
app.get('/parkingLot?37.415912?-121.897520', function(req, res) {
res.render('parkingLot', {
title: 'testing ParkingLotPage'
});
});
But it seems like there has to be an easier way. Should I not be using an app.get() at all? I am sure this is a noob question so please forgive me, as I am new to working with Node/Express. I am using the ejs templating engine if that makes any difference.
Think a little more abstractly, if you have a route for /parkinglot with a query string, then we can work with that query string directly on the route.
app.get('/parkinglot', (req, res) => {
let lat = req.query.lat;
let long = req.query.long;
res.render('parkinglot', {
title: '',
data: {
lat: lat,
long: long
}
});
});
Make sure you're properly constructing your query string with the key=value syntax beginning with ? and all Key-Value pairs separated by an &
$("#parking_icon").on("click", function() {
window.location = "_views/parkingLot?lat=37.415912&long=-121.897520";
});

How to use parameters containing a slash character?

My MongoDB keys in person collection are like this:
TWITTER/12345678
GOOGLE/34567890
TWITTER/45678901
...
I define getPersonByKey route this way:
router.route('/getPersonByKey/:providerKey/:personKey').
get(function(req, res) { // get person by key
var key = req.params.providerKey + '/' + req.params.personKey;
// ...
}
);
Of course I'd prefer to be able to write something like this:
router.route('/getPersonByKey/:key').
get(function(req, res) { // get person by key
var key = req.params.key;
// ...
}
);
But this doesn't work, since GET http://localhost/getPersonByKey/TWITTER/12345678 of course results in a 404, since the parameter with the slash is interpreted as two distinct parameters...
Any idea?
Express internally uses path-to-regexp to do path matching.
As explained in the documentation, you can use a "Custom Match Parameter" by adding a regular expression wrapped in parenthesis after the parameter itself.
You can use the following path to get the result you need:
router.route('/getPersonByKey/:key([^/]+/[^/]+)').
get(function(req, res) { // get person by key
var key = req.params.key;
// ...
}
);
You can test and validate this or any other route here.
You can use this if your parameters has containing slashes in it
app.get('/getPersonByKey/:key(*)', function(req, res) { ... })
It works for me (at least in Express 4). In my case, I used parameters like ABC1/12345/6789(10).
Hopefully this useful.
app.get('/getPersonByKey/:key(*)', function(req, res) { ... })
This isn't working for me.
Swagger-ui will encode the path var before using it.
e.g. article/2159 will become article%2F2159.
When going directly with curl, it will not get encoded. the slash will remain a slash instead of %2F. And then the route is not matched.
Update: I'm on fastify. On express 4.X this works correctly.

In Meteor Js how do I add a referral code from query string to user profile?

I'm using the accounts-entry package in a Meteor application. I want to be able to give partners to our application the ability to refer users to us with a link, eg: ourawesomeapp.com?partnerId=1234. When a user comes from a partner I want to be able to store that in the users collection under a partnerId field to pay commissions when users spend money with us. I'm currently trying to use this: (note this Accounts.onCreateUser() method runs on the server only)
Accounts.onCreateUser(function(options, user){
user.partnerId = partnerId from the query string here...;
return user;
});
The spot I'm getting stuck at is getting the partnerId from the query string to the server to be able to use it there.
If you use the recommended routing package for Meteor, iron-router, you can access the query string like this:
// given the url: "/?partnerId=1234"
Router.route('/', function () {
var partnerId = this.params.query.partnerId;
});
If the query string isn't available on the server, an option is to make the partnerId a URL path instead of query string:
Router.route('/partner/:_id', function () {
var partnerId = this.params._id;
}, {where: 'server'});
More in the iron-router guide.

Categories