Angular Router duplicates my route component - javascript

I have Screen shots of the application: https://ibb.co/NmnSPNr and https://ibb.co/C0nwG4D
info.component.ts / Info component where child component of Item component, this is displayed when I route to this some link.
export class InfoComponent implements OnInit {
p: Post;
paramsSubscription: Subscription;
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.p = {
id: this.route.snapshot.params['id'],
name: this.route.snapshot.params['name'],
price: this.route.snapshot.params['price'],
place: this.route.snapshot.params['place'],
image: this.route.snapshot.params['image'],
date: this.route.snapshot.params['date'],
desc: this.route.snapshot.params['desc'],
};
**item.component.ts ** / Item component only fetches HTTP request and displayes items
export class ItemComponent implements OnInit {
items: any;
searchValue: any;
constructor(private http: HttpService) {}
ngOnInit(): void {
this.getAllPosts();
}
//GetPost's
getAllPosts() {
this.http.getPost().subscribe((res) => {
this.items = res;
});
}
}
info.component.html / This is the info component where I store the data from info.ts
<div class="container">
<div class="col-xs-12">
<div class="imagee-div">
<img [src]="p.image" alt="snkr1" />
</div>
<div class="details">
<h3>{{ p.id }}. {{ p.name }}</h3>
<small>release date: {{ p.date }}.</small>
<p>Price: ${{ p.price }}</p>
<h4>More Details:</h4>
<p>
{{ p.desc }}
</p>
</div>
</div>
</div>
item.component.html / This is my Parent component, here I store the router outlet, routerLink and loop over the items
<div class="row mx-auto">
<div class="col-4">
<div class="col-12 mt-3" id="main-card">
<div class="row" id="card" *ngFor="let p of items | filter: searchValue">
<div class="img-div">
<img [src]="p.image" alt="" width="250px" />
</div>
<div class="main">
<h4>{{ p.id }}. {{ p.name }}</h4>
<p>Price: ${{ p.price }}</p>
<small>{{ p.place }}</small
><br />
<a
href="#"
[routerLink]="[
'/item',
p.id,
p.name,
p.date,
p.desc,
p.price,
p.image
]"
>
<button class="btn btn-success mt-1">
<i class="fas fa-question"></i>
</button>
</a>
</div>
</div>
</div>
</div>
<div class="col-8"><router-outlet></router-outlet></div>
</div>

Instead of using the <router-outlet>, you can use <app-info-component> and add *ngIf condition in the item component.
Instead of this:
<div class="col-8"><router-outlet></router-outlet></div>
Use this:
<div class="col-8">
<app-info-component *ngIf="p.id > 0">
</app-info-component>
</div>
Same in the info-component add ngIf condition has below.
<div *ngIf="p.id > 0" class="container">
<div class="col-xs-12">
<div class="imagee-div">
<img [src]="p.image" alt="snkr1" />
</div>
<div class="details">
<h3>{{ p.id }}. {{ p.name }}</h3>
<small>release date: {{ p.date }}.</small>
<p>Price: ${{ p.price }}</p>
<h4>More Details:</h4>
<p>
{{ p.desc }}
</p>
</div>
</div>
</div>

Related

Vuejs - getting a querystring value into a component

I have a querystring like this:
https://someurl.com?q=test
And I have a component like so:
Vue.component('externalrecipes', {
props: ['results'],
template: `
<section>
<div class="" v-for="result in results">
<div class="card card-similar card-external text-center">
<img :src="result.image_url" />
<div id="meta" class="text-center">
<h5>{{ result.title }}</h5>
<a target="_blank" :href="'https://www.wine-searcher.com/find/' + q + '/1/uk'" role="button">Buy Wine</a>
</div>
</div>
</div>
</section>
`
})
However, this isn;t working. I want to be able to pass the value of 'q' in the querystring to this line of code:
<a target="_blank" :href="'https://www.wine-searcher.com/find/' + q + '/1/uk'" role="button">Buy Wine</a>
How would I go about doing that?
You have to define the q variable within the component context. You can do so with props (set the value upon component instantiation) but in your use case it would make sense to retrieve its value from the result object used through the v-for.
Check the following snippet for both 'query in props' and 'query in result' examples.
You have to know/define where this query value come from. Your results items or the parent component
Vue.component('externalrecipes_props', {
props: ['results', 'query'],
template: `
<section>
<div v-for="result in results">
<div class="card card-similar card-external text-center">
<img :src="result.image_url" />
<div id="meta" class="text-center">
<h5>{{ result.title }}</h5>
<a target="_blank" :href="'https://www.wine-searcher.com/find/' + query + '/1/uk'" role="button">Buy Wine</a>
</div>
</div>
</div>
</section>
`
});
Vue.component('externalrecipes_result', {
props: ['results'],
template: `
<section>
<div class="" v-for="result in results">
<div class="card card-similar card-external text-center">
<img :src="result.image_url" />
<div id="meta" class="text-center">
<h5>{{ result.title }}</h5>
<a target="_blank" :href="'https://www.wine-searcher.com/find/' + result.query + '/1/uk'" role="button">Buy Wine</a>
</div>
</div>
</div>
</section>
`
});
new Vue({
el: '#app',
});
.card {
display: flex;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<p>Include query in props</p>
<externalrecipes_props :results="[
{
title: 'Some result',
image_url: 'https://via.placeholder.com/100'
}]" query="merlot" />
</div>
<div>
<p>Include query in results items</p>
<externalrecipes_result :results="[
{
title: 'Some result',
image_url: 'https://via.placeholder.com/100',
query: 'merlot'
}]" />
</div>
</div>

Problems updating component property in vuejs using composition-api

Problem
I have the problem that the value of the property :torrent of the ShowVideo component is not updating.
In the MovieSection component there is a select to choose options, it uses a torrent_selected v-model to save the selected data, when changing options it saves the changes but the value of :torrent.sync = "torrent_selected.torrent_magnet" It remains the same.
The ShowVideo component is supposed to update the video once the property is updated.
ShowVideo: Component
<template>
<div>
<div id='player' style="display: block; background: #000; margin: 0 auto;" class='webtor'></div>
</div>
</template>
<script>
import { onMounted, watch } from '#vue/composition-api';
import { loadPlayer } from '../utils/index';
export default {
name: "ShowVideo",
props: {
torrent: String
},
setup(props) {
let data = props.torrent;
// data is not updating ...
watch(() =>
data,
value =>{
data = value;
let d = data;
loadPlayer(d);
}
)
onMounted(()=> loadPlayer(data));
return {
data
};
}
};
</script>
MovieSection
<template>
<!--Begin: Main-->
<div id="main-wrapper">
<!--Begin: Detail-->
<div class="detail_page detail_page-style">
<div
class="cover_follow"
:style="{ 'background-image': 'url(' + data[0][0].poster_big + ')' }"
></div>
<div class="container">
<div class="prebreadcrumb">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<router-link :to="{ name: 'Movies' }">Movies</router-link>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ data[0][0].title }}
</li>
</ol>
</nav>
</div>
<!--Begin: Watch-->
<div class="detail_page-watch">
<div class="dp-w-cover">
<!-- <div class="dp-w-c-play goto-seasons">
<i class="fa fa-play"></i>
</div> -->
</div>
<div class="detail_page-infor">
<div class="dp-i-content">
<div class="dp-i-c-poster">
<div class="film-poster mb-2">
<img
class="film-poster-img"
:src="data[0][0].poster_big"
:title="data[0][0].title"
:alt="data[0][0].title"
/>
</div>
<div class="block-rating" id="block-rating"></div>
</div>
<div class="dp-i-c-right">
<h2 class="heading-name">
<div>{{ data[0][0].title }}</div>
</h2>
<div class="dp-i-stats">
<span class="item mr-1">
<button
#click.prevent="() => (show = !show)"
title="Trailer"
class="btn btn-sm btn-trailer"
>
<i class="fas fa-video mr-2"></i>Trailer
</button>
</span>
<span class="item mr-1"
><button class="btn btn-sm btn-quality">
<strong>HD</strong>
</button></span
>
<span class="item mr-2"
><button class="btn btn-sm btn-radius btn-warning btn-imdb">
{{ data[0][0].rating }}
</button></span
>
</div>
<div class="description">
{{ data[0][0].description }}
</div>
<div class="elements">
<div class="row">
<div class="col-xl-5 col-lg-6 col-md-8 col-sm-12">
<div class="row-line">
<span class="type"><strong>Released: </strong></span>
{{ data[0][0].year }}
</div>
<div class="row-line">
<span class="type"><strong>Genre: </strong></span>
{{ data[0][0].genres && data[0][0].genres.toString() }}
</div>
<div class="row-line">
<span class="type"><strong>Actors: </strong></span>
{{
(data[0][0].actors && data[0][0].actors.toString()) ||
"n/a"
}}
</div>
<div class="row-line">
<span class="type"><strong>Directors: </strong></span>
{{
(data[0][0].directors &&
data[0][0].directors.toString()) ||
"n/a"
}}
</div>
</div>
<div class="col-xl-6 col-lg-6 col-md-4 col-sm-12">
<div class="row-line">
<span class="type"><strong>Runtime: </strong></span>
{{ data[0][0].runtime }}
</div>
<div class="row-line">
<span class="type"><strong>Writers: </strong></span>
{{
(data[0][0].writers &&
data[0][0].writers.toString()) ||
"n/a"
}}
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<!--Trailer-->
<div v-if="show">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="iframe16x9">
<iframe
width="560"
height="315"
id="iframe-trailer"
:src="data[0][0].trailer_url"
frameborder="0"
allow="autoplay;"
allowfullscreen
></iframe>
</div>
<button
#click.prevent="() => close()"
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
</div>
<!--End: Trailer-->
<div
class="alert mb-3"
style="
background: #ffaa00;
color: #111;
font-size: 16px;
font-weight: 600;
"
>
If you get any error message when trying to stream, please Refresh
the page or switch to another torrent.
</div>
<div class="watching_player-control">
<div id="pc-fav" class="btn btn-sm btn-radius btn-secondary mr-2">
<i class="fa fa-magnet mr-2"></i>Select Torrent
</div>
<select v-model="torrent_selected">
<option
v-for="(options, index) in data[0][0].torrents.items"
:value="options"
:key="index"
>
{{ options.file }}
</option>
</select>
<div class="clearfix"></div>
<!--torrent video-->
<div v-if="torrent_selected">
<ShowVideo :torrent.sync="torrent_selected.torrent_magnet" />
<i></i>Quality: {{ torrent_selected.quality }} <i></i>Peers:
{{ torrent_selected.torrent_peers }} <i></i>Seeds:
{{ torrent_selected.torrent_seeds }}
<a
:href="torrent_selected.torrent_magnet"
download
title="Download Torrent"
>
<i class="fa fa-magnet mr-2"></i>Download Torrent
</a>
</div>
<!--End: torrent video-->
</div>
</div>
<!--End: Watch-->
</div>
</div>
<!--End: Related-->
</div>
<!--End: Main-->
</template>
<script>
import { nSQL } from "#nano-sql/core";
import { useRouter } from "#u3u/vue-hooks";
import { ref } from "#vue/composition-api";
import ShowVideo from "../components/ShowVideo";
export default {
name: "MovieSection",
components: {
ShowVideo
},
setup() {
const { route } = useRouter();
const data = ref([]);
const id = ref(route.value.params.id);
nSQL().useDatabase("popcorntimedb");
nSQL("movies");
nSQL()
.query("select")
.where(["ID", "=", id.value])
.exec()
.then(rows => {
data.value.push(rows);
});
const show = ref(false);
const torrent_selected = ref(null);
const close = () => (show.value = false);
return {
data,
torrent_selected,
show,
close,
id
};
}
};
</script>
Because you are making a copy of props.torrent and watching that copy for changes....which never happens. Just watch the prop
setup(props) {
watch(() =>
props.torrent,
value => {
loadPlayer(props.torrent);
}
)
onMounted(()=> loadPlayer(props.torrent));
}

i am finding this.myScrollContainer.nativeElement.scrollHeight but getting Cannot read property 'nativeElement' of undefined

When i open this template I need to find out one div scrollHeight from the code this.myScrollContainer.nativeElement.scrollHeight. But I am getting nativeElement. Actually div scroll is coming top to bottom. What I need to do is scroll bottom to top. Does anyone know what is the issue?
<ng-template #ModalReviewHistory>
<div class="modal-header">
{{ "workFlowCommentsHistory.commentModalTitle" | translate }}
<button
type="button"
class="close pull-right"
aria-label="Close"
(click)="modalRef.hide()"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body scroll" #scrollMe >
<div class="container box" *ngIf="commentHistory === null">
{{ "workFlowCommentsHistory.noCommentMessage" | translate }}
</div>
<!-- <ul class="p-0"> -->
<div class="round" *ngFor="let comments of commentHistory; let i = index">
<div class="bs-callout bs-callout-default mb-0">
<div class="talktext pt-1">
<div class="row">
<div class="col-4 font-12">
<strong>{{ comments?.creator?.firstName }}</strong> |
<strong>{{ comments.role }}</strong>
</div>
<div class="col-5 font-12">
{{ comments?.creator?.createdAt | myDateFormat }}
</div>
<!-- <div class="col-5"></div> -->
<div class="col-2 text-left">
<div
*ngIf="
comments.formKey === 'edjw:panelReviewTask' ||
comments.consolidatedTask === true
"
>
<button
(click)="clickViewMore(comments.id, FeedbackModel)"
type="button"
class="btn btn-outline-primary font-12 btn-sm"
>
{{ "workFlowCommentsHistory.viewBtn" | translate }}
</button>
</div>
</div>
<div class="col-1 text-right">
<button
(click)="onClickReplyToComment(i, comments)"
class="btn btn-outline-primary btn-sm"
title="Reply"
>
<i class="fa fa-reply text-info"></i>
</button>
</div>
</div>
<div class="row pl-3">
{{ comments?.contents }}
</div>
</div>
</div>
<br />
<div class="row">
<div class="col-3"></div>
<div *ngIf="comments.repliesPost" class="col-9">
<div
*ngFor="let reply of comments.repliesPost; let index = index"
[ngClass]="{
'bs-callout bs-callout-default margin-5-left':
reply.isCommentOwner,
'bs-callout-right bs-callout-default-right margin-6-right': !reply.isCommentOwner
}"
>
<!-- <p
*ngIf="
lineCommentReplyEditIndex.replyIndex !== index ||
lineCommentReplyEditIndex.commentIndex !== commentIndex
"
[innerHTML]="reply.contents"
></p> -->
<div class="row">
<div class="col-9 font-12">
<strong>
{{ reply.creator }} |
{{ reply.createdAt | myDateFormat }}</strong
>
</div>
</div>
<div class="row pl-3 py-2">
{{ reply?.contents }}
</div>
</div>
</div>
</div>
<div *ngIf="lineCommentReplyIndex === i" class="row">
<form [formGroup]="lineNumberReplyCommentForm" novalidate>
<div class="col-md-1"></div>
<div class="col-md-9">
<div class="form-group">
<textarea
placeholder="Your comment goes here..."
pInputTextarea
formControlName="comment"
class="form-control"
rows="2"
style="width: 350px;"
></textarea>
<div
class="ui-message ui-messages-error ui-corner-all"
*ngIf="
lineNumberReplyCommentForm.controls['comment'].invalid &&
lineNumberReplyCommentForm.controls['comment'].dirty
"
>
<i class="fa fa-close"></i>
<span
*ngIf="
lineNumberReplyCommentForm.controls['comment'].errors
.required
"
>{{
"lineComments.viewLineComment.replyCommentValidation"
| translate
}}</span
>
</div>
</div>
</div>
<div class="col-md-2">
<button
(click)="submitlineNumberReplyCommentForm()"
class="btn btn-primary"
>
{{ "lineComments.viewLineComment.replyBtn" | translate }}
</button>
</div>
</form>
</div>
</div>
<!-- </ul> -->
</div>
<div class="modal-footer">
<button
(click)="modalRef.hide()"
type="button"
class="btn btn-outline-primary"
>
{{ "prReviewResponseModal.cancel" | translate }}
</button>
</div>
</ng-template>
#ViewChild('scrollMe') myScrollContainer: ElementRef;
#ViewChild('ModalReviewHistory') ModalReviewHistory: ElementRef;
onShowReviewerList() {
this.modalRef = this.modalService.show(this.ModalReviewHistory,
Object.assign({}, {
class: 'gray modal-lg'
},
this.config));
this.scrollToBottom();
}
scrollToBottom() {
this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight;
}
<ng-template> isn't a physical element in the DOM. Converting this to a <div> or something that is created in the DOM should fix your problem.
For example:
<div #ModalReviewHistory>
<!-- modal stuff here -->
</div>
You can diagnose this by inspecting the HTML that gets created. You will see that <ng-template> doesn't exist.

Dynamic data from v-for displayed in imported modal using slots

Problem:
I have a v-for of cards with interpolated data. When someone clicks a card, it triggers a modal component (separate component, using slots).
I want to display the data (title, img, previewUrl, downloadUrl) for whatever card was clicked in the modal, but currently I'm getting an error:
is not defined on the instance but referenced during render
Obviously data is not getting passed into the modal, even though I'm referencing the (card). I want to pass it the index of the card that was clicked, but am unsure of the best way to do this.
I assume that slots can be used to pass dynamic v-for data in the way I'm doing it. I hope I won't have to switch to props as that would muddy things.
Tried so far:
<!-- Cards -->
<div class="card-wrapper">
<div v-for="(card, index) in cards" :key="index" class="card">
<div #click="showModal(card)" class="card-body">
<img :src="card.img" alt="resource img" />
<h4 class="card-title">{{ card.title }}</h4>
<h6 class="card-subtitle">{{ card.subtitle }}</h6>
</div>
</div>
</div>
<!-- MODAL -->
<Modal v-show="isModalVisible" #close="closeModal">
<template v-slot:header>{{ img }} </template>
<template v-slot:body>
{{ title }}
<div class="text-center mb-1 mt-2">
<a :href="previewUrl"><button class="modal-btn btn btn-large">Preview</button></a>
<a :href="downloadUrl"><button class="modal-btn btn btn-large">Download</button></a>
</div>
</template>
</Modal>
DATA
`cards: [
{
title: "Card Title",
subtitle: "Card subtitle",
img: require("#/assets/images/test.jpg"),
previewUrl: "https://test.com",
downloadUrl: "https://test.com"
},`
METHODS:
`methods: {
showModal(card) {
this.isModalVisible = true;
this.title = card.title;
this.img = card.img;
this.previewUrl = card.previewUrl;
this.downloadUrl = card.downloadUrl;
this.isModalVisible = true;
},
closeModal() {
this.isModalVisible = false;
}
}`
The imported modal component
`<template>
<div>
<div class="modal-backdrop" #click.self="close">
<div class="card relative">
<button type="button" class="btn-close" #click="close">
<i class="material-icons">clear</i>
</button>
<header class="modal-header mb-1">
<slot name="header" />
</header>
<div class="mt-1 text-center">
<slot name="header-sub" />
</div>
<slot name="body" />
<footer class="text-center p-2">
<slot name="footer" />
</footer>
</div>
</div>
</div>
</template>
<script>
export default {
name: "modal",
methods: {
close() {
this.$emit("close");
}
}
};
</script>`
you should set the data of modal before and in the click set the correct info
for example in you data set
{
modalInfo:{title:'',img:''}
}
then in click set it like this
showModal(card) {
this.modalInfo.title = card.title;
this.modalInfo.img = card.img;
this.isModalVisible = true;
}
and in the modal part set it like this
<!-- Cards -->
<div class="card-wrapper">
<div v-for="(card, index) in cards" :key="index" class="card">
<div #click="showModal(card)" class="card-body">
<img :src="card.img" alt="resource img" />
<h4 class="card-title">{{ card.title }}</h4>
<h6 class="card-subtitle">{{ card.subtitle }}</h6>
</div>
</div>
</div>
<!-- MODAL -->
<Modal v-show="isModalVisible" #close="closeModal">
<template v-slot:header>{{ modalInfo.img }} </template>
<template v-slot:body>
{{ modalInfo.title }}
<div class="text-center mb-1 mt-2">
<a :href="previewUrl"><button class="modal-btn btn btn-large">Preview</button></a>

View not updated after modifying the array data in angular 6

I am deleting data from array and trying to update the view but it is not working.
async deleteProduct(e) {
try {
const data = await this.rest.get(environment.apiUrl + `/api/seller/products/delete/?id=${e.target.id}`);
data['success'] ? this.products = (this.products.filter(e => e != (data['products'].id))) : this.data.error(data['message']);
} catch (error) {
this.data.error(error['message']);
}
}
Html:
<section id="myProducts">
<div class="container p-5">
<app-message></app-message>
<div *ngIf="!products" class="m-auto">
<h1 class="text-center display-3 mt-5">
<i class="fa fa-spinner fa-spin"></i>
</h1>
</div>
<h3 *ngIf="products && !products.length" class="display-2 text-center mt-5">My Products is Empty</h3>
<div *ngIf="products && products.length" class="row">
<div class="col">
<h4 class="display-4">My Products</h4>
<div class="row">
<div class="offset-10 col-2 d-none d-md-block">
<p>
<small class="text-muted">Price</small>
</p>
</div>
</div>
<hr class="mt-0">
<div *ngFor="let product of products" class="product">
<div class="row">
<div class="col-4 col-md-2">
<a routerLink="/product/{{ product.id }}">
<img src="{{ product.image }}" alt="image" class="img-fluid img-thumbnail">
</a>
</div>
<div class="col-5 col-md-8">
<h5>
<a routerLink="/product/{{ product.id }}">{{ product.title }}</a>
<p class="m-0">
<small class="text-muted">{{ product.category.name }}</small>
</p>
</h5>
</div>
<div class="col-2">
<h6 class="font-weight-bold text-danger" >{{ product.price | currency : 'INR' }}</h6>
</div>
<div class="col-2">
<button type="button" class="btn btn-info" id="{{product.id}}" (click)="editProduct($event)" [disabled]="btnDisabled">Edit</button>
</div>
<div class="col-2">
<button type="button" class="btn btn-info" id="{{product.id}}" (click)="deleteProduct($event)" [disabled]="btnDisabled">Delete</button>
</div>
</div>
<hr>
</div>
</div>
</div>
</div>
</section>
After deleting the item from array, I am trying to update the object like this:
this.products = (this.products.filter(e => e != (data['products'].id)))
It seems so that your view does not check the changes of your products array.
So I would say trigger it manually:
InjectChangeDetectorRef to trigger change detection manually.
constructor(private cd: ChangeDetectorRef){....}
And in your method call this.cd.detectChanges():
async deleteProduct(e) {
...
data['success'] ? this.products = (this.products.filter(e => e != (data['products'].id))) : this.data.error(data['message']);
this.cd.detectChanges();
...
}
you are comparing e to != e['products'].id ..
it is not true.
i think you should be checking the variable which holds the id in your "e"
which means
e.id != ...or something like so.
I Hope it is working.

Categories

Resources