Creating a search box with vue.js - javascript

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.

Related

How make buttons in all cards clickable?

Hi I created a web app with Django. In this app there are 6 cards with a button for increase and a button for decrease the quantity of food to buy. I have a problem: only the buttons in the first card work. Here's the HTML code
<div class="container">
<div class="row">
{% for roll in rolls %}
<div class="col-4">
<div class="card" style="width: 16rem;">
<img src="{{ roll.immagine.url }}" class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">{{ roll.nome }} Roll</h5>
<p class="card-text">€ {{ roll.prezzo }}</p>
<button id="incrementBtn" style="border-radius: 8px; background-color:orange;">+</button>
<span id="counter">0</span>
<button id="decrementBtn" style="border-radius: 8px; background-color: lightsalmon;">-</button>
Acquista
</div>
</div>
</div>
{% endfor %}
</div>
</div>
Here's the Javascript code:
document.addEventListener("DOMContentLoaded", function() {
let idCounter = "counter1, counter2, counter3, counter4, counter5, counter6";
let arrIdCounter = idCounter.split(", ");
console.log(arrIdCounter);
let valueCounter = document.getElementById('counter').innerHTML;
const incrementBtn = document.getElementById('incrementBtn');
const decrementBtn = document.getElementById('decrementBtn');
incrementBtn.addEventListener('click', () => {
console.log(valueCounter);
valueCounter++;
document.getElementById('counter').innerHTML = valueCounter;
console.log(valueCounter);
});
decrementBtn.addEventListener('click', () => {
if (valueCounter > 0)
{
valueCounter--;
}
document.getElementById('counter').innerHTML = valueCounter;
});
});
When you render your file you will have something like:
<div class="col-4">
<div class="card" style="width: 16rem;">
...
<button id="incrementBtn" ...>+</button>
...
<button id="decrementBtn" ...>-</button>
...
</div>
</div>
<div class="col-4">
<div class="card" style="width: 16rem;">
...
<button id="incrementBtn" ...>+</button>
...
<button id="decrementBtn" ...>-</button>
...
</div>
</div>
<div class="col-4">
<div class="card" style="width: 16rem;">
...
<button id="incrementBtn" ...>+</button>
...
<button id="decrementBtn" ...>-</button>
...
</div>
</div>
How your script may know which element take? You cannot have more than 1 html element with same id, they have to be unique. To do so, you may change you buttons' ids to:
<button id="incrementBtn_{{ poll.id }}" style="border-radius: 8px; background-color:orange;">+</button>
And your variable to array:
const incrementBtn = document.querySelectorAll('[id^="incrementBtn"]');
But then of course you have to use it in loop.

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>

Vue js: Change value using if else

I am new to Vue and I have two button. One is to show the login section and one is to show the register section. What I am tryin to achieve is, if I click on the login button, I want the login section to show and if I click on the register button, I want to hide login section and the register section to show. And by default, I want the login section to be showing. And also, if I click on the login button or Join button and that section was already showing, I want to keep that section showing. Is there a way to achieve this using if else statement or is there a better way to do this. Below is my code
var app = new Vue({
el: '#app',
data: {
displayLoginPage: true,
displayJoinPage: false
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container-fluid p-0" id="app">
<div class="col-md-12">
<div class="col-md-12 sub-title">
<div class="col horizontal-line">
<h5>PERSONAL DETAILS</h5>
</div>
<div class="col-md-12 text-color-per">
<p>Make Sure All Enter Information Are Correct</p>
</div>
</div>
</div>
<div class="d-flex justify-content-center entry-section col-sm-12">
<div class="col-md-6 entry-option-button-login" id="show-login-section">
<button #click="displayLoginPage = !displayLoginPage" type="button" name="btn button">
Login</button>
</div>
<div class="col-md-6 entry-option-button-join" id="show-join-section">
<button #click="displayJoinPage = !displayJoinPage" type="button" name="btn button">
Join</button>
</div>
</div>
<div v-show="displayLoginPage">
<h5>Hello Login Page</h5>
</div>
<div v-show="displayJoinPage">
<h5>Hello Register Page</div>
</div>
</div>
You could use a single boolean, since there are only two views. Set the variable to true to show the login view and hide the other, and vice versa for false. Additionally, replace v-show with v-if and v-else:
<template>
<div>
<button #click="displayLoginPage = true">Login</button>
<button #click="displayLoginPage = false">Join</button>
<div v-if="displayLoginPage">
<h5>Hello Login Page</h5>
</div>
<div v-else>
<h5>Hello Register Page</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
displayLoginPage: true
}
}
}
</script>
var app = new Vue({
el: '#app',
data: {
displayLoginPage: true
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<div class="container-fluid p-0" id="app">
<div class="col-md-12">
<div class="col-md-12 sub-title">
<div class="col horizontal-line">
<h5>PERSONAL DETAILS</h5>
</div>
<div class="col-md-12 text-color-per">
<p>Make Sure All Enter Information Are Correct</p>
</div>
</div>
</div>
<div class="d-flex justify-content-center entry-section col-sm-12">
<div class="col-md-6 entry-option-button-login" id="show-login-section">
<button #click="displayLoginPage = true" type="button" name="btn button">
Login</button>
</div>
<div class="col-md-6 entry-option-button-join" id="show-join-section">
<button #click="displayLoginPage = false" type="button" name="btn button">
Join</button>
</div>
</div>
<div v-if="displayLoginPage">
<h5>Hello Login Page</h5>
</div>
<div v-else>
<h5>Hello Register Page</div>
</div>
</div>
If you plan to have more than two views, you could set the variable to a string specific to each view. For example, set displayPage to "login" to show the login-view; or "join" to show the join-view. Change your v-show condition to compare displayPage against the corresponding value:
<template>
<div>
<button #click="displayPage = 'login'">Login</button>
<button #click="displayPage = 'join'">Join</button>
<div v-show="displayPage == 'login'">
<h5>Hello Login Page</h5>
</div>
<div v-show="displayPage == 'join'">
<h5>Hello Register Page</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
displayPage: 'login'
}
}
}
</script>
var app = new Vue({
el: '#app',
data: {
displayPage: 'login'
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<div class="container-fluid p-0" id="app">
<div class="col-md-12">
<div class="col-md-12 sub-title">
<div class="col horizontal-line">
<h5>PERSONAL DETAILS</h5>
</div>
<div class="col-md-12 text-color-per">
<p>Make Sure All Enter Information Are Correct</p>
</div>
</div>
</div>
<div class="d-flex justify-content-center entry-section col-sm-12">
<div class="col-md-6 entry-option-button-login" id="show-login-section">
<button #click="displayPage = 'login'" type="button" name="btn button">
Login</button>
</div>
<div class="col-md-6 entry-option-button-join" id="show-join-section">
<button #click="displayPage = 'join'" type="button" name="btn button">
Join</button>
</div>
</div>
<div v-show="displayPage == 'login'">
<h5>Hello Login Page</h5>
</div>
<div v-show="displayPage == 'join'">
<h5>Hello Register Page</div>
</div>
</div>
You just need to explicitly set the values for displayLoginPage and displayJoinPage when either button is clicked. See the following example:
var app = new Vue({
el: '#app',
data: {
displayLoginPage: true,
displayJoinPage: false
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container-fluid p-0" id="app">
<div class="col-md-12">
<div class="col-md-12 sub-title">
<div class="col horizontal-line">
<h5>PERSONAL DETAILS</h5>
</div>
<div class="col-md-12 text-color-per">
<p>Make Sure All Enter Information Are Correct</p>
</div>
</div>
</div>
<div class="d-flex justify-content-center entry-section col-sm-12">
<div class="col-md-6 entry-option-button-login" id="show-login-section">
<button #click="(displayLoginPage = true) && (displayJoinPage = false)" type="button" name="btn button">
Login</button>
</div>
<div class="col-md-6 entry-option-button-join" id="show-join-section">
<button #click="(displayJoinPage = true) && (displayLoginPage = false)" type="button" name="btn button">
Join</button>
</div>
</div>
<div v-show="displayLoginPage">
<h5>Hello Login Page</h5>
</div>
<div v-show="displayJoinPage">
<h5>Hello Register Page</div>
</div>
</div>

dynamic form funky behavior in vuejs

I am using VueJS 2.6.11 and bootstrap 4 to create two dynamic sections(Category and Product) that contain divs and input fields. The product section is nested within the category section. When someone clicks the New Category button another category should get generated. The same behavior should also happen when someone clicks the New Product button, another Product section should get generated, but only inside the current category section.
Issue:
When someone clicks the New Product button, the Add Product section will get generated inside all current Category sections. Also, v-model appears to bind to every product name input. When someone clicks the X button for a specific Product section one product section would get deleted from all current Category sections.
I'm not exactly sure why this is happening.
codepen:
https://codepen.io/d0773d/pen/ExjbEpy
code:
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Create Categories and Products</title>
<!-- New Category -->
<button class="btn btn-success mt-5 mb-5"
#click="addNewCategoryForm">
New Category
</button>
<div class="card mb-3" v-for="(category, index) in categories">
<div class="card-body">
<span class="float-right"
style="cursor:pointer"
#click="deleteCategoryForm">
X
</span>
<h4 class="card-title">Add Category</h4>
<div class="category-form">
<input
type="text"
class="form-control mb-2"
placeholder="Category Name"
v-model="category.name">
</div>
<!-- New Product -->
<button class="btn btn-success mt-5 mb-5"
#click="addNewProductForm">
New Product
</button>
<div class="card mb-3" v-for="(product, index) in products">
<div class="card-body">
<span class="float-right"
style="cursor:pointer"
#click="deleteProductForm">
X
</span>
<h4 class="card-title">Add Product</h4>
<div class="product-form">
<input
type="text"
class="form-control mb-2"
placeholder="Product Name"
v-model="product.name">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: '.container',
data: {
categories: [
{
name: '',
}
],
products: [
{
name: '',
}
]
},
methods: {
addNewCategoryForm () {
this.categories.push({
name: '',
});
},
deleteCategoryForm (index) {
this.categories.splice(index, 1);
},
addNewProductForm () {
this.products.push({
name: '',
});
},
deleteProductForm (index) {
this.products.splice(index, 1);
},
}
});
</script>
The general problem is you don't specify which products belong to which category. So in your current code, all products belong to all categories.
I would suggest to instead nest the products inside the category object.
var app = new Vue({
el: ".container",
data: {
categories: [{
name: "",
products: [{
name: ""
}]
}]
},
methods: {
addNewCategoryForm() {
this.categories.push({
name: "",
products: []
});
},
deleteCategoryForm(index) {
this.categories.splice(index, 1);
},
addNewProductForm(index) {
this.categories[index].products.push({
name: ""
});
},
deleteProductForm(categoryIndex, index) {
this.categories[categoryIndex].products.splice(index, 1);
}
}
});
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css">
<!-- Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>Create Categories and Products</title>
<div class="container">
<!-- New Category -->
<button class="btn btn-success mt-5 mb-5" #click="addNewCategoryForm">
New Category
</button>
<div class="card mb-3" v-for="(category, catIndex) in categories">
<div class="card-body">
<span class="float-right" style="cursor:pointer" #click="deleteCategoryForm">
X
</span>
<h4 class="card-title">Add Category</h4>
<div class="category-form">
<input type="text" class="form-control mb-2" placeholder="Category Name" v-model="category.name">
</div>
<!-- New Product -->
<button class="btn btn-success mt-5 mb-5" #click="addNewProductForm(catIndex)">
New Product
</button>
<div class="card mb-3" v-for="(product, index) in category.products">
<div class="card-body">
<span class="float-right" style="cursor:pointer" #click="deleteProductForm(catIndex, index)">
X
</span>
<h4 class="card-title">Add Product</h4>
<div class="product-form">
<input type="text" class="form-control mb-2" placeholder="Product Name" v-model="product.name">
</div>
</div>
</div>
</div>
</div>
</div>

BootstrapVue collapses with open and close all buttons

This has been troubling me for some time now.
Can someone please help me figure out how to build multiple BootstrapVue collapses that open and close individually. In fact, the opening and closing individually already works, as that comes out of the box. I'd like the Open and Close all buttons to open all or close all collapses when pressed at any point.
https://codepen.io/akolinski/pen/ZNKraN
new Vue({
el: "#app",
data: {
showCollapse: false
}
});
<link href="https://unpkg.com/bootstrap-vue#2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap#4.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<div id='app'>
<div class="row">
<div class="col-12 mt-2">
<h1>Vue with BootstrapVue collapse and open and close all buttons</h1>
<p class="lead">The purpose of this pen is to build multiple BootstrapVue collapses that open and close individually. However we want the Open and Close all buttons to open all or close or collapses when pressed.</p>
<hr>
<div class="row my-3">
<div class="col-12">
<b-button class="mr-2" #click="showCollapse = true">Open all</b-button>
<b-button #click="showCollapse = false">Close all</b-button>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<b-button v-b-toggle.collapse-1 variant="primary">Toggle Collapse 1</b-button>
<b-collapse id="collapse-1" class="mt-2">
<b-card>
<p class="card-text">Collapse 1 contents Here</p>
</b-card>
</b-collapse>
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<b-button v-b-toggle.collapse-2 variant="primary">Toggle Collapse 2</b-button>
<b-collapse id="collapse-2" class="mt-2">
<b-card>
<p class="card-text">Collapse 2 contents Here</p>
</b-card>
</b-collapse>
</div>
</div>
<div class="row">
<div class="col-12">
<b-button v-b-toggle.collapse-3 variant="primary">Toggle Collapse 3</b-button>
<b-collapse id="collapse-3" class="mt-2">
<b-card>
<p class="card-text">Collapse 3 contents Here</p>
</b-card>
</b-collapse>
</div>
</div>
</div>
</div>
</div>
Thanks to the BootstrapVue community on discord. We came up with this CodePen to show the correct functionality.
Credit: Hiws#0325
https://codepen.io/Hiws/pen/MdvPEX
new Vue({
el: "#app",
data: {
collapses: [
{ show: false },
{ show: false },
{ show: false }
]
},
methods: {
openAll() {
this.collapses.forEach(collapse => {
collapse.show = true
})
},
closeAll() {
this.collapses.forEach(collapse => {
collapse.show = false
})
}
}
});
<link href="https://unpkg.com/bootstrap-vue#2.0.0-rc.11/dist/bootstrap-vue.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap#4.1.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<div id='app'>
<div class="row">
<div class="col-12 mt-2">
<h1>Vue with BootstrapVue collapse and open and close all buttons</h1>
<p class="lead">The purpose of this pen is to build multiple BootstrapVue collapses that open and close individually. However we want the Open and Close all buttons to open all or close or collapses when pressed.</p>
<hr>
<div class="row my-3">
<div class="col-12">
<b-button class="mr-2" #click="openAll">Open all</b-button>
<b-button #click="closeAll">Close all</b-button>
</div>
</div>
<div class="row mb-4" v-for="(collapse, index) in collapses" :key="index">
<div class="col-12">
<b-button #click="collapse.show = !collapse.show" variant="primary">Toggle Collapse {{ index + 1 }}</b-button>
<b-collapse v-model="collapse.show" id="collapse-1" class="mt-2">
<b-card>
<p class="card-text">Collapse {{ index + 1 }} contents Here</p>
</b-card>
</b-collapse>
</div>
</div>
</div>
</div>
</div>

Categories

Resources