I am learning Aurelia and have stuck at this for quite a while. I want to add a navigation bar at the top of the screen using routing in Aurelia.
app.js:
export class App {
configureRouter(config, router) {
this.router = router;
config.map([
{
route: "add",
moduleId: "./add",
title: "Add new Post",
nav: "true",
name: "Add"
}
]);
}
... rest of the code
app.html:
<template>
<nav class="navbar navbar-default">
<div class="container-fluid">
<ul class="nav navbar-nav">
<li repeat.for="row of router.navigation">
<a href.bind="row.href">${row.title}</a>
</li>
</ul>
</div>
</nav>
</template>
Nothing shows up when I load the app. The navbar remains empty. Is there any required dependency to use the router? Am I missing anything? Thanks.
Note: Not sure if this is enough context to answer my question. I can add config.js or any other file if it's required.
Update : I replaced ${row.title} with hello (any hard coded string) and it's not showing up.
Thanks to comment from doeck I fixed the issue. I had to do two things:
add a <router-view></router-view> tag in my app.html
add an empty route in my app.js as follows: route: ["", "home"],
(When I didn't give the empty route, aurelia gave an error asking route "/" is not defined.)
Related
I have a routing structure such as:
{
path: '/post/'
component: Post,
children: [
{
path: '/',
component: Text,
},
{
path: 'text/',
component: Text,
},
{
path: 'video/',
component: Video,
},
],
}
The important thing is that the route /post/text/ is just an "alias" to the /post/ (root point in this case). Also the router configuration has the custom linkActiveClass option such as 'act' with some defined styles.
In the parent template I have the kind of tabs with router-link's:
<ul>
<li>
<router-link to="/post/text/">Text</router-link>
</li>
<li>
<router-link to="/post/video/">Video</router-link>
</li>
</ul>
So the question is: when going to the /post/ route it would be nice the Text tab to be marked as "active" with that 'act' class because it's just a duplicate of the /post/text/ (or vice versa).
I haven't found any mention of this in the Vue Router docs. How such problems are solved competently?
Thanks in advance!
Solution (TL;DR - currently unsupported, fixed in v4)
The easiest way to achieve this - to use route alias prop, like:
{
path: 'text/',
component: Text,
alias: '/',
},
But, unfortunately, active-class doesn't work properly with aliases yet. It has been fixed in Vue Router v4.
You can do something like this
<ul>
<li :class="[currentPage.includes('/post/text/') ? 'activeClass' : 'no-active-class']">
<router-link to="/post/text/">Text</router-link>
</li>
<li :class="[currentPage.includes('/post/video/') ? 'activeClass' : 'no-active-class']">
<router-link to="/post/video/">Video</router-link>
</li>
</ul>
If your header or browser is a single component, you can include all this functionality in each of your links and it should work correctly.
NOTE: The variable with your current path will depend on the type of project and certain settings in it.
Use the Vuex state.
When every pages go to the tab area are mounted, call a setter for currentPage state.
And you can give an active class according to the state value
<li>
<div :class="{ 'active': currentPage === 'Text'}">
<router-link to="text">Text</router-link>></div>
</li>
<li>
<div :class="{ 'active': currentPage === 'Video'}">
<router-link to="video">Video</router-link>></div>
</li>
using exact-active-class solved a similar problem to yours.
docs: https://router.vuejs.org/api/#exact-active-class
In my Laravel 5/vuejs 2/ VueRouter / app I have navigation area :
<li class="navigation_item_top">
<router-link :to="{ name: 'DashboardIndex' }" class="a_link">
Dashboard
</router-link>
</li>
<li class="active navigation_item_top" >
Customers
<ul class="collapse list-unstyled ml-2" id="backendCustomersSubmenu">
<li class="mt-2">
<router-link :to="{name : 'listCustomers'}" class="a_link">
Customers
</router-link>
</li>
<li class="mt-2">
<router-link :to="{name : 'listCustomers', params: { filter: 'new' } }" class="a_link">
New Customers
</router-link>
</li>
<li class="mt-2">
<router-link :to="{name : 'listCustomers', params: { filter: 'inactive' } }" class="a_link">
Inactive Customers
</router-link>
</li>
</ul>
</li>
Where there are 3 links listCustomers with different default filter opening page and it works ok if from
DashboardIndex page I move to any listCustomers.
But it does not work if from opened listCustomers page I open listCustomers with other filter.
I suppose as VueRouter considers all listCustomers as 1 page.
If there is a way to make it and selecting other listCustomers to reopen filter?
Not sure if i understand your Q very well, but i think you want to:
Append query to url. e.g company.com/listCustomers?filter=new
Make Vue notice the change and do something with that change
If that's the case then try this :
<template>
<--! HTML HERE -->
</template>
<script>
export default {
watch: {
'$route'(to, from){
// you don't need this but just in-case.
//this.$forceUpdate();
//If you're using query like ?filter=new, this should work
if (this.$route.query.filter) {
if (this.$route.query.filter== 'new') {
}else{
}
}
}
}
}
</script>
N.B
If you want use parameters it means you expect your url to be:
domain.com/listCustomers/inactive.
so just try the basics and link like this:
<router-link to="/listCustomers/inactive">
or
<router-link to="/listCustomers/new">.
And if your want queries your url is going to be:
domain.com/listCustomers?filter=new.
and you should pass exact prop to activate active page style.
then you need to watch for changes in the watch hook just like i did my answer
Now all the been said,
linking with parameters should work without any problem, but if you decide to use any Navigation Guards technique, like router.afterEach.
Please do not forget to add next(), to allow it to move on after your code. otherwise it won't navigate.
read Navigation Guards.
I hope you will understand.
My page currently has Navigation.vue component.
I want to make the each navigation hover and active. The hover works but active doesn't.
This is how Navigation.vue file looks like :
<template>
<div>
<nav class="navbar navbar-expand-lg fixed-top row">
<router-link tag="li" class="col" class-active="active" to="/" exact>TIME</router-link>
<router-link tag="li" class="col" class-active="active" to="/CNN" exact>CNN</router-link>
<router-link tag="li" class="col" class-active="active" to="/TechCrunch" exact>TechCrunch</router-link>
<router-link tag="li" class="col" class-active="active" to="/BBCSport" exact>BBC Sport</router-link>
</nav>
</div>
</template>
And the following is the style.
<style>
nav li:hover,
nav li:active {
background-color: indianred;
cursor: pointer;
}
</style>
This is how hover looks like now and expected exactly same on active.
I would appreciate if you give me an advice for styling router-link active works.
Thanks.
The :active pseudo-class is not the same as adding a class to style the element.
The :active CSS pseudo-class represents an element (such as a button)
that is being activated by the user. When using a mouse, "activation"
typically starts when the mouse button is pressed down and ends when
it is released.
What we are looking for is a class, such as .active, which we can use to style the navigation item.
For a clearer example of the difference between :active and .active see the following snippet:
li:active {
background-color: #35495E;
}
li.active {
background-color: #41B883;
}
<ul>
<li>:active (pseudo-class) - Click me!</li>
<li class="active">.active (class)</li>
</ul>
Vue-Router
vue-router automatically applies two active classes, .router-link-active and .router-link-exact-active, to the <router-link> component.
router-link-active
This class is applied automatically to the <router-link> component when its target route is matched.
The way this works is by using an inclusive match behavior. For example, <router-link to="/foo"> will get this class applied as long as the current path starts with /foo/ or is /foo.
So, if we had <router-link to="/foo"> and <router-link to="/foo/bar">, both components would get the router-link-active class when the path is /foo/bar.
router-link-exact-active
This class is applied automatically to the <router-link> component when its target route is an exact match. Take into consideration that both classes, router-link-active and router-link-exact-active, will be applied to the component in this case.
Using the same example, if we had <router-link to="/foo"> and <router-link to="/foo/bar">, the router-link-exact-activeclass would only be applied to <router-link to="/foo/bar"> when the path is /foo/bar.
The exact prop
Lets say we have <router-link to="/">, what will happen is that this component will be active for every route. This may not be something that we want, so we can use the exact prop like so: <router-link to="/" exact>. Now the component will only get the active class applied when it is an exact match at /.
CSS
We can use these classes to style our element, like so:
nav li:hover,
nav li.router-link-active,
nav li.router-link-exact-active {
background-color: indianred;
cursor: pointer;
}
The <router-link> tag was changed using the tag prop, <router-link tag="li" />.
Change default classes globally
If we wish to change the default classes provided by vue-router globally, we can do so by passing some options to the vue-router instance like so:
const router = new VueRouter({
routes,
linkActiveClass: "active",
linkExactActiveClass: "exact-active",
})
Change default classes per component instance (<router-link>)
If instead we want to change the default classes per <router-link> and not globally, we can do so by using the active-class and exact-active-class attributes like so:
<router-link to="/foo" active-class="active">foo</router-link>
<router-link to="/bar" exact-active-class="exact-active">bar</router-link>
v-slot API
Vue Router 3.1.0+ offers low level customization through a scoped slot. This comes handy when we wish to style the wrapper element, like a list element <li>, but still keep the navigation logic in the anchor element <a>.
<router-link
to="/foo"
v-slot="{ href, route, navigate, isActive, isExactActive }"
>
<li
:class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']"
>
<a :href="href" #click="navigate">{{ route.fullPath }}</a>
</li>
</router-link>
https://router.vuejs.org/en/api/router-link.html
add attribute active-class="active"
eg:
<ul class="nav navbar-nav">
<router-link tag="li" active-class="active" to="/" exact><a>Home</a></router-link>
<router-link tag="li" active-class="active" to="/about"><a>About</a></router-link>
<router-link tag="li" active-class="active" to="/permission-list"><a>Permisison</a></router-link>
</ul>
When you are creating the router, you can specify the linkExactActiveClass as a property to set the class that will be used for the active router link.
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes,
linkActiveClass: "active", // active class for non-exact links.
linkExactActiveClass: "active" // active class for *exact* links.
})
This is documented here.
As mentioned above by #Ricky vue-router automatically applies two active classes, .router-link-active and .router-link-exact-active, to the <router-link> component.
So, to change active link css use:
.router-link-exact-active {
//your desired design when link is clicked
font-weight: 700;
}
Just add to #Bert's solution to make it more clear:
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
const router = new VueRouter({
routes,
linkExactActiveClass: "active" // active class for *exact* links.
})
As one can see, this line should be removed:
linkActiveClass: "active", // active class for non-exact links.
this way, ONLY the current link is hi-lighted. This should apply to most of the cases.
David
Let's make things simple, you don't need to read the document about a "custom tag" (as a 16 years web developer, I have enough this kind of tags, such as in struts, webwork, jsp, rails and now it's vuejs)
just press F12, and you will see the source code like:
<div>
page1
page2
page3
</div>
so just add styles for the .router-link-active or .router-link-exact-active
If you want more details, check the router-link api:
https://router.vuejs.org/guide/#router-link
While I am new to Aurelia, I am really liking Aurelia. I have read the "Getting started" with Aurelia and have done some reading on configure router. Specifically I am using http://mobilemancer.com/2016/11/18/using-router-in-aurelia-spa/ as a basis for my understanding.
I am following the normal conventions (app.ts, app.html and navigation.html). I am unable to get the "repeat.for" to iterate over the rows (specifically in this case one row) in router.navigation. I am sure that I am making some elementary mistake. But unable to find out what. Both of app.html and navigation.html seem to be "executing" in terms of seeing both "Aurelia Router Demo" and "nice" appearing on the browser.
Thanks for your help!
app.ts
import { autoinject } from 'aurelia-framework';
import { RouterConfiguration, Router } from 'aurelia-router';
#autoinject
export class App {
public router: Router;
configureRouter(config: RouterConfiguration, router: Router): void {
this.router = router;
config.title = ' Test ';
config.map( [
{route: ['', 'home'], name: 'home', moduleId: './home', nav: true, title: 'Home'},
]);
}
}
app.html
<template>
<require from="./navigation.html"> </require>
<h1> Aurelia Router Demo </h1>
<navigation router.bind="router"> </navigation>
<div class="page-host">
<router-view>
</router-view>
</div>
</template>
--navigation.html
<template bindable="router">
<h2> nice </h2>
<nav>
<ul>
<li repeat.for="row of router.navigation">
<a href.bind="row.href"> ${row.title} </a>
</li>
</ul>
</nav>
</template>
I don't see anything wrong at first glance. Try using compose instead of binding the router to see if that works. compose without a specified view-model attribute uses the consumer's view-model, removing the necessity of passing the router through data binding. Note that when requiring a custom element with a .html extension, Aurelia automatically generates a view model for it.
Basically, use compose instead of navigation:
app.html
<template>
<h1> Aurelia Router Demo </h1>
<compose view="./navigation.html"> </compose>
<div class="page-host">
<router-view>
</router-view>
</div>
</template>
And remove bindable="router" from:
navigation.html
<template>
<h2> nice </h2>
<nav>
<ul>
<li repeat.for="row of router.navigation">
<a href.bind="row.href"> ${row.title} </a>
</li>
</ul>
</nav>
</template>
In my configuration , including aurelia-routing.min.js as a script tag does NOT do the work. (Possible duplicate issue at How to install/setup Aurelia router/routes).
If I do a build ( au build) and include the vendor.js, then the thing (repeat.for) works.
Thanks for quick responses!
I have following shell.js
define(function (require) {
var router = require('durandal/plugins/router');
return {
router: router,
activate: function () {
return router.activate('movies/show');
}
};
});
and following shell.html
<div>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<ul class="nav" data-bind="foreach: router.visibleRoutes">
<li data-bind="css: { active: isActive }">
<a data-bind="attr: { href: hash }, html: name"></a>
</li>
</ul>
</div>
</div>
<div class="container-fluid page-host">
<!--ko compose: {
model: router.activeItem, //wiring the router
afterCompose: router.afterCompose, //wiring the router
transition:'entrance', //use the 'entrance' transition when switching views
cacheViews:true //telling composition to keep views in the dom, and reuse them (only a good idea with singleton view models)
}--><!--/ko-->
</div>
</div>
But when I run my application, first div in the shell.html having class="navbar navbar-fixed-top" never renders. What am I missing?
This turned out to be a silly mistake. I use ReSharper quite heavily. So I created a shell.html and then hit F6 to move it to view folder. Resharper instead of moving, copied the file thus leaving the old file behind. All this while I was editing the wrong file. Now I have one shell.html and everything works just ok.