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>
Related
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>
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'm wanting to add functionality for the search box to search the current cards on the page for the movie inputted, but all the other examples and solutions I've found online their solutions don't seem to work for me.
This is the body of the HTML:
<body>
<div id="app">
<div class="row pt-3">
<div class="col">
<input type="text" class="form-control" v-model="search" placeholder="Search Movies">
</div>
<div class="col-md-auto">
<button type="button" class="btn btn-primary" id="search"> Go! </button>
</div>
</div>
<div class="row text-center pt-3">
<div v-for="movie in movies" class="card" style="width: 18rem;">
<img :src="movie.Poster" class="card-img-top" alt="img">
<div class="card-body">
<h5 class="card-title">{{ movie.Title }}</h5>
<p class="card-text">{{ movie.Year }}</p>
View Movie
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
</body>
And this the JS file:
new Vue({
el: '#app',
data: {
movies: [],
search: '',
},
created() {
var vm = this
axios.get('https://www.omdbapi.com/?s=Harry+Potter&apikey=a9018efb')
.then(function(response) {
vm.movies = response.data.Search
})
}
})
Instead of looping over movies, create a computed set of filtered data to loop over. For example, if you were searching the titles:
computed: {
searchedMovies() {
return this.movies.filter(movie => {
return movie.Title.toLowerCase().includes(this.search.toLowerCase());
})
}
}
Loop over this:
<div v-for="movie in searchedMovies" :key="movie.Title">
...
</div>
When you haven't searched for anything, this will return all movies.
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>
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.