Property Binding & Sync in vue.js - vue.js

I'm having trouble syncing my properties in vue.js, I have an 'active' property that I want to set to the value of each instance 'plan', but at the same time I would like to sync the property with the parent, with no luck. What am I doing wrong ?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Vue</title>
<link rel="stylesheet prefetch" href="http://bootswatch.com/paper/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
</head>
<body>
<div class="container">
<div id="app">
<pre>
#{{ $data | json}}
</pre>
<div v-for="plan in plans">
<plan :active.sync="active" :plan.sync="plan"></plan>
</div>
</div>
</div>
<template id="plan_template">
<div>
<span >#{{ plan.name }}</span>
<span >#{{ plan.price }}/month</span>
<button #click="setActivePlan" class="btn btn-primary btn-xs">UPGRADE</button>
</div>
</template>
<script>
new Vue({
el:'#app',
data:{
plans:[
{name:'Executive',price:100},
{name:'Professional',price:50},
{name:'Personal',price:30},
{name:'Free',price:0}
],
active:{},
},
components:{
plan:{
template:'#plan_template',
props:['plan', 'active'],
methods:{
setActivePlan:function(){
this.active=this.plan;
}
}
}
}
});
</script>
</body>
</html>

Note: This answer applies to V2 of Vue JS, < 2.3.0.
If you are using up V2.3.0+ then you can use .sync and .once modifiers: documentation here
You are using version 2 of Vue. The .sync and .once modifiers have been removed. From the docs:
Props are now always one-way down. To produce side effects in the parent scope, a component needs to explicitly emit an event instead of relying on implicit binding.
I have modified your code to use events here:
new Vue({
el:'#app',
data:{
plans:[
{name:'Executive',price:100},
{name:'Professional',price:50},
{name:'Personal',price:30},
{name:'Free',price:0}
],
active:{},
},
methods: {
setActivePlan: function(plan) {
this.active = plan;
}
},
components:{
plan:{
template:'#plan_template',
props:['plan', 'active'],
methods:{
setActivePlan:function(){
// emit an event to the parent indicating that this is the active plan
this.$emit('activate-plan');
}
}
}
}
});
<link rel="stylesheet prefetch" href="http://bootswatch.com/paper/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div class="container">
<div id="app">
<div v-for="plan in plans">
<plan :plan="plan"
:active="active"
#activate-plan="setActivePlan(plan)"
>
</plan>
</div>
<pre>
{{ JSON.stringify($data, null, 2) }}
</pre>
</div>
</div>
<template id="plan_template">
<div>
<span >{{ plan.name }}</span>
<span >{{ plan.price }}/month</span>
<button #click="setActivePlan" class="btn btn-primary btn-xs">UPGRADE</button>
</div>
</template>

Related

How to send props in Vue

I am quite new in vue so I haven't understood the logic completely. My question is I have ticket and ticketlist components. So I am not on my ticket list component I am creating some tickets data and I want to show them according to the ticket component. To make it more clear here is my ticketlist component:
<template>
<section class="tickets">
<div class="container">
<div class="row">
<div class="col-12 col-md-3 mb-3">
<Ticket v-for="ticket in tickets" :key="ticket.id" :product="ticket"/>
</div>
</div>
</div>
</section>
</template>
<script>
import Ticket from './Ticket'
export default {
components: {
Ticket
},
data() {
return {
tickets: [
{
id: 0,
category: "Einzelkarte",
price: "€3,50",
tariff: [
"Wählen Sie eine Option",
"Erwachsene",
"Erwachsener erm.",
"Kinder / Jugendliche",
"Kinder / Jugendliche erm.",
],
available_amount: 23,
article_number: "2021.05.04-2673990197-1",
},
],
};
},
}
</script>
And also ticket component:
<template>
<widget type="ticket" class="--flex-column">
<div class="top --flex-column">
<div class="bandname -bold">Ghost Mice</div>
<div class="tourname">Home Tour</div>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/199011/concert.png" alt="" />
<div class="deetz --flex-row-j!sb">
<div class="event --flex-column">
<div class="date">3rd March 2017</div>
<div class="location -bold">Bloomington, Indiana</div>
</div>
<div class="price --flex-column">
<div class="label">Price</div>
<div class="cost -bold">€{{ ticket.price }}</div>
</div>
</div>
</div>
<div class="rip"></div>
<div class="bottom --flex-row-j!sb">
<a class="btn button" href="#">ADD TO CART</a>
</div>
</widget>
</template>
<script>
export default {
props: ['ticket'],
}
</script>
<style scoped>
#import 'https://i.koya.io/flex/1.1.0.css';
*, ::after, ::before {
box-sizing: unset;
}
</style>
So, I am showing TicketList component in one of the page but the thing is it doesnt show anything. So I wonder how can I connect them together and show tickets data according to ticket component. I hope I am clear but if I am not I can answer you in the comments.
The probleme is the props name, you need to pass ticket as props and not product
...
<Ticket v-for="ticket in tickets" :key="ticket.id" :ticket="ticket"/>
...
or the contrary inside you Ticket component set :
props: ['product']

using vuejs how do i get the value of content in a div and display inside of the model

I am using vuejs and I want to get the value of a div and display it inside of the model. Issue is i Cannot use the recommended refs because I in reality cant modify the html. Does anyone have a basic solution where I can leverage vuejs and push the content to the model where location is?
new Vue({
el: "#app",
data: {
location:''
},
methods: {
test:function(){
if (!this.$refs.myRef) {
console.log("This doesn't exist yet!");
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="FilePathPlaceholder" class="d2l-placeholder d2l-placeholder-live" aria-live="assertive">
<div class="d2l_1_234_979">
<div class="d2l_1_235_849 d2l_1_236_43 d2l-inline">
<span class="d2l-textblock"></span>
<span
class="d2l-textblock d2l_1_237_505 d2l_1_238_137"
id="d2l_1_233_684"
title="/content/Stuff/12183-CC-242/">
/content/Stuff/
<strong>12183-CC-242</strong>/
</span>
<input type="hidden" name="FilePath" id="FilePath" value="/content/Stuff/12183-CC-242/">
</div>
<div class="d2l_1_237_505 d2l-inline">
<span class="d2l-validator" id="d2l_1_239_562"></span>
</div>
</div>
</div>
</div>

Conditional a href in Vuejs

I am rendering a list of store titles in VueJS, some of them have a url property, some of them don't. If the title has a url, I want to add a a href property:
<div v-for="(store, index) in stores">
<span v-if="store.link"><a :href="store.link" target="_blank">{{ store.title }}</a></span>
<span v-else="store.link">{{ store.title }}</span>
</div>
This works, but the code looks duplicated. Is there anyway to simplify the code further?
you can use component tag:
var app = new Vue({
el: '#app',
data () {
return {
stores: [
{title:'product1',link:'/products/222'},
{title:'product2'},
{title:'product3',link:'/products/333'},
{title:'product4'}
]
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<div v-for="(store, index) in stores">
<component :is="store.link?'a':'span'" :href="store.link || ''" target="_blank">{{store.title}}
</component>
</div>
</div>
I'd remove the first span element, as it's not necessary. Also, the v-else does not need the conditional statement (it's not v-else-if):
new Vue({
el: '#app',
data: {
stores: [
{ link: 'foo', title: 'foo-text' },
{ title: 'bar-text' }
]
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div v-for="(store, index) in stores" :key="index">
<a v-if="store.link" :href="store.link" target="_blank">{{ store.title }}</a>
<span v-else>{{ store.title }}</span>
</div>
</div>
You can use dynamic arguments in vue3
https://v3.vuejs.org/guide/template-syntax.html#dynamic-arguments
<a v-bind:[attributeName]="url"> ... </a>
or binding an object of attributes
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

Vue.js pass props to dynamicly change component class

I'm trying to learn Vue and encountered this problem.
Vue.component('alert', {
props: ['type', 'bold', 'msg'], template: '<div class="alert alert-{{ type }}" role="alert"><b>{{ bold }}</b> {{ msg }}</div>'
});
var componentProps=new Vue( {
el: '#app',
}
);
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div id="app" class="container">
<alert type="info" bold="Greetings." msg="This is some information."></alert>
<alert type="warning" bold="Slow down." msg="You might crash."></alert>
<alert type="danger" bold="Oh no!" msg="The program just crashed!"></alert>
<alert type="success" bold="Rock Out" msg="with your Props out!"></alert>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
This is in the output in the inspector.As you can see the props[type] is not changed there.
<div role="alert" class="alert alert-{{ type }}'"><b>Slow down.</b> You might crash.</div>
Link to codepen => https://codepen.io/dakata911/pen/XEKbyq?editors=1010
In vue 2 you can't use interpolations in attributes anymore. You have several possible syntaxes for class and style bindings now. In your specific case you can use:
<div class="alert" :class="'alert-' + type" role="alert">
Demo below.
new Vue({
el: '#app',
data: {
type: 'warning'
}
})
.alert { background: yellow; }
.alert-warning { color: red }
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div class="alert" :class="'alert-' + type" role="alert"> Warning! </div>
</div>
On attributes interpolation doesn't work, you can use : to bind
:class="type"
or
:class="[ type, other, ... ]"
or
:class="{ 'someClass': true, 'other-class': false, 'another': method() }"
And you can have both :class="..." attributes and class="normal class attribute" on the same element/tag

Vue JS Component reattach or Cache

VueJS component doesn't get cached or atleast reattached after navigation. On refresh or launch everything gets attached and rendered well but after navigating to another page then back. The First Component - Carousel - component in my case doesn't get rendered but the API call is made.
<template>
<div class="rel">
<div id="homeCarousel" class="owl-carousel owl-slider">
<div class="item" v-for="product in featured">
<div class="bg-holder top-area-half" >
<div class="bg-mask-lighten"></div>
<img class="bg-img" v-bind:src="product.feature_image_url">
<div class="hero-caption">
<div class="container">
<h3 class="hero-title">{{product.feature_title}}</h3>
<p class="hero-subtitle">{{product.feature_subtitle}}</p>
<a class="btn btn-white btn-ghost btn-lg hero-btn" href="#">Shop now</a>
</div>
</div>
</div>
</div>
</div>
<div id="hero-slider-nav" class="hero-slider-nav">
<div class="container">
<div class="pull-right"></div>
</div>
</div>
</div>
</template>
<style>
</style>
<script>
export default{
data(){
return{
featured:[]
}
},
ready(){
},
mounted(){
this.getFeaturedProducts();
},
components:{
},
methods: {
getFeaturedProducts: function () {
Vue.http.get('/api/product/filter/featured=1').then(
(response) => {
this.featured = response.body;
}
)
}
}
}
</script>
`
<template>
<div class="global-wrapper clearfix ">
<keep-alive>
<Carousel></Carousel>
</keep-alive>
//The rest of the code which is just importing the Component
I found out what i was doing wrong. I had a separate JS/JQuery file and on the document ready i was initializing an owl carousel by id #('homeCarousel').owlCarousel({}) . What worked was, since i had already bootstrapped owl carousel -> on the mounted lifecycle callback i was now targeting the element and making it an owl carousel.