NextJS dynamic routes /[optional_path]/[slug].js - next.js

In NextJS, is it possible to create an optional path in the dynamic route file in some way?
I want to use the same template for mdx pages for routes /blog/<slug> or /<slug> depending upon the frontmatter key type which may equal 'post' or 'page'. If type == 'post', create a /blog/<slug> path, else just create /<slug> directly.
How do I do this?

You probably want optional catch all routes:
Catch all routes can be made optional by including the parameter in double brackets ([[...slug]]).
For example, pages/post/[[...slug]].js will match /post, /post/a, /post/a/b, and so on.
The main difference between catch all and optional catch all routes is that with optional, the route without the parameter is also matched (/post in the example above).
The query objects are as follows:
{ } // GET `/post` (empty object)
{ "slug": ["a"] } // `GET /post/a` (single-element array)
{ "slug": ["a", "b"] } // `GET /post/a/b` (multi-element array)

Related

how to add dash(-) between name of dynamic route Nextjs in url

I create a dynamic route pages/post/[postname].tsx . and when I send name to the dynamic route the url shows name with url-encode (%20,%E2,...)
I want to show name of the url with dash between words. like below url
https://stackoverflow.com/questions/68041539/using-dash-in-the-dynamic-route-name-in-nuxt-js
how can I do this?
I've used the getStaticPaths method and pass it an object of slugs before. This has worked for me when dealing with a headless CMS'.
export async function getStaticPaths() {
// Hit API to get posts as JSON
const posts = await getPosts()
// Map a new object with just the slugs
const paths = posts.map((post) => {
return { params: { slug: post.slug } }
})
// Return paths
return {
paths: paths,
fallback: true
}
}
I think I understand the problem, you're trying to use a set of strings with spaces e.g "the fundamentals of starting web development" as path param to achieve something like this https://www.geniushawlah.xyz/the-fundamentals-of-starting-web-development. That will most likely convert your spaces to %20 which is normal. I would have advised you to first use replace() method to change all spaces to hyphen before passing it as param but the replace() method only changes the first space and leave the rest. There are other ways to get rid of the spaces programmatically but may be stressful and not worth it, so I'll advise you use an hyphenated set of strings by default.
If not, try to use a for-loop with the replace() method to change all spaces to hyphens, then pass it as param.

Getting the right permitted fields of conditions

Currently, I'm building an app with with following similar logic:
...
const user = {
isAdmin: true,
company: '5faa6a847b42bf47b8f785a1',
projects: ['5faa6a847b42bf47b8f785a2']
}
function defineAbilityForUser(user) {
return defineAbility((can) => {
if (user.isAdmin) {
can('create', 'ProjectTime', {
company: user.company,
}
);
}
can(
'create',
'ProjectTime',
["company", "project", "user", "start", "end"],
{
company: user.company,
project: {
$in: user.projects
}
}
);
});
}
const userAbility = defineAbilityForUser(user); //
console.log( permittedFieldsOf(userAbility, 'create', 'ProjectTime') );
// console output: ['company', 'project', 'user', 'start', 'end']
Basically an admin should be allowed to create a project time with no field restrictions.
And a none admin user should only be allowed to set the specified fields for projects to which he belongs.
The problem is that I would expect to get [] as output because an admin should be allowed to set all fields for a project time.
The only solution I found was to set all fields on the admin user condition. But this requires a lot of migration work later when new fields are added to the project time model. (also wrapping the second condition in an else-block is not possible in my case)
Is there any other better way to do this? Or maybe, would it be better if the permittedFieldsOf-function would prioritize the condition with no field restrictions?
There is actually no way for casl to know what means all fields in context of your models. It knows almost nothing about their shapes and relies on conditions you provide it to check that objects later. So, it does not have full information.
What you need to do is to pass the 4th argument to override fieldsFrom callback. Check the api docs and reference implementation in #casl/mongoose
In casl v5, that parameter is mandatory. So, this confusion will disappear very soon

How to implement redux-search

I am trying to implement a search filter in my application which uses react/redux using redux-search. The first gotcha I get is when I try to add the store enhancer as in the example.
// Compose :reduxSearch with other store enhancers
const enhancer = compose(
applyMiddleware(...yourMiddleware),
reduxSearch({
// Configure redux-search by telling it which resources to index for searching
resourceIndexes: {
// In this example Books will be searchable by :title and :author
books: ['author', 'title']
},
// This selector is responsible for returning each collection of searchable resources
resourceSelector: (resourceName, state) => {
// In our example, all resources are stored in the state under a :resources Map
// For example "books" are stored under state.resources.books
return state.resources.get(resourceName)
}
})
)
I understand evarything up to the resourceSelector, when I tried to get a deep dive into the example to see how it works but I can barely see how they are generated and the last line returns an error, Cannot read property 'get' of undefined
My state object looks like this
state: {
//books is an array of objects...each object represents a book
books:[
//a book has these properties
{name, id, author, datePublished}
]
}
Any help from anyone who understands redux-search is helpful
If this line:
return state.resources.get(resourceName)
Is causing this error:
Cannot read property 'get' of undefined
That indicates that state.resources is not defined. And sure enough, your state doesn't define a resources attribute.
The examples were written with the idea in mind of using redux-search to index many types of resources, eg:
state: {
resources: {
books: [...],
authors: [...],
// etc
}
}
The solution to the issue you've reported would be to either:
A: Add an intermediary resources object (if you think you might want to index other things in the future and you like that organization).
B: Replace state.resources.get(resourceName) with state[resourceName] or similar.

How to use URL parameters using Meteorjs

How can I use URL parameters with meteor.
The URL could look like this: http://my-meteor.example.com:3000?task_name=abcd1234
I want to use the 'task_name' (abcd1234) in the mongodb query in the meteor app.
eg.
Template.task_app.tasks = function () {
return Tasks.find({task_name: task_name});
};
Thanks.
You are probably going to want to use a router to take care of paths and rendering certain templates for different paths. The iron-router package is the best one available for that. If you aren't using it already I would highly recommend it.
Once you are using iron-router, getting the query strings and url parameters is made very simple. You can see the section of the documentation here: https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#route-parameters
For the example you gave the route would look something like this:
Router.map(function () {
this.route('home', {
path: '/',
template: 'task_app'
data: function () {
// the data function is an example where this.params is available
// we can access params using this.params
// see the below paths that would match this route
var params = this.params;
// we can access query string params using this.params.query
var queryStringParams = this.params.query;
// query params are added to the 'query' object on this.params.
// given a browser path of: '/?task_name=abcd1234
// this.params.query.task_name => 'abcd1234'
return Tasks.findOne({task_name: this.params.query.task_name});
}
});
});
This would create a route which would render the 'task_app' template with a data context of the first task which matches the task name.
You can also access the url parameters and other route information from template helpers or other functions using Router.current() to get the current route. So for example in a helper you might use Router.current().params.query.task_name to get the current task name. Router.current() is a reactive elements so if it is used within the reactive computation the computation will re-run when any changes are made to the route.

How to parse url with Meteor

I'm using Meteor with another CMS, and am creating a url with the variables I need to run Meteor (ex. http://site.com?a=flash&b=hash). How to I make those variables usable, and get Meteor to ignore it as a location? When I load the url like that, my app doesn't load correctly, presumably because it thinks I'm requesting a different location.
Using iron router, if there is a query string or hash fragment in the url, you can access those using the query and hash properties of the this.params object.
// given the url: "/post/5?q=s#hashFrag"
Router.route('/post/:_id', function () {
var id = this.params._id;
var query = this.params.query;
// query.q -> "s"
var hash = this.params.hash; // "hashFrag"
});
Use of the querystring in Meteor should have no effect unless you're using eg. Meteor Router to invoke different methods depending on the current URL.
If you want to parse the querystring, just parse it by hand with eg. (in coffeescript)
querystring: ->
qs = {}
for pair in window.location.search.replace("?", "").split "&"
[k, v] = pair.split("=")
qs[k] = v
qs
Which will return an object like:
{ "a": "flash", "b": "hash" }

Resources