unable to get rows of "router.navigation" - aurelia

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!

Related

How to make text interpolation work inside css functions and router links

I was trying to implement a reusable card component, so I printed them out inside variable properties that is changed image by image
This is my code. As for title, it works perfectly. I implemented it many times, so my issue is different. I also added this props' text inside mustaches, so I can change link and image out of my card, but it doesn't work, so I need your help. I might just not understand how text interpolation works. But I think that vue supports the way to create reusable cards within a component
<template>
<RouterLink class="card" to="{{ link }}">
<div class="card__background" style="background-image: url({{ image }})"></div>
<div class="card__content">
<h3 class="card__heading">{{ title }}</h3>
</div>
</RouterLink>
</template>
<script>
import { RouterLink } from 'vue-router';
export default {
props: ['link', 'image', 'title'],
created() {
console.log(this.link)
console.log(this.image)
console.log(this.title)
},
}
</script>
I think you need to use the v-bind directive. This directive allows you to bind the value of an HTML attribute to a dynamic expression.
Here's how you can modify your code to use the v-bind directive:
<template>
<RouterLink class="card" v-bind:to="link">
<div class="card__background" v-bind:style="{ backgroundImage: `url(${image})`
}"></div>
<div class="card__content">
<h3 class="card__heading">{{ title }}</h3>
</div>
</RouterLink>
</template>
<script>
import { RouterLink } from 'vue-router';
export default {
props: ['link', 'image', 'title'],
created() {
console.log(this.link)
console.log(this.image)
console.log(this.title)
}
}
</script>

Cannot render list using V-for in VueJs

I am very new in Vue and I am trying to loop through an array. Don't exactly know what I am doing wrong but the list is not displaying on HTML. Here is the code below: This is an index file that is being rendered through a router view.
<template>
<div class="index container">
<div class="card" v-for="tournament in tournaments" :key="tournament.id">
<div class="card-content">
<h2 class="indigo-text">{{tournament.title}}</h2>
<ul class="tournaments">
<li v-for="(score,index) in tournamnet.scores" :key="index"></li>
<span class="chip">{{score}}</span>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'index',
data () {
return {
tournaments:[
{title:'Muthaiga golf Tournament',slug: 'muthaiga-golf-tournament',scores:['Round 1', 'Round 2', 'Round 3'],id:'1'},
{title:'Wilson Churchhill',slug: 'Wilson Churchhill',scores:['Round 1', 'Round 2', 'Round 3'],id:'2'},
]
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
</style>
Here is the router view index.js
import Vue from 'vue'
import Router from 'vue-router'
import index from '#/components/index'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'index',
component: index
}
]
})
And here is the app.vue
<template>
<div id="app">
<navbar />
<router-view/>
</div>
</template>
<script>
import navbar from '#/components/navbar'
export default {
name: 'App',
components:{
navbar
}
}
</script>
Any help will be highly appreciated.
Place your span inside the v-for
<ul class="tournaments">
<li v-for="(score,index) in tournament.scores" :key="index+'tournament'">
<span class="chip">{{score}}</span>
</li>
</ul>
Also, it is better not to use the index as a key, I added string 'tournament' to make it more unique.
Additionally, please make sure you got the spelling corrected for 'tournament'.
Link to official docs.
You have a typo on <li v-for="(score,index) in tournamnet.scores" :key="index"></li>
Mispelled tournament
If you look in the console you should see
vue.runtime.esm.js?2b0e:619 [Vue warn]: Property or method "score" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> <Index> at src/components/index.vue
<App> at src/App.vue
<Root>

Implementing a reusable tabbed component using Vuejs

I'm trying to implement a tabbed reusable component in vueJs but I'm getting an error that a particular component is not defined. Below are both components
//TabComponent
<template>
<div>
<div class="row">
<div class="col-lg-12 col-xl-12">
<div class="card-box">
<ul class="nav nav-tabs nav-bordered">
<li v-for="tab in tabs" :key="tab" class="nav-item">
{{tab}}
</li>
</ul>
<div class="tab-content">
<component :is="selectedComponent"></component>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TabComponent',
props: [ selectedComponent, tabs ] //The error is coming from this line
}
</script>
I have imported it to this component and currently it shows the error
Uncaught ReferenceError: selectedComponent is not defined
//Entitlements component
<template>
<div>
<tab-component :tabs="tabs" :selectedComponent="selectedComponent" />
</div>
</template>
<script>
import TabComponent from "../../../components/TabComponent";
import List from "./Entitlements/List";
import MyEntitlements from "./Entitlements/MyEntitlements";
export default {
name: 'Entitlements',
components: {List, MyEntitlements, TabComponent},
data(){
return{
tabs: ['List', 'MyEntitlements'],
selectedComponent: 'List',
}
}
}
</script>
HTML attribute names are case-insensitive, so browsers will interpret
any uppercase characters as lowercase. That means when you’re using
in-DOM templates, camelCased prop names need to use their kebab-cased
(hyphen-delimited) equivalents (source)
Try with:
<tab-component :tabs="tabs" :selected-component="selectedComponent" />
Edit:
If you define props as an array, change the list with strings (see "Prop types" here):
props: [ 'selectedComponent', 'tabs' ]

Vue how to customize global navbar at view level

Im super new to Vue.
i have a Vue-CLI app, which have a navbar and content.
Navbar is common to all pages, but i want to customize in each page whit some additional content.
Example:
Common-> home | about
View home -> home | about | your are in view home
View about -> home | about | your are in view about
router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import NavBar from '#/components/NavBar.vue';
Vue.use(VueRouter);
Vue.component('nav-bar', NavBar);
//...
components/navbar.vue
<template>
<div>
<b-nav-item to="/">home</b-nav-item>
<b-nav-item to="/about">about</b-nav-item>
{{customContent}}
</div>
</template>
<script>
export default {
name: 'NavBar',
props: {
customContent: {
type: String,
default: 'default Content',
},
},
};
</script>
App.vue
<template>
<div id="app">
<nav-bar />
<div class="container-fluid">
<router-view />
</div>
</div>
</template>
views/home.vue
<template>
<div class="row">
<div class="col-12">
<image-card :images="images"/>
</div>
</div>
</template>
<script>
//how can i customize here the navbar by adding for example 'your are in view home'???
</script>
Thanks so much!
There are a few ways in which you can solve this problem. I'll list two of them.
1. Update NavBar by $route
In this approach, the NavBar component already contains all of the possible combinations, and will display the relevant portion(s) depending on what $route contains.
Here's some pseudo code:
navbar.vue
<template>
<div class="navbar">
<div class="navbar-left>
APPNAME
</div>
<div v-if="name === 'landing'">
...
</div>
<div v-else-if="name === 'room'">
...
</div>
</div>
</template>
App.vue
<template>
<div id="app">
<NavBar :name="$route.name"/>
<main>
<router-view/>
</main>
</div>
</template>
In this example, the NavBar component is very rigid, and doesn't really lend itself to much reuse. However, it does encapsulate all the relevant code relating to the nav bar.
2. Extensible NavBar with slots
In this approach, the NavBar only provides the bare-minimum to create a nav bar. The rest of the route-specific elements are to be filled in by the views.
navbar.vue
<template>
<div class="navbar">
<div class="navbar-left">
<div class="navbar-brand">
APPNAME
</div>
<slot name="left"></slot>
</div>
<div class="navbar-right">
<slot name="right"></slot>
</div>
</div>
</template>
App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
landing.vue
<template>
<div>
<header>
<NavBar>
<template slot="right">
<span>
<div class="navbar-item">
<div class="buttons">
<button class="button" #click="...">Start Watching</button>
</div>
</div>
</span>
</template>
</NavBar>
</header>
<main>
...
</main>
</div>
</template>
This approach has a bit of repetition in terms of DOM elements, but gives you an extremely flexible NavBar that can be customized by each view.
The approach you want to use depends on what is important to you.
If strict encapsulation is what you want, then you may want to use approach 1, as all of the NavBar-related code is contained within a single file.
However, if you believe that there is a potential for reuse, or if you would like all view-related code to live in one place, then it makes sense to use slots instead and extend the NavBar as required by each view.
I use a breadcrumb to achieve a similar thing. Just an idea but Vue router allows you to add meta data to the current route which you always have access to
router.js
path: '/add',
name: 'add',
component: () => import(/* webpackChunkName: "add" */ '../../views/Add.vue'),
meta: {
breadCrumb: [
{ name: 'Add New' }
]
},
Notice the meta object attached to the route.. this will be used to describe the current view.
Breadcrumb.vue component
<template>
<div class="breadcrumb">
<ul class="d-flex m-0 p-0"
<li
v-for="(breadcrumb, idx) in breadcrumbList"
:key="idx">
{{ breadcrumb.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Breadcrumb',
data () {
return {
breadcrumbList: []
}
},
mounted () { this.updateList() },
watch: { '$route' () { this.updateList() } },
methods: {
routeTo (pRouteTo) {
if (this.breadcrumbList[pRouteTo].link) this.$router.push(this.breadcrumbList[pRouteTo].link)
},
updateList () { this.breadcrumbList = this.$route.meta.breadCrumb },
formatPath(path) {
const newPath = path.replace(/\//g, " > ")
return newPath
}
}
}
</script>
And then you can import the breadcrumb into your navbar or where ever you would like to place it
<Breadcrumb class="breadcrumb" />
import Breadcrumb from '#/components/Breadcrumb.vue'
components: {Breadcrumb}
So basically the breadcrumb will always watch your current route and change the data based on the meta data you provide in your router.js file
You can access to router name like this:
<div v-if="this.$route.name == 'home'">
<HeaderTransparent />
</div>
<div v-else>
<HeaderWhite />
</div>

Nav not showing up in aurelia

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.)