Displaying information using v-if from an API - javascript

I want the tag that currently says true or false, I want it to say "FREE" if it's free and say "PAID" if it's not.
https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF
I'm getting a response from data.events.is_free in the form of a boolean that's true if free and false if not.
I know I have nothing between the v-if tags, but the whole thing goes blank if add anything.
HTML:
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<h2 class="title is-4" id="eventName">{{ event.name.html }} <span v-if="" class="tag is-success">{{ event.is_free }}</span></h2>
<div id="eventDescription">{{ event.description.text }}</div>
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>
Vue / JS
// The plan is to make this more extensive later
// https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF
// This is a random address...
const baseUrl = 'https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF';
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get(baseUrl)
.then(response => (this.info = response.data.events))
},
computed () {
isFree
if (response.data.events.is_free == true) {
return true;
}
else {
return false;
}
}
})
https://codepen.io/Mortiferr/pen/qyajJd
Here's a link to my Codepen.

You can use v-if and v-else.
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span v-if="event.is_free" class="tag is-success">Free</span>
<span v-else class="tag is-success">Paid</span>
</h2>
<div id="eventDescription">{{ event.description.text }}</div>
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>

You don't need a computed property for this. You can use v-if and v-else.
Alternatively, if you know that you will only have the text "FREE" or "PAID" without any markup needed, you might want to consider just using a ternary expression:
<span class="tag is-success">{{event.is_free ? "FREE" : "PAID"}}</span>
I added a cost class just to make it a little easier to see.
const baseUrl = 'https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF';
new Vue({
el: '#app',
data() {
return {
info: null,
isFree: false
}
},
mounted() {
axios
.get(baseUrl)
.then(response => {
this.info = response.data.events;
this.isFree = response.data.events
})
}
})
.cost {
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<!-- Using v-if/else -->
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span v-if="event.is_free" class="cost tag is-success">FREE</span>
<span v-else class="cost tag is-success">PAID</span>
</h2>
<!-- Using ternary -->
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span class="cost tag is-success">{{event.is_free ? "FREE" : "PAID"}}</span>
</h2>
<!--<div id="eventDescription">{{ event.description.text }}</div>-->
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>

Related

Vuejs emit not working form child to parent

I'm working on this app and the idea is to show details of the cars in a sidebar on click. There are several issues like the sidebar is showing four times and I resolve it somehow but I don't know why is it showing four times. now I don't getting any response on emit call help me out please, I try $parent.$emit, $root.$emit but not seems working!!!
<template>
<div class="home">
<!-- warehouse details -->
<div
v-for="(detail, detailindex) in details"
:key="detailindex"
class="container mt-5 mb-5"
>
<h1>
{{ detail.name }}
<span class="location">{{ detail.cars.location }}</span>
</h1>
<!-- vehicle details -->
<SingleGarage :detail="detail"> </SingleGarage>
</div>
<b-sidebar
id="my-sidebar"
title="Sidebar with backdrop"
backdrop-variant="dark"
ref="mySidebar"
backdrop
shadow
#emitData="testingEmit()"
>
<div class="px-3 py-2">
<h1>{{currentCar}}</h1>
</div>
</b-sidebar>
</div>
</template>
<script>
// # is an alias to /src
import axios from "axios";
import SingleGarage from "../components/SingleGarage";
export default {
components: { SingleGarage },
name: "Home",
data: () => ({
details: String,
currentCar: 'String',
}),
methods:{
testingEmit(data){
this.currentCar = data
console.log('data from emit',data)
}
},
mounted() {
axios
.get("https://api.jsonbin.io/b/5ebe673947a2266b1478d892")
.then((response) => {
var results;
response.data.forEach((element) => {
element.cars.vehicles.sort((a, b) => {
a = new Date(a.date_added);
b = new Date(b.date_added);
results = a > b ? -1 : a < b ? 1 : 0;
return results * -1;
});
});
this.details = response.data;
});
},
};
</script>
<template>
<div class="vGrid mt-4">
<div
class="gridItem border vehicle singleCar"
v-for="(vehicle, vehicleIndex) in detail.cars.vehicles"
:class="'griditem' + vehicleIndex"
:key="vehicle._id"
>
<SingleCar
:vehicle="vehicle"
#click.native="testingTef(vehicleIndex)"
></SingleCar>
</div>
</div>
</template>
<script>
import SingleCar from "#/components/SingleCar";
export default {
name: "SingleGarage",
components: { SingleCar },
props: ["detail"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
currentCar : 1
}),
methods: {
testingTef(vehicleIndex) {
this.$parent.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)
this.$root.$emit('bv::toggle::collapse', 'my-sidebar')
console.log(this.detail.cars.vehicles[vehicleIndex].make)
console.log(this.detail.cars.vehicles[vehicleIndex].date_added)
this.currentCar = this.detail.cars.vehicles[vehicleIndex].make;
},
},
};
</script>
<template>
<div class="singleCar">
<!-- conditionally show image -->
<img
class="carImg"
:src="vehicle.img"
v-if="vehicle.img"
alt="No Preview"
/>
<img class="carImg" :src="dummyImg" v-else alt="No Preview" />
<div class="p-3">
<h3 class="make">{{ vehicle.make }}</h3>
<div class="modelDetails">
<div class="model d-flex ">
<p class="bold">Model:</p>
<p class="price ml-auto ">{{ vehicle.model }}</p>
</div>
<div class="price d-flex ">
<p class="bold">Price:</p>
<p class="price ml-auto ">€{{ vehicle.price }}</p>
</div>
</div>
<p class="dateAdded ml-auto ">{{ vehicle.date_added }}</p>
</div>
</div>
</template>
<script>
export default {
name: "SingleCar",
props: ["vehicle"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
}),
methods:{
working(){
console.log('working');
console.log(this.vehicle.make)
}
}
};
</script>
Thanks for your help.
So a few things you can try to fix this
in your Home.vue you can change
#emitData="testingEmit()"
to
#emitData="testingEmit"
// or
#emitData="testingEmit($event)"
You are telling to the function testingEmit that is not params to parse. So you need to take out the () and Vue will parse everything that comes from the $event or you cant say put the $event as a param in your testingEmit (second option).
For your SingleGarage.vue you can take the $parent.$emit and replace it with
this.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)

How can I get Vue to correctly update data dynamically?

The component I have below allows a user to view a products macro nutrient info and then also modify the serving size which in return updates the macro nutrient amounts.
The issue I'm having is that Im not getting the values to be updated correctly even when using vue set.
I'm using a watcher to run the calcNewNutriValues function.
<template>
<div class="product">
<div class="topbar">
<div class="left">
<p class="left__name">{{ product.name }}</p>
<p class="left__energy">{{ product.energy }}</p>
</div>
<div class="right">
<button class="cancel" #click="removeItem">
<inline-svg
:src="require('../assets/svg/addition-icon.svg')"
></inline-svg>
</button>
</div>
</div>
<div class="details">
<div class="macros">
<p class="details__heading">Macros</p>
<div class="macros__container container">
<div class="wrapper" v-for="(macro, name, index) in product.macros" :key="index">
<p>{{ name }}</p>
<p>{{ product.macros[name] }}</p>
</div>
</div>
</div>
<div class="serving">
<p class="details__heading">Serving Size (g)</p>
<input type="number" placeholder="40" v-model.number="productServSize">
</div>
</div>
</div>
</template>
export default {
data () {
return {
productServSize: 0,
ogServSize: 0,
macros: {
protein: '',
carbs: '',
fats: '',
fibre: ''
},
micros: {},
energy: ''
}
},
props: [
'product',
],
methods: {
serving () {
const num = this.product.servingSize.split(' ')[0]
this.productServSize = parseFloat(num)
this.ogServSize = parseFloat(num)
},
removeItem () {
this.$emit('removeProduct', this.product)
},
calcNewNutriValues () {
Object.keys(this.product.macros).forEach(key => {
let num = parseFloat(this.product.macros[key].split(' ')[0])
let perGram = parseFloat(num / this.ogServSize)
let newTotal = `${(perGram * this.productServSize).toFixed(1)} g`
this.$set(this.macros, key, newTotal)
})
}
},
mounted () {
this.serving()
Object.assign(this.macros, this.product.macros)
this.energy = this.product.energy
},
watch: {
productServSize: {
handler () {
this.calcNewNutriValues()
this.$emit('updatedNutriValues', this.product)
}
}
}
}
It only seems like macros isn't updating because your template displays product.macros instead of macros:
<div class="wrapper" v-for="(macro, name, index) in product.macros" :key="index">
<p>{{ name }}</p>
<!-- <p>{{ product.macros[name] }}</p> DON'T DO THIS -->
<p>{{ macros[name] }}</p>
</div>
demo

Get child element on click - Vue JS

I need an equivalent of jQuery "this.find()" to get child element from this section on click.
So on click="showProd(6) I want to find "this .dropProd" inside a method ":
Image
<div class="sections" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<div class="dropProd" :class="{ activate : active_el == 6}">
<div v-for="item in shelf" :key="item.id" class="niceBox">
<p class="prod_title">{{item.title}}</p>
<p class="prod_info">{{item.product_details}}</p>
</div>
</div>
</div>
You can use $refs:
<div class="sections" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<!-- note the ref attribute below here -->
<div ref="dropProd" class="dropProd" :class="{ activate : active_el == 6}">
<div v-for="item in shelf" :key="item.id" class="niceBox">
<p class="prod_title">{{item.title}}</p>
<p class="prod_info">{{item.product_details}}</p>
</div>
</div>
</div>
Access it in <script> via this.$refs.dropProd
You could just use this.$refs with an appropriate reference name inside your function like this:
new Vue({
el: '#app',
data: function() {
return {
}
},
methods: {
showProd(){
console.log(this.$refs.referenceMe);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="sections"style="background-color: red" #click="showProd(6)">
<h2 class="padding-10">Limited Shelf Life</h2>
<div class="dropProd" ref="referenceMe">
</div>
</div>
</div>

How can I get the selected data on my modal window(on button click) based on the v-for value?

I am new to Vue and am using the Bootstrap modals to display product information. I have grid containers that each have a product picture, description, and two buttons. One of the buttons(More details >>), when clicked, would shoot a modal window that should show the very same product description and picture of the grid it was contained in.
<div id="myapp">
<h1> {{ allRecords() }} </h1>
<div class="wrapper" >
<div class="grid-container" v-for="product in products" v-bind:key="product.ID">
<div class="Area-1">
<img class="product_image" src="https:....single_product.jpg">
</div>
<div class="Area-2">
<div class = "amount">
{{ product.amount }}
</div>
{{ product.Description }}
</div>
<div class="Area-3">
<b-button size="sm" v-b-modal="'myModal'" product_item = "'product'">
More Details >>
</b-button>
<b-modal id="myModal" >
<h1> {{ product.Name }} </h1>
<h3> {{ product.Description }} </h3>
</b-modal>
</div>
<div class="Area-4">
<br><button>Buy</button>
</div>
</div>
</div>
</div>
var app = new Vue({
'el': '#myapp',
data: {
products: "",
productID: 0
},
methods: {
allRecords: function(){
axios.get('ajaxfile.php')
.then(function (response) {
app.products = response.data;
})
.catch(function (error) {
console.log(error);
});
},
}
})
Area 1, 2 and 4 work perfectly fine and they display the product data according to the v-for value and as expected respectively for each grid container. Area 3 is a problem here when I click the More details >> button, I just see a faded black screen. I am not sure what I am doing wrong here, would really appreciate some help.
Add a property selectedProduct, then on More Details button click event, assign the current product to the selectedProduct member as below :
HTML
<div class="Area-3">
<b-button size="sm" v-b-modal="'myModal'"
#click="selectProduct(product)">More Details >> </b-button>
<b-modal id="myModal">
<h1> {{ this.selectedProduct.Name }} </h1>
<h3> {{ this.selectedProduct.Description }} </h3>
</b-modal>
</div>
Javascript:
var app = new Vue({
'el': '#myapp',
data: {
products: "",
productID: 0,
selectedProduct: {Name: '', Description: '', Amount:0}
},
methods: {
allRecords: function(){
...
},
selectProduct: function(product)
{
this.selectedProduct = product;
}
...
}
I can't replicate the issue. I created JSFiddle to test:
https://jsfiddle.net/4289wh0e/1/
However, I realized multiple modal elements are displayed when I click on the "More Details" button.
I suggest you add only one modal in the wrapper and store the chosen product in a data variable.
https://jsfiddle.net/4289wh0e/2/
<div id="myapp">
<h1> {{ allRecords() }} </h1>
<div class="wrapper">
<div class="grid-container" v-for="product in products" v-bind:key="product.ID">
<div class="Area-1"><img class="product_image" src="https:....single_product.jpg"> </div>
<div class="Area-2">
<div class="amount">{{ product.amount }} </div>
{{ product.Description }}</div>
<div class="Area-3">
<b-button size="sm" v-b-modal="'productModal'" #click="chooseProduct(product)" product_item="'product'">More Details >> </b-button>
</div>
<div class="Area-4">
<br>
<button>Buy</button>
</div>
</div>
<b-modal id="productModal" v-if="chosenProduct">
<h1> {{ chosenProduct.Name }} </h1>
<h3> {{ chosenProduct.Description }} </h3>
</b-modal>
</div>
</div>
Vue.use(BootstrapVue)
var app = new Vue({
'el': '#myapp',
data: {
products: [],
chosenProduct: null
},
methods: {
chooseProduct: function (product) {
this.chosenProduct = product
},
allRecords: function(){
this.products = [
{
ID: 1,
Description: 'dek',
Name: 'Name',
amount: 100
},
{
ID: 2,
Description: 'dek 2',
Name: 'Name 2',
amount: 300
}
]
},
}
})
The reason you're just seeing a black screen is because you're not giving the b-modal in your v-for a unique ID.
So when you click the button it's actually opening all the modals at the same time, and stacking the backdrop making it look very dark.
Instead you could use your product ID (I'm guessing it's unique) in your modal ID to make it unique
<div id="myapp">
<h1> {{ allRecords() }} </h1>
<div class="wrapper" >
<div class="grid-container" v-for="product in products" v-bind:key="product.ID">
<div class="Area-1">
<img class="product_image" src="https:....single_product.jpg">
</div>
<div class="Area-2"><div class = "amount">{{ product.amount }} </div>
{{ product.Description }}
</div>
<div class="Area-3">
<b-button size="sm" v-b-modal="`myModal-${product.ID}`" product_item = "'product'">
More Details >>
</b-button>
<b-modal :id="`myModal-${product.ID}`" >
<h1> {{ product.Name }} </h1>
<h3> {{ product.Description }} </h3>
</b-modal>
</div>
<div class="Area-4">
<br><button>Buy</button>
</div>
</div>
</div>
</div>
Example pen:
https://codepen.io/Hiws/pen/qBWJjOZ?editors=1010

Vue.js show white space (line breaks)

How would I show line space in vue.js. Right now everything is after each other....
Already tried this:
https://laracasts.com/discuss/channels/vue/vuejs-how-to-return-a-string-with-line-break-from-database
But nothing seems work. Trying this for 3 days now -_-.
I'm using Vue.js 1.0 and browserify.
Thanks a lot!
--EDIT--
<template>
<div>
<bar :title="title" />
<div class="Row Center">
<div class="Message Center" v-if="!loading">
<div class="Message__body" v-if="messages">
<div class="Message__item__body" v-for="message in messages" v-link="{ name: 'Message', params: { message: message.slug }}">
<div class="Message__item__body_content">
<p class="Message__title">{{ message.subject }}</p>
</div>
<div class="Message__item__body_content">
<p>Reacties: {{ message.totalReactions }}</p>
</div>
<div class="Message__item__body_content">
<p>Door: {{ message.user.name }} {{ message.user.last_name }}</p>
</div>
</div>
<pagination :last-page="lastPage" :page="page" :name="Message" />
<p v-if="noMessages" class="Collection__none">Er zijn momenteel geen berichten voor het topic {{ topic.name }}.</p>
</div>
</div>
<div class="Loader" v-if="loading">
<grid-loader :loading="loading" :color="color" :size="size" />
</div>
</div>
<div class="Row center" v-if="!loading && page == 1 && topic">
<div>
<button type="submit" class="Btn Btn-main" v-link="{ name: 'NewMessage', params: { topic: topic.slug }}">Nieuw bericht</button>
</div>
</div>
</div>
</template>
<script>
import Bar from '../Shared/Bar.vue';
import Pagination from '../Shared/Pagination.vue';
import Topic from '../../Services/Topic/TopicService';
import { GridLoader } from 'vue-spinner/dist/vue-spinner.min.js';
export default {
components: { Bar, Pagination, GridLoader },
data () {
return {
title: 'Berichten',
messages: [],
topic: null,
noMessages: false,
loading: false,
color: "#002e5b",
page: 1,
lastPage: 1,
}
},
route: {
data ({ to }) {
this.loading = true;
this.page = to.query.page || 1;
Topic.show(this.$route.params.topic, this.page)
.then((data) => {
this.topic = data.data.topic;
if(!data.data.messages.data.length == 0) {
this.messages = data.data.messages.data;
this.lastPage = data.data.messages.last_page;
} else {
this.noMessages = true;
}
this.loading = false;
});
}
}
}
</script>
When I do it like this:
<div class="Message__body__message">
<p>{{ message.message.split("\n"); }}</p>
</div>
It only adds comma's.
--EDIT--
Set container white-space style to pre-line, as in:
<div style="white-space: pre-line;">{{textWithLineBreaks}}</div>
When you split the message, you get multiple data items, which you should handle with a v-for.
But also see LMK's answer wherein you don't have to split the message.
new Vue({
el: '#app',
data: {
message: `this is a message
it is broken across
several lines
it looks like a poem`
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<div id="app">
<template v-for="line in message.split('\n')">{{line}}<br></template>
</div>
You have to transform your data before rendering it with Vue.
const lines = stringWithLineBreaks.split('\n')
// then render the lines
I can give a more specific answer if you share the code you're working with.

Categories