I am trying to show result from json to table with vue.js
i have no result this is the script:
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4 class="title">Progress Queue's details Live</h4>
</div>
<div class="card-content table-responsive table-full-width">
<el-table :data="tableData2">
<el-table-column label="Name" property="name"></el-table-column>
<el-table-column class="danger" label="Numbers" property="numbers"></el-table-column>
</el-table>
</div>
</div>
</div>
<script>
import ChartCard from 'src/components/UIComponents/Cards/ChartCard.vue'
Vue.use(Table)
Vue.use(TableColumn)
const WorldMap = () => ({
component: import('./../Maps/WorldMap.vue'),
loading: Loading,
delay: 200
})
import axios from 'axios';
import Vue from 'vue'
import {Table, TableColumn} from 'element-ui'
Vue.use(Table)
Vue.use(TableColumn)
// Vue.use(tableRowClassName)
import vSelect from 'vue-select';
//Vue.component('v-select', VueSelect.VueSelect)
export default {
components: {
vSelect,
StatsCard
},
data () {
return {
tableData2: [],
},
mounted() {
axios.get("/statcard").then(response => {
this.tableData2.push({
name: response.data.queue,
numbers: reponse.data.queue_count
});
});
}
}
i recieve no data
the result of the json is :
{"queue_count":"4","queue":"OP_AD_WIN_HARDWARE"},{"queue_count":"35","queue":"OPBO_WIN_Fiber_pend_i"},{"queue_count":"5","queue":"OP_AD_WIN_RELOCATION"},{"queue_count":"44","queue":"OPBO_WIN_Act_pend_i"}]}
Remove mounted from data.
Don't add plugins multiple times.
The element documentation says, that prop is correct, not property.
Work on your line indentation.
<template>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4 class="title">Progress Queue's details Live</h4>
</div>
<div class="card-content table-responsive table-full-width">
<el-table :data="tableData2">
<el-table-column label="Name" prop="queue_count"></el-table-column>
<el-table-column class="danger" label="Numbers" prop="queue"></el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import vSelect from 'vue-select';
import axios from 'axios';
import { Table, TableColumn } from 'element-ui';
import ChartCard from 'src/components/UIComponents/Cards/ChartCard.vue';
Vue.use(Table);
Vue.use(TableColumn);
const WorldMap = () => ({
component: import('./../Maps/WorldMap.vue'),
loading: Loading,
delay: 200
});
export default {
components: {
vSelect,
StatsCard
},
data() {
return {
tableData2: []
};
},
mounted() {
axios.get('/statcard').then(response => {
this.tableData2 = response.data.queue_progress;
});
}
};
</script>
Related
I have products in my database and I have created controller on my backend app that I tested and works really good, so now I need to implement that to my frontend. I have product.component.ts file that looks like this
import { Component, OnInit } from "#angular/core";
import { FormControl, FormGroup } from "#angular/forms";
import { debounceTime, switchMap } from "rxjs";
import { ProductService } from "./product.service";
#Component({
selector: 'app-product',
templateUrl: './product.component.html'
})
export class ProductComponent implements OnInit {
products: any[] = [];
productSearchForm!: FormGroup;
page: number = 0;
size: number = 4;
constructor(
private productService: ProductService
) { }
loadMore() {
this.page = this.page+1;
this.productSearchForm.get('searchTerm')?.valueChanges
.pipe(
debounceTime(500),
switchMap(value => {
return this.productService.searchByTermPageable(value, this.page, this.size);
})
).subscribe(data => {
this.products = data;
}, error => {
console.log(error);
// this.products = [];
});
}
ngOnInit(): void {
this.initializeForm();
this.productSearchForm.get('searchTerm')?.valueChanges
.pipe(
debounceTime(500),
switchMap(value => {
return this.productService.searchByTermPageable(value, this.page, this.size);
})
).subscribe(data => {
this.products = data;
}, error => {
console.log(error);
// this.products = [];
});
}
private initializeForm(): void {
this.productSearchForm = new FormGroup({
searchTerm: new FormControl(null)
});
}
}
searchTerm is a query param that is used to find products with name starting with that term. I call function from file product.service.ts that looks like this
import { HttpClient } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { environment } from "src/environments/environment";
#Injectable({ providedIn: 'root'})
export class ProductService {
constructor(private httpClient: HttpClient) { }
searchByTerm(searchTerm: string): Observable<any> {
const url = `${environment.apiUrl}product/search/by-name-or-desc?term=${searchTerm}`;
return this.httpClient.get(url);
}
searchByTermPageable(searchTerm: string, page: number, size: number): Observable<any> {
const url = `${environment.apiUrl}product/search/by-name-or-desc?term=${searchTerm}&page=${page}&size=${size}`;
return this.httpClient.get(url);
}
}
When I click the button load more I want to load next 4 products from database, but keep the first 4 products on my html page, so what is the best way to do this? This is my html page, and also I am using Bulma as my css framework
<div class="mt-5">
<form>
<div class="field" [formGroup]="productSearchForm">
<div class="control has-icons-left">
<input class="input" type="text" formControlName="searchTerm" placeholder="Find products">
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</div>
</div>
<hr />
</form>
</div>
<div class="columns">
<div class="column" *ngFor="let product of products">
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">{{ product.name }}</p>
<p class="subtitle is-6">{{ product.category?.name}}</p>
</div>
</div>
<div class="content">
{{ product.description }}
</div>
</div>
</div>
</div>
</div>
<button type="button" class="button is-primary" (click)="loadMore()">Load more...</button>
You can to have a new function in your service that return the elements of the page plus the other elements search. If you has a function that return the paginate elements
searchByTermPageable(search:string,page:number,size:number)
{
...
}
Some like
product:any[]=[] //define an empty array where you store the product
searchOld:string=null //and a variable to store the search
getData(search:string,page:number,size:number)
{
if (search!=this.searchOld) //if is a new search
{
this.searchOld=search
this.product=[]
}
return this.searchByTermPageable(search,page,size).pipe(
map((res:any[])=>[...this.product,...res]), //concat the before store product
tap((res:any[])=>{
this.product=res //store in the product the new array
})
)
}
Allow you some like
<div *ngFor="let product of product$|async">
{{product.name}}
</div>
<button (click)="more()">more</button>
pageIndex:number=-1;
product$:Observable<any[]>
more()
{
this.pageIndex++
this.product$=this.dataService.getData("",this.pageIndex,4)
}
The other solution is search all the product and simple use slice pipe
<div *ngFor="let product of allProduct$|async |slice:0:(index+1)*pageSize">
{{product.name}}
</div>
<button (click)="index=index+1">more</button>
a litle stackblitz
I am trying to make cards from an array of objects containing ids and URL (relative paths ) to my images. But when I try to use mapping to return arrays and use background CSS property to set images I am unable to do it. Below is the code
import React from "react";
import { useState } from "react";
import { Fragment } from "react";
// import { Link } from "react-router-dom";
import styles from "../Styles/Services.module.scss";
const Services = () => {
const [pic, setPic] = useState(1);
const list = [
{ id: 1, url: "../Images/mentorship.jpg" },
{ id: 2, url: "../Images/entertainment.jpg" },
{ id: 3, url: "../Images/support.jpg" },
{ id: 4, url: "../Images/opportunity.jpg" },
{ id: 5, url: "../Images/counselling.jpg" },
];
// const clickHandler = (e) => {
// console.log(e.target.value);
// setPic(e.target.value);
// };
return (
<Fragment>
<section
className="bg-light p-5 text-dark"
style={{ fontFamily: "Lato" }}
>
<div className="container py-5 ">
<div className="display-2 text-center">Our Services</div>
<div className={`${styles.bodyCard}`}>
<div className={`${styles.options}`}>
{list.map((x) => {
var a = x.url;
return (
<div
key={x.id}
value={x.id}
className={`${styles.option} ${
pic === x.id ? styles.active : ""
}`}
onClick={() => setPic(x.id)}
style={{
background: `url(${
require(a).default
})`,
backgroundSize: "auto 100%",
backgroundPosition: "center",
}}
>
<div className={`${styles.shadow}`}></div>
<div className={`${styles.label}`}>
<div className={`${styles.icon}`}>
<i className="fas fa-walking"></i>
</div>
<div className={`${styles.info}`}>
<div className={`${styles.main}`}>Blonkisoaz</div>
<div className={`${styles.sub}`}>
Omuke trughte a otufta
</div>
</div>
</div>
</div>
);
})}
;
</div>
</div>
</div>
</section>
</Fragment>
);
};
export default Services;
I am unable to display images at code background
background: `url(${require(x.url).default})
But When I use this it works.
background: `url(${require("../Images/mentorship.jpg").default})
It gives this error in React
enter image description here
**Kindly do not make it a duplicate as I have checked other similar questions as well and have found no answer there. Thanks **
import React from "react";
import { useState } from "react";
import { Fragment } from "react";
// import { Link } from "react-router-dom";
import styles from "../Styles/Services.module.scss";
import image1 from "../Images/mentorship.jpg";
import image2 from "../Images/entertainment.jpg";
const Services = () => {
const [pic, setPic] = useState(1);
const list = [
{ id: 1, url: image1 },
{ id: 2, url: image2 },
];
// const clickHandler = (e) => {
// console.log(e.target.value);
// setPic(e.target.value);
// };
return (
<Fragment>
<section
className="bg-light p-5 text-dark"
style={{ fontFamily: "Lato" }}
>
<div className="container py-5 ">
<div className="display-2 text-center">Our Services</div>
<div className={`${styles.bodyCard}`}>
<div className={`${styles.options}`}>
{list.map((x) => {
var a = x.url;
return (
<div
key={x.id}
value={x.id}
className={`${styles.option} ${
pic === x.id ? styles.active : ""
}`}
onClick={() => setPic(x.id)}
style={{
background: `url(${a})`,
backgroundSize: "auto 100%",
backgroundPosition: "center",
}}
>
<div className={`${styles.shadow}`}></div>
<div className={`${styles.label}`}>
<div className={`${styles.icon}`}>
<i className="fas fa-walking"></i>
</div>
<div className={`${styles.info}`}>
<div className={`${styles.main}`}>Blonkisoaz</div>
<div className={`${styles.sub}`}>
Omuke trughte a otufta
</div>
</div>
</div>
</div>
);
})}
;
</div>
</div>
</div>
</section>
</Fragment>
);
};
export default Services;
As mentioned in the answerer above by https://stackoverflow.com/users/12902108/samira , it will work, just set style as style={{ background: `url(${photo})` }} assuming image is imported as photo .
The following error shows up when I run my react code: TypeError: Cannot read property 'comments' of undefined. I am trying to eradicate this error but can't do so. Is this because I have not mapped my array correctly or do I need to add in some more code? Please Help!!!!!!!
This is my MainComponent file:
import React, { Component} from 'react';
import { Navbar, NavbarBrand } from 'reactstrap';
import { DISHES } from '../shared/dishes';
import Menu from './menucomponent';
import DishDetails from './dishdetail'
class Main extends Component {
constructor(props) {
super(props);
this.state = {
dishes: DISHES,
selectedDish: null
};
}
onDishSelect(dishId) {
this.setState({
selectedDish: dishId
});
}
render() {
return (
<div>
<Navbar dark color="primary">
<div className="container">
<NavbarBrand href = "/" > Ristorante Con Fusion </NavbarBrand>
</div>
</Navbar>
<Menu dishes={this.state.dishes}
onCick = {(dishId) => this.onDishSelect(dishId)} />
<DishDetails dish={
this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]
}/>
</div>
);
}
}
export default Main;
This is my DishDetail file:
import React, { Component } from 'react';
import {
Card,
CardImgOverlay,
CardImg,
CardBody,
CardText,
CardTitle,
CardHeader
} from 'reactstrap';
import { Media } from 'reactstrap';
class DishDetail extends Component {
constructor(props) {
super(props);
}
render() {
const como = this.props.dishes.comments.map((dish) => {
return (
<div className="container">
<div key={dish.id}>
<p>
{dish.comment}
<br/>
--{dish.author},
{
new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: '2-digit'
}).format(new Date(Date.parse(dish.date)))
}
<br/>
</p>
</div>
</div>
);
});
return (
<div>
<div className="row">
<div className="col-12 col-md-5 m-1">
<Card>
<CardImg src={this.props.dish.image}
alt={this.props.dish.name}/>
<CardBody>
<h3> {this.props.dish.name} </h3>
<CardText>{this.props.dish.description}</CardText>
</CardBody>
</Card>
</div>
<div className="col-12 col-md-6">
<p> Comment </p>
<Media list>{como}</Media>
</div>
</div>
</div>
);
}
}
export default DishDetail;
I believe your dishes object contains comment array
change with below the line in your render method first line
const como = this.props.dishes && this.props.dishes.comments.map((dish) => {
DishDetails is expecting a dishes prop. But in your main component, you are giving DishDetails a dish prop.
DishDetail file:
this.props.dishes.comments.map // here we are referencing 'dishes'
Main file:
DishDetails dish = { // here we are referencing 'dish'
this.state.dishes.filter((dish) => dish.id === this.state.selectedDish)[0]
}
/>
Using React Prop Types, Typescript or Flow can help you to avoid spelling errors like this in future. PropTypes would be the easiest to get started with for now.
You call the dishes while you must to call the dish
this.props.dish.comments.map
I have a main app page component with a search bar. The Search results that come back is in cards And I am looking to set up a "Click here to view more detail" that would be placed in each card. And it would link to the Details page of the one result clicked. How do I link these components on Vue and if the id could be passed? I am hoping that upon click of the button the component renders on the same page and not a new tab.
Once I click on "click here" It updates the link to http://localhost:8081/#/{name:'Details',%20params:%20{id:%20result._gddid}}
and
I get an [Vue warn]: Property or method "results" is not defined on the instance but referenced during render.
Thank you!
app.vue
<template>
<div id="app">
<Header/>
<SearchForm v-on:search="search"/>
<SearchResults
v-if="results.length > 0"
v-bind:results="results"
v-bind:reformattedSearchString="reformattedSearchString"/>
<Details
v-bind:results="results"
/>
<Pagination
v-if="results.length > 0"
v-bind:prevPageToken="api.prevPageToken"
v-bind:next_page="api.scrollId"
v-on:prev-page="prevPage"
v-on:next-page="nextPage"
/>
</div>
</template>
<script>
import Header from './components/layout/Header';
import SearchForm from './components/SearchForm';
import SearchResults from './components/SearchResults';
import Details from './components/Details'
import Pagination from './components/Pagination';
import axios from 'axios';
export default {
name: 'app',
components: {
Header,
SearchForm,
SearchResults,
Details,
Pagination
},
data() {
return {
results: [],
reformattedSearchString: '',
api: {
baseUrl: 'https://test.org/api/v1/articles?',
max: 25,
q: '',
prevPageToken: '',
scrollId: ''
}
};
},
methods: {
search(searchParams) {
this.reformattedSearchString = searchParams.join(' ');
this.api.q = searchParams.join('+');
const { baseUrl, q, max} = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&recent&max=${max}&full_results`;
this.getData(apiUrl);
},
prevPage() {
const { baseUrl, q, max, prevPageToken } = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&pageToken=${prevPageToken}`;
this.getData(apiUrl);
},
nextPage() {
const { baseUrl, q, max,scrollId } = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&recent&full_results&scroll_id=${scrollId}`;
this.getData(apiUrl);
},
getData(apiUrl) {
axios
.get(apiUrl)
.then(res => {
this.results = res.data.success.data;
this.api.prevPageToken = res.data.success.data.prevPageToken;
this.api.next_page = res.data.scrollId;
})
.catch(error => console.log(error))
}
}
};
</script>
SearchResults.vue
<template>
<div class="container mb-3">
<div class="d-flex mb-3">
<div class="mr-auto">
<h3>Search Results for "{{ reformattedSearchString }}"</h3>
</div>
<div class="btn-group ml-auto" role="group">
<button
#click="changeDisplayMode('grid')"
type="button"
class="btn btn-outline-secondary"
v-bind:class="{ active: displayMode === 'grid' }"
>
<i class="fas fa-th"></i>
</button>
<button
#click="changeDisplayMode('list')"
type="button"
class="btn btn-outline-secondary"
v-bind:class="{ active: displayMode === 'list' }"
>
<i class="fas fa-list"></i>
</button>
</div>
</div>
<div class="card-columns" v-if="displayMode === 'grid'">
<div class="card" v-bind:key="result._gddid" v-for="result in results">
<ArticleGridItem v-bind:result="result"/>
</div>
</div>
<div v-else>
<div class="card mb-2" v-bind:key="result._gddid" v-for="result in results">
<ArticleListItem v-bind:result="result"/>
</div>
</div>
<div class="card mb-2" v-bind:key="result._gddid" v-for="result in results">
<Details v-bind:result="result"/>
</div>
</div>
</template>
<script>
import ArticleListItem from './ArticleListItem';
import ArticleGridItem from './ArticleGridItem';
import Details from './Details';
export default {
name: 'SearchResults',
components: {
ArticleListItem,
ArticleGridItem,
Details,
},
data() {
return {
title: 'Search Results',
displayMode: 'grid'
};
},
methods: {
changeDisplayMode(displayMode) {
this.displayMode = displayMode;
}
},
props: ['results', 'reformattedSearchString']
};
</script>
<style scoped>
button:focus {
box-shadow: none !important;
}
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import moment from 'moment'
Vue.config.productionTip = false
Vue.filter('formatDate', function (value) {
if (!value) return ''
return moment(value.toString()).format('MM/DD/YYYY hh:mm')
})
Vue.use(VueRouter)
import Details from './components/Details';
const router = new VueRouter({
routes: [
{
path: '/Details/:id',
name: 'Details',
component: Details
}
]
})
new Vue({
router,
render: h => h(App),
}).$mount('#app')
ArticleListItem.vue
<template>
<div>
<div class="card-body">
<h6 class="card-text">{{ result.title }}</h6>
<p class="card-subtitle mb-2 text-muted"
>{{ result.publisher }} | {{ result.journal }} | {{ result.year }}</p>
<a :href="'https://test.org/api/articles?docid=' + result._gddid" target="_blank">
<i class="fa fa-download" alt="Download"> </i>
</a>
<router-link dark to="{name:'Details', params: {id: result._gddid}}">
Click here for more Details
</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'ArticleListItem',
props: ['result'],
}
</script>
Details.vue
<template>
<div class="Details">
<div class="container">
<div class="row">
<div class="col-md-12" v-for="result in results" :key="result._gddid">
<div v-if="id == result._gddid">
<h1>{{result.title}}</h1>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Details',
props: ['result'],
};
</script>
Once I click on "click here" It updates the link to http://localhost:8081/#/{name:'Details',%20params:%20{id:%20result._gddid}}
Glancing over the code it appears that within ArticleListItem.vue the router-link's to attr isn't bound so it's treated as a string.
Currently: to="{name:'Details', params: {id: result._gddid}}"
Try: :to="{name:'Details', params: {id: result._gddid}}" so it's passed as an object.
I get an [Vue warn]: Property or method "results" is not defined on the instance but referenced during render.
Within Details.vue you have props: ['result'], but in the v-for it looks for results which isn't defined within data() nor within props.
As for the # appearing, vue-router's default mode is hash, if you're not wanting to use # you can set it to history via:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
But beware you'll need a server running to handle the routing; You can find more info at https://router.vuejs.org/guide/essentials/history-mode.html#html5-history-mode
I am learning MEAN stack. I've deployed my application here. Right now If you click on any card i.e. Read more button, it will automatically take you to a division where contenets are displayed. But I want to show all that content on a separate route or page because now I am planning to provide some more useful options such as Like, Report, Upvote,Donwvote`, etc. So I made some changes. Please look at them.
articles.component.html
<div class="row mt-5">
<div class="col-md-4 mb-3" *ngFor="let article of articles; let i = index;">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{article.title}}</h5>
<a (click)="onPress(i)" class="btn btn-primary">Read More</a>
</div>
<div class="card-footer text-muted">
{{article.date}}
</div>
</div>
</div>
</div>
articles.component.ts
import { Component, OnInit } from '#angular/core';
import { ArticlesService } from '../articles.service'; <---- SERVICE FOR READING FROM MONGODB
import {Router, ActivatedRoute }from '#angular/router';
#Component({
...
})
export class ArticlesComponent implements OnInit {
articles=[]
constructor(private _articleService: ArticlesService, private router: Router) { }
ngOnInit() {
this._articleService.getAllArticles()
.subscribe(
res => this.articles = res,
err => console.log(err)
)
}
onPress(id) {
console.log(id); <--- THIS PRINTS INDEX NO OF THE CARD
this.router.navigate(['/options',id]);
}
}
And all the options I mentioned above I've kept them in a separate component.
options-panel.component.html
<div style="margin: 0 auto; width:50vw">
<p> {{data }} </p>
<button (click)="back()"> Back</button>
<div style="display:flex; margin-top:1rem;padding:1rem;">
<button style="margin:0.5rem;"> upVote </button>
<button style="margin:0.5rem;"> DownVote </button>
...
</div>
</div>
options-panel.component.ts
import { Component, OnInit } from '#angular/core';
import {ActivatedRoute,Router } from '#angular/router';
#Component({
...
})
export class OptionsPanelComponent implements OnInit {
private data;
constructor(private router: Router,private activatedRoute: ActivatedRoute) { }
ngOnInit() {
this.activatedRoute.paramMap.subscribe(id =>{
this.data = id.get('id');
})
}
back(){
this.router.navigate(['../'])
}
}
And please review my app-routing.module.ts
...
import { ArticlesComponent } from './articles/articles.component';
import { OptionsPanelComponent } from './options-panel/options-panel.component';
const routes: Routes = [
{path: 'articles', component: ArticlesComponent},
{path:'',redirectTo: 'articles', pathMatch:'full'},
{path: 'options/:id', component:OptionsPanelComponent}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
PS: I read documentation and dependancy injection in Angular. I also tried this stackblitz project.
But I'm getting no errors but blank page.
Please tell me what else I should do now.
What you showed in your picture was working, but you are printing just the id. You must get the article with that id from somewhere, like you service.
There is some information missing about your project, but you could make something like this.
Get the id from the route.
Retrieve your article from your service.
Show it on front using async if possible.
options-panel.component.ts
#Component({
...
})
export class OptionsPanelComponent implements OnInit {
private id: number;
private article$: Observable<Article>;
constructor(private router: Router, private activatedRoute: ActivatedRoute, private _articleService: ArticlesService) { }
ngOnInit() {
this.id = Number(this.activateRoute.snapshot.params['id']);
if (this.id) {
this.article$ = this._articleService.getArticle(this.id);
}
}
back(){
this.router.navigate(['../'])
}
}
options-panel.component.html
<div style="margin: 0 auto; width:50vw" *ngIf="article$ | async as article">
<p> {{ article.content }} </p>
<button (click)="back()"> Back</button>
<div style="display:flex; margin-top:1rem;padding:1rem;">
<button style="margin:0.5rem;"> upVote </button>
<button style="margin:0.5rem;"> DownVote </button>
...
</div>
</div>
If you are seeing that Welcome to my app! and logo, it must be on the index.html file.
If I am not wrong then, you want to create a separate link for each read more. In that case, you have to add router-link in your html and you have to update your routes as well. Try this one:
Your html:
<div class="row mt-5">
<div class="col-md-4 mb-3" *ngFor="let article of articles; let i = index;">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{article.title}}</h5>
<a [routerLink]="['/'+article.id]" routerLinkActive="router-link-active" (click)="onPress(i)" class="btn btn-primary">Read More</a>
</div>
<div class="card-footer text-muted">
{{article.date}}
</div>
</div>
</div>
</div>
this html will generate links for each read more. you also have to update your router and have to put your router-outlet in your desired position.
const routes: Routes = [
{
path: 'articles', component: ArticlesComponent,
children: [
{
path: 'id',
component: 'Read more component'
}
]
},
{ path: '', redirectTo: 'articles', pathMatch: 'full' },
{ path: 'options/:id', component: OptionsPanelComponent }
];