I am trying to mimic this example from react-router. I dug through some issues on GH and it doesn't seem possible. At the same time, though, isn't this something that is basic/common among web apps? Am I missing something obvious?
My current structure is:
/pages
/session
[sid].js
/topics
[tid].js
The session page has a list of topics that I want to update on the [sid].js page. However, everything I tried just navigates to [tid].js. I've tried using <Link> with replace but this doesn't do what I want because I do still want the item in history. I tried router.push but I'm in the same boat and would really like to use a <a> element.
Related
I am trying to make a simple form that slides to the right like this one used by DigitalOcean when you click on "Sign up using email": https://cloud.digitalocean.com/registrations/new.
The transition itself is pretty easy, what caught my attention is that they use 2 separate routes for this, the first one under /new and the other one under /email. These 2 seem to be separate pages and not just 2 different states to which a route is programmatically added, how can I do this in NextJS?
I believe the feature that you're looking for is shallow routing.
From the Docs:
Shallow routing allows you to change the URL without running data
fetching methods again, that includes getServerSideProps,
getStaticProps, and getInitialProps.
You'll receive the updated pathname and the query via the router
object (added by useRouter or withRouter), without losing state.
Note, however, that:
[s]hallow routing only works for URL changes in the current page.
See also:
next/router - router.push()
Dynamic Routes
This answer by #metaaa may also shed some light re implementation.
Best of luck and happy coding!
I'm fairly new to Next as a framework and I'm trying to determine how best to handle pagination.
My goal is to have urls such as:
/category-one
/category-one/2
/category-one/3
/category-two
/category-two/2
... and so on
*notice the lack of a /1
Next appears to operate through dynamic slugs in the folder/filename e.g.
pages/
[category]/
[page].jsx
However, what I'm struggling to work out, is that how I can have a page template for NON-paginated urls, and one for paginated urls, without essentially copying the file, this ending up with a bunch of extra code to maintain.
My first thought was to see if I could have say:
pages/
[page].jsx
[category]/
[page].jsx
and extend the parent page for the child page, and just add some littles bits to handle the second part of the slug.
However, this doesn't seem to be an option.
I feel like I'm missing something obvious, but I can't seem to find any examples that show a similar setup to what I'm seeking.
I appreciate that the simple answer would be "just have a /1 after the page one and forget the parent page template altogether", but I'd expect that a framework as robust as Next.js would be able to handle something simple like this.
Any help/pointers would be greatly appreciated!
For anybody finding this question and having the same problem, the answer (which was provided by juliomalves in the comments) is exactly what was missing.
Look into optional catch-all routes.
I'm implementing multi-language support in my app, and I guess this is the last thing that I would need in order to be able to change between languages without reloading the whole app/page. (I already have a solution with full page reload.)
For a simple example let's say this is how my router looks:
Router.map(function() {
this.route('search', { path: t('search') });
this.route('item', { path: `${t('item')}/:id`);
});
The t function would be getting the correct translation for the given strings in the currently active language.
The structure of the route hierarchy won't change, the only things that need to be updated are the path strings. Application state should be kept, of course.
I'm wondering whether this is possible to do.
I am not %100 sure about the correctness of what I wrote but Router.map is executed and resources with the definitions given within this method is transformed to a DSL instance and that is then passed to the actual router maintained by Ember.Router itself. In order to achieve what you want I believe what we need is dynamic modification to the router even if it is just the paths you need yo modify not the whole route structure.
If you look at the following github issue, Ember.js no more supports dynamically adding routes (hence no dynamic modification to the existing ones I believe). With all that said, I believe what you want is not possible without reloading the whole app (hence losing the application state).
I'm making a mobile app using Cordova and AngularJS. Currently I have installed ui-router for routing but I'm open to any other alternative for routing.
My desire: I want to cache certain views bound with parameters. In other words I want to cache paths (or pages).
Example situation: let's say that we see some dashboard page, click on some book cover which redirects to the path book/2. This path is being loaded for the first time into app. Router redirects from HomeController to BooksController (whatever the name). Now the BooksController loads data for given $stateParams (book id = 2) and creates view filled with info about chosen book.
What I want in this situation:
I go back to the dashboard page - it is already loaded (cached?)
I choose book #2 again
Controller or router notices that data about this book is already loaded
The view isn't being recreated, instead it's being fetched from cache
Actually, it would be best to cache everything what I visit based on path. Preloading would be cool too.
Reason: performance. When I open some list of books then I want it to show fast. When view is being created every time, then animation of page change looks awful (it's not smooth).
Any help would be appreciated.
EDIT:
First of all, since I believe it's a common problem for many mobile HTML app programmers, I'd like to precise some information:
I'm not looking for hacks but a clear solution if possible.
Data in the views uses AngularJS, so YES, there are things like ng-bind, ng-repeat and so on.
Caching is needed for both data and DOM elements. As far as I know, browser's layout operation is not as expensive as recreating whole DOM tree. And repaint is not what we can omit.
Having separate controllers is a natural thing. Since I could leave without it I cannot imagine how it would work anyway.
I've got some semi-solutions but I'm gonna be strict about my desire.
Solution 1.
Put all views into one file (I may do it using gulp builder) and use ng-show. That's the simplest solution and I don't believe that anyone knowing AngularJS would not think about it.
A nice trick (from #DmitriZaitsev) is to create a helper function to show/hide element based on current location path.
Advantages:
It's easy.
KIND OF preload feature.
Disadvantages:
all views have to be in a single file. Don't ask why it's not convenient.
Since it's all about mobile devices, sometimes I'd like to "clear" memory. The only way I can think of is to remove those children from DOM. Dirty but ok.
I cannot easily cache /book/2 and /book/3 at the same time. I would have to dynamically create DOM children on top of some templates for each view bound with parameters.
Solution 2.
Use Sticky States AND Future States from ui-router-extras which is awesome.
Advantages:
Separated views.
Very clear usage, very simple since it's just a plugin for ui-router.
Can create dynamic substates. So it would be possible to cache book1, book2 but I'm not sure about book/1 and book/2
Disadvantages:
Again, I'm not sure but I didn't found an example with caching a pair/tuple (view, parameters). Other than that it looks cool.
This is precisely the problem I had to solve for my site 33hotels.com. You can check it and play with the tabs "Filter" and "Filter List" (corresponding to different Routes), and see that the View is updated instantly without any delay!
How did I do it? The idea is surprisingly simple - get rid of the Router!
Why? Because the way the Router works is it re-compiles the View upon every single Route change. Yes, Angular does cache the Template but not the compiled View populated with data. Even if data do not change! As the result, when I used the Router in the past, the switch always felt sluggish and non-reactive. Every time I could notice annoying delay, it was a fraction of second but still noticeable.
Now the solution I used? Don't re-compile your Views! Keep them inside your DOM at all times! Then use ng-hide/ng-show to hide/show them depending on the routes:
<div ng-show="routeIs('/dashboard')">
<-- Your template for Dashboard -->
</div>
<div ng-show="routeIs('/book')">
<-- Your template for Book -->
</div>
Then create a function routeIs(string) inside your Controller to test if $location.path() matches string, or begins with string as I am using it. That way I still get my View for all pathes like /book/2. Here is the function I am using:
$scope.routeBegins = function () {
return _.some(arguments, function (string) {
return 0 === $location.path().indexOf(string);
});
};
So no need to be smart with caching - just keep it in the DOM. It will cache your Views for you!
And the best part is - whenever your data is changed, Angular will instantly update all the Views inside your DOM, even the hidden ones!
Why is this awesome? Because, as user, I don't have to wait for all the parsing and compiling at the moment I want to see the result. I want to click the tab and see my results immediately! Why should the site wait for me to click it and then begin all the re-compiling as I am waiting? Especially when this could be easily done before, during the time my computer is idle.
Is there any downside? The only real one I can think of is loading memory with more DOM elements. However, this actual byte size of my views is negligible, comparing e.g. with all JS, CSS and images.
Another possible but avoidable downside is the re-compilation cost of the hidden views. This is where you can get smart and avoid computation-heavy parts depending on the current routes.
Also, you are not re-compiling the whole View, just the parts affected by data changes, which also lowers computational cost.
I find it quite remarkable that everyone is using Routes and seems to be completely unaware (or ignorant) of this problem.
1) About static pages in the app (views), angular takes care of loading them.
for example: for your dashboard page you need not worry about caching the page, as angular will take care of it. Angular will only load the dashboard view once and on all next requests for the dashboard view, angular will just show you the view(not load the file for view), if it is all a static view without any data loaded by ajax calls.
2) if your dashboard is itself loading the book list(or similar data) via ajax, then you can tell your controller to only load the data once and store it to localstorage and on subsequent requests to the dashboard page can only load the data from the localStorage.
3) similar approach can be used when your BooksController loads the data into a view. You can check in your BooksController if the request for a particular book is been previously made and if not your can store it to localstorage or database. and if the data was previously requested then you can load the same data from the storage without making a request to server.
Example situation:
say user makes request for book1, then
your controller i.e BooksController check whether the same data was requested before,
if not, you can load the data via the ajax call from server and also save it to local storage.
if it was loaded before you will load the data stored in the localstorage or in the database.
If you're using ui.router, then you should take a look at ui.router extras, specifically the sticky states module. This allows you to cache the state 'tree' (including rendered views) so they don't have to be compiled or re-rendered on state changes.
http://christopherthielen.github.io/ui-router-extras/
Here's a demo:
http://christopherthielen.github.io/ui-router-extras/example/sticky/#/
I'm trying to add the equivalent of rails' "flash" functionality in my backbone app, part of which involves putting a showFlash() at the top of each route in my router, and a purgeFlash() at the bottom.
Needless to say, adding those two methods to every route works, but it isn't the most elegant approach. Still, I'm struggling to figure out how to add hooks to backbone routers.
In short, I'd like to run showFlash() before navigating to any new page, and purgeFlash() afterwards. ...Any thoughts?
This plugin should do the trick:
https://github.com/angelo0000/backbone_filters
(not sure though if it works with the latest backbone version)
update - according to this comment it works with 0.9.2