Can you display your child routes in the parent router-outlet? - angular-routing

Main question: is there a way to display a child route to the parent router-outlet?
Consider this example in Angular.io guide for router.
Main Route Snippet:
const appRoutes: Routes = [
...
{
path: 'admin',
loadChildren: 'app/admin/admin.module#AdminModule',
canLoad: [AuthGuard]
},
{
path: 'crisis-center',
loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule',
data: { preload: true }
},
....
];
Main Component Snippet:
#Component({
selector: 'app-root',
template: `
<h1 class="title">Angular Router</h1>
<nav>
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/superheroes" routerLinkActive="active">Heroes</a>
<a routerLink="/admin" routerLinkActive="active">Admin</a>
...
</nav>
<router-outlet></router-outlet>
`
})
CrisisCenter Route Snippet:
const crisisCenterRoutes: Routes = [
{
path: '',
component: CrisisCenterComponent,
children: [
{
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
...
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
CrisesListComponent Snippet:
#Component({
template: `
<ul class="items">
<li *ngFor="let crisis of crises$ | async"
[class.selected]="crisis.id === selectedId">
<a [routerLink]="[crisis.id]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
</li>
</ul>
<router-outlet></router-outlet>
`
})
CrisisDetailComponent Snippet:
#Component({
template: `
<div *ngIf="crisis">
<h3>"{{ editName }}"</h3>
...
</div>
`
})
The output of this router is this:
So. What I'm trying to say is when you click on say Dragon Burning Cities, instead of displaying it under, why not just display it on the CrisesListComponent level?
All I can think of is using *ngIf like this in CrisesListComponent :
#Component({
template: `
<ul class="items" *ngIf="a list is selected hide this!!!">
<li *ngFor="let crisis of crises$ | async"
[class.selected]="crisis.id === selectedId">
<a [routerLink]="[crisis.id]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
</li>
</ul>
<router-outlet></router-outlet>
`
})
Is there like to set the child router to this display on this parent route-outlet?
Thanks. I hope I made my question clear.

I think you can, by adding name to the <router-outlet> selector and add outlet property with that name to children routes.
HTML:
<router-outlet name="test"></router-outlet>
CHILD ROUTES MODULE:
path: '',
component: CrisisCenterComponent,
outlet: "test"
Try that, you may face some issues with nested routes of this child.

Related

$route.params.id dont want to give id data when clicking on drink. CocktailDB API, nuxt.js

Hello Im doing a simple cocktailapp to practice nuxt.js and axios with coktailDB API https://www.thecocktaildb.com/api.php. In drinks/index.vue I have listed all drinks with v-for. When clicking on a drink you get to drinks/_id/index.vue page where the full info about the drink will get showed by its ID. Im using $route.params.id and I have tried with this.$route.params.id. No drink info get showed. Its just shows undefined and brackets. How can I get the drink info to be showed by its ID after been clicking on a specific drink? Thanks in advance!
Drinks/index.vue;
<template>
<div>
<div>
<SearchDrink/>
</div>
<div>
<div v-for="drink in drinks" :key="drink.id">
<nuxt-link :to="'drinks/' + id">
<div class="drink">
<p> {{ drink.strDrink
}} </p>
<img :src="drink.strDrinkThumb" alt=""/>
<p>Instructions:</p>
<p> {{ drink.strInstructions }} </p>
<div class="ing"> Ingridients:
<ul>
<li>{{ drink.strIngredient1 }} </li>
<li>{{ drink.strIngredient2 }} </li>
<li>{{ drink.strIngredient3 }} </li>
<li>{{ drink.strIngredient4 }} </li>
<li>{{ drink.strIngredient5 }} </li>
</ul>
</div>
</div>
</nuxt-link>
</div>
</div>
</div>
</template>
<script>
import SearchDrink from '../../components/SearchDrink.vue'
import axios from 'axios'
export default {
components:{
SearchDrink,
},
data(){
return {
drinks: [],
}
},
methods: {
getAllDrinks(){
axios.get('https://thecocktaildb.com/api/json/v1/1/search.php?s=')
.then((response) => {
this.drinks = response.data.drinks
const myDrink = response.data.drinks
console.log(myDrink)
console.log(myDrink.strDrinkThumb)
})
.catch((error) =>{
console.log(error)
})
},
},
created(){
this.getAllDrinks()
},
// methods: {
// searchDrink(){
// if(!this.search){
// return this.drinks
// }else{
// return this.drinks.filter(drink =>
// drink.text.toLowerCase().includes(this.search.
// toLowerCase()))
// }
// }
// },
head(){
return {
title: 'Drinks App',
meta: [
{
hid: 'description',
name: 'description',
content: 'Best place to search a Drink'
}
]
}
}
}
</script>
Drinks/_id/index.vue;
<template>
<div>
<nuxt-link to="/drinks">
Go Back
</nuxt-link>
<h2> {{ drink }} </h2>
<hr>
<small>Drink ID: {{ this.$route.params.id }}</small>
</div>
</template>
<script>
import axios from 'axios'
export default {
data(){
return{
drink: {}
}
},
methods: {
getAllDrinks(){
axios.get(`www.thecocktaildb.com/api/json/v1/1/lookup.php?i=${this.$route.params.id}`)
.then((response) => {
this.drinks = response.data.drinks
const myDrink = response.data.drinks
console.log(myDrink)
})
.catch((error) =>{
console.log(error)
})
},
},
created(){
this.getAllDrinks()
},
head(){
return {
title: this.drink,
meta: [
{
hid: 'description',
name: 'description',
content: 'Best place to search a Drink'
}
]
}
}
}
</script>
There are quite a few things that be improved here (and the API is a bit messy too).
Here is how I would do it with modern practices.
/pages/drinks/index.vue
<template>
<div>
<div v-for="drink in drinks" :key="drink.idDrink">
<nuxt-link :to="`/drinks/${drink.idDrink}`">
<div class="drink">
<p>{{ drink.strDrink }}</p>
<img width="100px" height="100px" :src="drink.strDrinkThumb" alt="" />
<p>Instructions:</p>
<p>{{ drink.strInstructions }}</p>
<div class="ing">
<p>Ingredients:</p>
<ul>
<li>{{ drink.strIngredient1 }}</li>
<li>{{ drink.strIngredient2 }}</li>
<li>{{ drink.strIngredient3 }}</li>
<li>{{ drink.strIngredient4 }}</li>
<li>{{ drink.strIngredient5 }}</li>
</ul>
</div>
</div>
</nuxt-link>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
drinks: [],
}
},
async fetch() {
await this.getAllDrinks()
},
methods: {
async getAllDrinks() {
try {
const { data } = await axios.get(
'https://thecocktaildb.com/api/json/v1/1/search.php?s='
)
this.drinks = data.drinks
} catch (error) {
console.log('error', error)
}
},
},
}
</script>
/pages/drinks/_id.vue
<template>
<div>
<nuxt-link to="/drinks"> Go Back </nuxt-link>
<h2>{{ drink.strGlass }}</h2>
<hr />
<small>Drink ID: {{ $route.params.id }}</small>
</div>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
drink: {},
}
},
async fetch() {
await this.getAllDrinks()
},
methods: {
async getAllDrinks() {
try {
const { data } = await axios.get(
`https://www.thecocktaildb.com/api/json/v1/1/lookup.php?i=${this.$route.params.id}`
)
this.drink = data.drinks[0]
} catch (error) {
console.log('error', error)
}
},
},
}
</script>
Few notes:
I skipped the parts I don't have access to (like your SearchDrink component) or that are not relevant with the current issue
you probably would need to use the axios module
you don't need to import your Nuxt components, it is done for you

why won't my code update when I add a new Item to the list

I am trying to allow an item to be pushed to a list of times that I looped through using Vue.js. I don't understand why when I click on the button the list item appears but the text doesn't.
HTML
<div id="root">
<input v-modle="newCat" v-on:keyup.enter="addKitty">
<button v-on:click="addKitty">
+add
</button>
<ul>
<li v-for="cat in cats">{{ cat.name }}</li>
</ul>
</div>
Vue.js
app = new Vue({
el: '#root',
data: {
cats:
[{name: 'kitkat'},
{ name: 'fish'},
{ name: 'henry'},
{ name: 'bosco'}],
//new data set
newCat: ''
},
methods: {
addKitty: function() {
this.cats.push({
name: this.newCat
})
this.newCat = ''
}
}
})
There is a typo in your code.
<input v-modle="newCat" v-on:keyup.enter="addKitty">
Should be:
<input v-model="newCat" v-on:keyup.enter="addKitty">
Notice the different spelling for v-model.

VueJS - How can I bind multiple class from object that created by v-for?

I wanted to make it like this:
<ul>
<li class="aaa active">text-aaa</li>
<li class="bbb">text-bbb</li>
<li class="ccc">text-ccc</li>
</ul>
Here's the code. https://jsfiddle.net/qwvwsgb9/
I can bind value calculated by v-for by using non-object format :class="v.name"
<div id="app">
<ul>
<li v-for="v, i in listAry" :class="{v.name:true,active:active==i}">{{ v.text }}</li>
</ul>
</div>
script:
let vm = new Vue({
el: "#app",
data: {
active:0,
listAry: [{
name: 'aaa',
text: 'text-aaa'
}, {
name: 'bbb',
text: 'text-bbb'
}, {
name: 'ccc',
text: 'text-ccc'
}]
}
})
but as long as I tried to apply it in object format, the error occurs.
How can I do it?
Try something like this :class="[{ active: active === i }, v.name]"
<div id="app">
<ul>
<li v-for="v, i in listAry" :class="[{ active: active === i }, v.name]">
{{ v.text }}
</li>
</ul>
</div>

Ionic Unable to view object

I am unable to view object in the page. Can someone help to take a look what am i missing here ? I have my code in code pen http://codepen.io/ccrash/pen/wWXVGj . Really need someone to help out. When I clicked on the list in mainpage, it should bring me to the second page where user details should be displayed. But, I am not seeing any details here.
In App.js
.state('app.person', {
url: "/person/:personId",
views: {
'menuContent': {
templateUrl: "templates/people-detail.html",
controller: 'PersonDetailCtrl'
}
}
})
Controller.js
.controller('PersonDetailCtrl', function($scope, $stateParams, Session, $state, $ionicHistory) {
var Persons = [
{id: 1, name: 'Mickey', Tel: '12345'},
{id: 2, name: 'Donald', Tel: '23444'},
{id: 3, name: 'Goofy', Tel: '12323'}
];
$scope.person = Persons[$stateParams.personId];
})
In people-detail.html
<ion-content ng-controller="PersonDetailCtrl" class="background">
<div>
<i class="{{person.id}}"> </i>
</div>
<div>
<i class="{{person.name}}"> </i>
</div>
</ion-content>
This $scope.person = Persons[$stateParams.locationId]; should be $scope.person = Persons[$stateParams.personId];

Angular 1.5 Component Example

I am fairly experienced using Angular pre-1.5, but I am currently starting to develop a web application based on 1.5 components. After much troubleshooting, I still can't seem to get a basic template working - can I get another set of eyes to please tell me what is wrong with the following simple menu component? I appreciate any assistance that may be offered.
var appMenuTemplate = "
<nav class='menu'>
<ul>
<li ng-repeat='item in menuCtrl.menuItems'>
{{ item }}
</li>
</ul>
</nav>
";
var appMenuController = function() {
var self = this;
self.menuItems = [
'home',
'about',
'portfolio',
'experience'
];
};
angular
.module('exampleApp', [])
.component('appMenu', {
template: appMenuTemplate,
controller: appMenuController,
controllerAs: 'menuCtrl'
});
https://jsfiddle.net/dzaslow/ej8r3vyo/1/
Here's how to do it. I learned how to use components mainly from reading todd motto's posts. You should probably also use templateUrl rather than template.
(function() {
'use strict';
angular
.module('exampleApp', [])
.component('appMenu', {
template: "<nav class='menu'> \
<ul> \
<li ng-repeat='item in vm.menuItems'> \
{{ item }} \
</li> \
</ul> \
</nav>",
controller: AppMenuController,
controllerAs: 'vm'
});
function AppMenuController() {
var vm = this;
vm.menuItems = [
'home',
'about',
'portfolio',
'experience'
];
}
AppMenuController.$inject = [];
})();
.menu > ul > li {
display: inline;
margin-right: 1em;
}
<!DOCTYPE html>
<html ng-app='exampleApp'>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.min.js"></script>
</head>
<body>
<app-menu></app-menu>
</body>
</html>