VueJS: How to add a boolean prop to existing template - vue.js

I am looking to extend a vue-toggle component I found to add a boolean value. I am trying to add ability to hide/show an element based on the boolean prop.
Here is my html code:
<div class="container" id="app">
<div class="row">
<div class="col-xs-3 col-sm-4 col-md-5 col-lg-6">
<img src="https://images-na.ssl-images-amazon.com/images/I/81UxhkSlBjL._UX466_.jpg" alt="" class="img-responsive" />
</div>
<div class="col-xs-9 col-sm-8 col-md-7 col-lg-6 options">
<fieldset class="form-group">
<legend class="sr-only">Style</legend>
<div class="form-group">
<vue-toggle :values="styles" :boolean="showVNeck" :selected.sync="style" default="crew"></vue-toggle>
</div>
</fieldset>
<div><span v-if="showVNeck">V Neck</span><span v-else>Crew Neck</span> Selected</div>
</div>
</div>
</div>
<template id="vue-toggle">
<div class="btn-group">
<button type="button"
v-for="(val, key) in values"
#click="changeSelectVal(key, boolean)"
:class="['btn', { 'btn-primary': selected === key, 'btn-default': selected !== key }]"
>{{ val }}</button>
</div>
</template>
Here is my javascript:
var Toggle = Vue.extend({
template: '#vue-toggle',
props: ['values','selected','boolean','default'],
mounted: function () {
this.selected = this.default;
},
methods: {
changeSelectVal: function(val, boolean) {
this.selected = val;
this.boolean = !this.boolean;
}
}
});
Vue.component('vue-toggle', Toggle);
new Vue({
el: '#app',
data: {
style: '',
showVNeck: false,
styles: {
'crew': 'Crew Neck',
'vneck': 'V-Neck',
}
}
});
Here is a codepen to share:
https://codepen.io/mujaji/pen/YzXVqaL
I think I am just overlooking something and looking for assistance.
Cheers!

The .sync modifier requires that your child emits events of the type update:myPropName instead of directly mutating the prop - look at the documentation:
var Toggle = Vue.extend({
template: '#vue-toggle',
props: ['values','selected','boolean','default'],
mounted: function () {
this.$emit('update:selected',this.default);
},
methods: {
changeSelectVal: function(val, boolean) {
this.$emit('update:selected',val);
this.$emit('update:boolean',!this.boolean);
}
}
});
Vue.component('vue-toggle', Toggle);
new Vue({
el: '#app',
data: {
style: '',
showVNeck: false,
styles: {
'crew': 'Crew Neck',
'vneck': 'V-Neck',
},
},
methods:
{
updateVNeck(newValue)
{
this.showVNeck = newValue;
}
}
});
body {
background-color: #5c4084;
padding: 50px;
}
.container {
background-color: #fff;
padding-top: 40px;
padding-bottom: 80px;
border-radius: 8px;
}
.heading
h1 {
color: #fff;
font-size: 4rem;
font-weight: 900;
margin: 0 0 5px 0;
background: -webkit-linear-gradient(#fff, #999);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-align: center;
}
.heading h4 {
color: #5c3d86;
font-size: 24px;
font-weight: 400;
text-align: center;
margin: 0 0 35px 0;
}
.options {
padding-top: 80px;
}
.btn{
outline: none !important;
}
.btn.btn-primary {
background-color: #5c4084;
border-color: #5c4084;
outline: none;
}
.btn.btn-primary:hover {
background-color: #5c4084;
border-color: #5c4084;
}
.btn.btn-primary:active, .btn.btn-primary:focus {
background-color: #5c4084;
border-color: #5c4084;
}
.btn.btn-default:hover {
background-color: #5c4084;
border-color: #5c4084;
color: #fff;
}
.btn.btn-default:active, .btn.btn-default:focus {
background-color: #5c4084;
border-color: #5c4084;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
<div class="container" id="app">
<div class="row">
<div class="col-xs-3 col-sm-4 col-md-5 col-lg-6">
<img src="https://images-na.ssl-images-amazon.com/images/I/81UxhkSlBjL._UX466_.jpg" alt="" class="img-responsive" />
</div>
<div class="col-xs-9 col-sm-8 col-md-7 col-lg-6 options">
<fieldset class="form-group">
<legend class="sr-only">Style</legend>
<div class="form-group">
<vue-toggle :values="styles" :boolean.sync="showVNeck" :selected.sync="style" default="crew"></vue-toggle>
</div>
</fieldset>
<div><span v-if="showVNeck">V Neck</span><span v-else>Crew Neck</span> Selected</div>
</div>
</div>
</div>
<template id="vue-toggle">
<div class="btn-group">
<button type="button"
v-for="(val, key) in values"
#click="changeSelectVal(key, boolean)"
:class="['btn', { 'btn-primary': selected === key, 'btn-default': selected !== key }]"
>{{ val }}</button>
</div>
</template>

Related

couldn't passing the data from axios to data return variable in vuejs

I have an issue in my vue template down below. I fetched data from axios but it couldn't store the data on this.sub_brand variable. console.log(this.sub_brand) is only working for inside axios. here is the full code -
<template>
<div>
<div class="row" >
<div class="col-md-4 pt-5 pl-5">
<div class="product">
<div class="product__images">
<img
src="http://127.0.0.1:8000/images/gsm.jpg"
alt="google pixel 6"
class="product__main-image"
id="main-image"
/>
<div class="product__slider-wrap">
<div class="product__slider">
<img
src="http://127.0.0.1:8000/images/gsm.jpg"
alt="google pixel 6"
class="product__image product__image--active"
/>
<img
src="http://127.0.0.1:8000/images/gsm.jpg"
alt="google pixel 6"
class="product__image"
/>
<img
src="http://127.0.0.1:8000/images/gsm.jpg"
alt="google pixel 6"
class="product__image"
/>
<img
src="http://127.0.0.1:8000/images/gsm.jpg"
alt="google pixel 6"
class="product__image"
/>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-5 pt-5 pr-5">
<h4>{{sub_brand}}</h4>
<!-- <input type="text" class="form-control" name="" id="" v-model="sub_brand"> -->
<h5>Star</h5>
<div class="bg-light mt-4" style="padding: 10px 0px">
<h2 class="pl-4 pt-3">RM869.00</h2>
</div>
<div class="mt-4">
<h3>Variation</h3>
</div>
<div class="bg-light mt-4" style="padding: 10px 0px">
<h5 class="pl-4">Quantity: </h5>
<input type="number" class="form-control pl-4" placeholder="0" style="width: 12%; margin-left: 4%" min="0">
</div>
<div class="row mt-5">
<button class="btn btn-secondary ml-3">Add to Cart</button>
<button class="btn btn-primary ml-3">Buy Now</button>
</div>
<hr class="mt-5">
</div>
<div class="col-md-3 bg-light">
<div class="pl-5">
<h3><strong>Samsung</strong></h3>
</div>
<div class="pl-5 custom_pan">
Chat
Video Chat
View
</div>
<hr>
<div class="pl-5 mt-4 pr-4">
<strong>Shipping Details</strong>
<p style="color: #D1D3D4">2A, Changkat Duta Kiara, Mont Kiara, 50480 Kuala Lumpur, Willayah Persekutuan Kuala Lumpur</p>
<strong>From: China Logistic, Shankal</strong>
<br><br>
<strong>To: Kuala Lumpur, Willayah Persekutuan</strong>
<br><br>
<strong>Shipping Fee: RM8.00</strong>
</div>
<hr>
<div class="pl-5 mt-5">
<h5>Authentic</h5>
<br>
<h5>15 Days Return</h5>
<br>
<h5>Free Shipping</h5>
</div>
<br><br>
</div>
</div>
<div class="row bg-light">
<div class="card">
<div class="card-header">
<h4>Product Description</h4>
</div>
<div class="card-body">
Samsung
</div>
</div>
</div>
<div class="row bg-light">
<div class="card">
<div class="card-header">
<h4>Review</h4>
</div>
<div class="card-body">
Samsung
</div>
</div>
</div>
<div class="row bg-light">
<div class="card">
<div class="card-header">
<h4>You may also like other product from same merchant</h4>
</div>
<div class="card-body">
Samsung
</div>
</div>
</div>
<div class="row bg-light">
<br><br>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
mounted() {
// console.log('Component mounted.');
this.fetchProduct();
},
data() {
return{
single_product: [],
sub_brand: "",
product_id: 6,
}
},
methods: {
fetchProduct(){
axios.get('https://admin.globalshopping-mall.site/api/single_sub_brand_detail/'+ this.product_id)
.then(res => {
this.single_product = res.data.data[0];
this.sub_brand = res.data.data[0].GUID;
}).catch(err => {console.log(err);});
},
},
}
</script>
<style>
.card{
margin-top: 2%;
margin-left: 4%;
background-color: white;
width: 71%;
/* height: 30%; */
}
.card-header{
background-color: white
}
.product {
width: 100%;
height: 68%;
}
.product__images {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.product__main-image {
max-width: 500px;
max-height: 600px;
object-fit: cover;
cursor: pointer;
border: 1px solid #070707;
}
.product__slider-wrap {
max-width: 500px;
min-height: 100px;
display: flex;
align-items: center;
}
.product__slider {
width: 98%;
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
padding-left: 2%;
}
.product__image {
max-width: 180px;
max-height: 100px;
object-fit: cover;
cursor: pointer;
opacity: 0.5;
margin: 0.25rem;
border: 1px solid #070707;
}
.product__image:first-child {
margin-left: 0;
}
.product__image:last-child {
margin-right: 0;
}
.product__image:hover {
opacity: 1;
}
.product__image--active {
opacity: 1;
}
.product__slider::-webkit-scrollbar {
height: 10px;
}
.product__slider::-webkit-scrollbar-thumb {
background-color: #D1AD33;
border-radius: 50px;
}
</style>
Look, the problem is, your context this. works inside axios with context of axios
If you want to use context this. of vue component, you have to get data from axios outside.
You have to use async/await for you vue method fetchProduct
Something like that
methods: {
async fetchProduct() {
let result = await axios.get("https://admin.globalshopping-mall.site/api/single_sub_brand_detail/" +this.product_id)
.then((res) => {
return res.data.data[0];
})
.catch((err) => {console.log(err);});
this.single_product = result;
this.sub_brand = result.GUID;
},
},
or
You can save your context this to the variable before axios
and use this variable inside the axios function
Something like this
methods: {
fetchProduct() {
let _this = this;
axios.get("https://admin.globalshopping-mall.site/api/single_sub_brand_detail/" + this.product_id)
.then((res) => {
_this.single_product = res.data.data[0];
_this.sub_brand = res.data.data[0].GUID;
})
.catch((err) => {console.log(err);});
console.log(this);
},
},
Root cause : As axios API calls works asynchronously, But other code will execute synchronously. Hence, While trying to logging this.sub_brand it will work synchronously and will invoke before the axios call (response time might vary).
Solution : If you want to access the API response immediately after a call. You have to use async/await which make promises easier to write.
async makes a function return a Promise
await makes a function wait for a Promise
Live Demo :
methods: {
async fetchProduct(){
const res = await axios.get('https://admin.globalshopping-mall.site/api/single_sub_brand_detail/'+ this.product_id)
.then(res => {
return res.data.data[0];
}).catch(err => {console.log(err);});
}
this.single_product = res;
this.sub_brand = res.GUID;
}

Styling selected value in Vue Select

I'm using vue select. In the dropdown, there are the labels (not only text). Is it possible to have also the label for the selected value?
<div class="form-group row">
<label for="project_status_id" class="col-sm-3 col-form-label">Projekt Status</label>
<div class="col-sm-9">
<v-select :options="resources.activeProjectStatus" :reduce="project_status_id => project_status_id.id" v-model="form.project_status_id" label="name" id="project_status_id" placeholder="Projekt Status" :class="$vSelectStyle($v.form.project_status_id)">
<template v-slot:option="option" >
<div v-html="option.status_label" class="mb-1">
</div>
</template>
</v-select>
<template v-if="$v.form.project_status_id.$error">
<p class="text-danger" v-if="!$v.form.project_status_id.required">
Projekt - Status ist erforderlich!
</p>
</template>
</div>
</div>
Assuming you want the HTML of the status_label, also assuming that status_label is a template string or similar, then use the selected-option slot with the slot's content being the same as your option slot without the class attached.
The key part in the example below is, as mentioned, the selected-option slot:
<!-- Using OP's `option` key -->
<template v-slot:selected-option="option">
<div v-html="option.status_label"></div>
</template>
The example below is a fork of Vue-Select's Codepen example with modifications for the answer.
Vue.config.productionTip = false;
Vue.component('v-select', VueSelect.VueSelect);
new Vue({
el: '#app',
data: {
options: [
{
name: `<span style="padding: 4px; background: green; border-radius: 0.25rem; color: white;">Foo</span>`
},
{
name: `<span style="padding: 4px; background: orange; border-radius: 0.25rem; color: white;">Bar</span>`
},
{
name: `<span style="padding: 4px; background: red; border-radius: 0.25rem; color: white;">Baz</span>`
}
]
}
});
body {
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
h1 {
font-size: 26px;
font-weight: 600;
color: #2c3e5099;
text-rendering: optimizelegibility;
-moz-osx-font-smoothing: grayscale;
-moz-text-size-adjust: none;
}
#app {
max-width: 30em;
margin: 1em auto;
}
<script src="https://unpkg.com/vue#latest"></script>
<script src="https://unpkg.com/vue-select#latest"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-select#latest/dist/vue-select.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:600">
<div id="app">
<h1>Vue Select</h1>
<v-select :options="options" label="label">
<template v-slot:option="option" >
<div v-html="option.name" style="padding: 2px 0;"></div>
</template>
<template v-slot:selected-option="option">
<div v-html="option.name"></div>
</template>
</v-select>
</div>

Google Chart within Bootstrap 3 Nav

I have a page using bootstrap 3 nav tabs and on one of the tabs I have a google timeline chart that is too far to the left. I have tried setting the chartArea.left option to different values but that doesn't seem to do anything, as well as setting different widths.
var selectedLanguage = 'en';
if ($("#selected-language") && $("#selected-language").val()) {
selectedLanguage = $("#selected-language").val();
}
google.charts.load('current', {
'packages': ['timeline'],
'language': selectedLanguage
});
google.charts.setOnLoadCallback(drawTimelineChart);
function drawTimelineChart() {
//Do ajax call to get json
var json = {
"timelineCharts": [{
"rowLabel": "Commissioned",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-18T16:25:29",
"end": "2018-07-20T10:48:42"
}, {
"rowLabel": "Pre-Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:42",
"end": "2018-07-20T10:48:45"
}, {
"rowLabel": "Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:45",
"end": "2018-09-28T14:08:03"
}, {
"rowLabel": "Pre-Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:45",
"end": "2018-09-28T12:22:05"
}, {
"rowLabel": "Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-09-28T12:22:05",
"end": "2018-09-28T14:08:03"
}]
};
setTimelineChartData(json);
}
function setTimelineChartData(jsonObj) {
if (jsonObj) {
var container = document.getElementById('portfolio-time-management-chart');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
if (jsonObj && jsonObj.timelineCharts) {
dataTable.addColumn({
type: 'string',
id: 'Status'
});
dataTable.addColumn({
type: 'string',
id: 'Label'
});
dataTable.addColumn({
type: 'string',
role: 'Tooltip'
});
dataTable.addColumn({
type: 'date',
id: 'Start'
});
dataTable.addColumn({
type: 'date',
id: 'End'
});
var hasData = false;
$.each(jsonObj.timelineCharts, function(index, timelineChart) {
if (timelineChart) {
var startDate = new Date(timelineChart.start);
var endDate = new Date(timelineChart.end);
dataTable.addRow(
[timelineChart.rowLabel, timelineChart.barLabel, timelineChart.barLabel, startDate, endDate]
);
hasData = true;
}
});
var windowHeight = $(window).height() * 0.5;
var windowWidth = $(window).width() * 0.7;
var options = {
height: windowHeight,
width: windowWidth,
chartArea: {
left: '30%'
}
};
if (hasData) {
chart.draw(dataTable, options);
}
}
}
}
.panel.with-nav-tabs.panel-tab-block {
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:focus {
color: #ffffff;
background-color: #999999;
}
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a,
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a:focus,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:focus {
color: #fff;
background-color: #666666;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a:focus {
color: #fff;
background-color: #2f70b1;
border-color: #2f70b1;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu {
background-color: #428bca;
border-color: #3071a9;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a {
color: #fff;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a:focus {
background-color: #3071a9;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a:focus {
background-color: #4a9fe9;
}
.list-group-item {
color: #000000;
background-color: #e4e4e4;
padding: 0.5em;
overflow: auto;
border: 1px solid #1d3c5c;
}
.list-group-item-title {
background-color: #fff;
}
.list-group label {
margin-bottom: 0px;
}
.spacer-sml {
margin: 0;
padding: 0;
height: 2em;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="container-fluid portfolio-overview-container">
<div class="col-sm-2 ">
<div class="row ">
<ul class="list-group">
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details">Side Details...</label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
</ul>
</div>
</div>
<div class="col-sm-10">
<div class="panel with-nav-tabs panel-tab-block">
<div class="panel-heading ">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" role="tab" class="" href="#portfolio-projects-tab">Projects</a></li>
<li><a data-toggle="tab" role="tab" class="" href="#portfolio-time-management-tab">Timeline Chart</a></li>
</ul>
</div>
<div class="panel-body">
<div class="tab-content">
<div id="portfolio-projects-tab" class="tab-pane fade in active">
<div class="tab-block-content ">
<div class="row ">
<div class="col-sm-12 ">
<div class="spacer-sml"></div>
</div>
<div class="col-sm-12">
<h1>
Project tab that is loaded by default but issue is with Timeline Chart tab chart being hidden
</h1>
</div>
</div>
</div>
</div>
<div id="portfolio-time-management-tab" class="tab-pane fade">
<div class="row col-xs-12">
<div class="spacer-sml"></div>
</div>
<div class="col-xs-11">
<div id="portfolio-time-management-chart" style="position:relative;"></div>
</div>
<div class="row col-xs-12">
<div class="spacer-sml"></div>
</div>
<div class="row ">
<div class="spacer-sml"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Does anyone know how I can get the full chart visible?
by default, google charts will follow the size of their container.
if the container is hidden when its drawn,
then it cannot determine a proper size for the specific chart elements.
need to wait until the tab is shown,
before drawing for the first time.
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
switch ($(e.target).html()) {
case 'Timeline Chart':
drawTimelineChart();
break;
}
});
see following working snippet...
var selectedLanguage = 'en';
if ($("#selected-language") && $("#selected-language").val()) {
selectedLanguage = $("#selected-language").val();
}
google.charts.load('current', {
'packages': ['timeline'],
'language': selectedLanguage
}).then(function () {
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
switch ($(e.target).html()) {
case 'Timeline Chart':
drawTimelineChart();
window.addEventListener('resize', drawTimelineChart);
break;
}
});
});
function drawTimelineChart() {
//Do ajax call to get json
var json = {
"timelineCharts": [{
"rowLabel": "Commissioned",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-18T16:25:29",
"end": "2018-07-20T10:48:42"
}, {
"rowLabel": "Pre-Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:42",
"end": "2018-07-20T10:48:45"
}, {
"rowLabel": "Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:45",
"end": "2018-09-28T14:08:03"
}, {
"rowLabel": "Pre-Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-07-20T10:48:45",
"end": "2018-09-28T12:22:05"
}, {
"rowLabel": "Production",
"barLabel": "Actual",
"tooltip": "",
"start": "2018-09-28T12:22:05",
"end": "2018-09-28T14:08:03"
}]
};
setTimelineChartData(json);
}
function setTimelineChartData(jsonObj) {
if (jsonObj) {
var container = document.getElementById('portfolio-time-management-chart');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
if (jsonObj && jsonObj.timelineCharts) {
dataTable.addColumn({
type: 'string',
id: 'Status'
});
dataTable.addColumn({
type: 'string',
id: 'Label'
});
dataTable.addColumn({
type: 'string',
role: 'Tooltip'
});
dataTable.addColumn({
type: 'date',
id: 'Start'
});
dataTable.addColumn({
type: 'date',
id: 'End'
});
var hasData = false;
$.each(jsonObj.timelineCharts, function(index, timelineChart) {
if (timelineChart) {
var startDate = new Date(timelineChart.start);
var endDate = new Date(timelineChart.end);
dataTable.addRow(
[timelineChart.rowLabel, timelineChart.barLabel, timelineChart.barLabel, startDate, endDate]
);
hasData = true;
}
});
var windowHeight = $(window).height() * 0.5;
var windowWidth = $(window).width() * 0.7;
var options = {
height: windowHeight,
width: windowWidth,
};
if (hasData) {
chart.draw(dataTable, options);
}
}
}
}
.panel.with-nav-tabs.panel-tab-block {
box-shadow: none;
-moz-box-shadow: none;
-webkit-box-shadow: none;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:focus {
color: #ffffff;
background-color: #999999;
}
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a,
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>.open>a:focus,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li>a:focus {
color: #fff;
background-color: #666666;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.active>a:focus {
color: #fff;
background-color: #2f70b1;
border-color: #2f70b1;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu {
background-color: #428bca;
border-color: #3071a9;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a {
color: #fff;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>li>a:focus {
background-color: #3071a9;
}
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a:hover,
.with-nav-tabs.panel-tab-block .nav-tabs>li.dropdown .dropdown-menu>.active>a:focus {
background-color: #4a9fe9;
}
.list-group-item {
color: #000000;
background-color: #e4e4e4;
padding: 0.5em;
overflow: auto;
border: 1px solid #1d3c5c;
}
.list-group-item-title {
background-color: #fff;
}
.list-group label {
margin-bottom: 0px;
}
.spacer-sml {
margin: 0;
padding: 0;
height: 2em;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="container-fluid portfolio-overview-container">
<div class="col-sm-2 ">
<div class="row ">
<ul class="list-group">
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details">Side Details...</label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
<li class="list-group-item list-group-item-title text-center ">
<label class="portfolio-details"></label>
</li>
</ul>
</div>
</div>
<div class="col-sm-10">
<div class="panel with-nav-tabs panel-tab-block">
<div class="panel-heading ">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" role="tab" class="" href="#portfolio-projects-tab">Projects</a></li>
<li><a data-toggle="tab" role="tab" class="" href="#portfolio-time-management-tab">Timeline Chart</a></li>
</ul>
</div>
<div class="panel-body">
<div class="tab-content">
<div id="portfolio-projects-tab" class="tab-pane fade in active">
<div class="tab-block-content ">
<div class="row ">
<div class="col-sm-12 ">
<div class="spacer-sml"></div>
</div>
<div class="col-sm-12">
<h1>
Project tab that is loaded by default but issue is with Timeline Chart tab chart being hidden
</h1>
</div>
</div>
</div>
</div>
<div id="portfolio-time-management-tab" class="tab-pane fade">
<div class="row col-xs-12">
<div class="spacer-sml"></div>
</div>
<div class="col-xs-11">
<div id="portfolio-time-management-chart" style="position:relative;"></div>
</div>
<div class="row col-xs-12">
<div class="spacer-sml"></div>
</div>
<div class="row ">
<div class="spacer-sml"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Vuejs modal component passing data

I am stuck making a modal component for my app in VueJS. I want to be able to put it in its own component for reusability, be able to pass custom content and have multiple modals.
I made the component and it looks like this from the VueJS docs:
Modal.vue
<template>
<div ref="modal">
<script type="text/x-template" id="modal">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
Header
</slot>
</div>
<div class="modal-body">
<slot name="body">
Body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
Footer
</slot>
<button class="btn btn-primary" #click="$emit('close')">
Button
</button>
</div>
</div>
</div>
</div>
</transition>
</script>
</div>
</template>
<script>
export default {
components: { },
props: ['header', 'footer', 'body', 'button'],
data: () => ({
showModal: false
}),
methods: {
open () {
console.log('Opening modal')
this.showModal = true
}
}
}
</script>
<style>
#modal {
/*color: #000;*/
}
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
/*padding: 20px 30px;*/
background-color: #25262D;
color: #FEFEFE;
border-radius: 3px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-size: 1.2em;
}
.modal-header {
border-radius: 3px;
background-color: #202128;
border: none;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
/*background-color: #202128;*/
border: none;
}
.modal-footer {
text-align: center;
border: none;
}
.modal-footer .btn {
font-size: 1.0em;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
</style>
I add a modal in my App.vue:
<button #click="openUpdatedModal()" type="button" class="btn btn-default" data-toggle="modal" data-target="#modal">
Launch Updated Modal
</button>
<modal ref="updatedModal" v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<div slot="header">custom header</div>
</modal>
<script>
import Modal from './components/Modal'
export default {
components: { Modal },
data: () => ({
showModal: false
}),
methods: {
openUpdatedModal () {
this.$refs.updatedModal.open()
}
}
}
</script>
When I click the button I get the text in console "Opening modal" but nothing happens.
I can summon it and it works if I have ALL the code in App.vue
What am I missing?
I made it work by creating a ModalComponent.vue and removing the script tag as Phil suggested in the comments. Here's the code.
ModalComponent.vue:
<template>
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default{
}
</script>
Here's how I defined my component:
Vue.component('modal', ModalComponent);
Modal button in markup:
<button id="show-modal" #click="showModal = true">Show Modal</button>
And the modal component being called on the page:
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
It's worth noting that I had to declare the showModal property wherever I use my modal.

Can't use Slick-Slider with Dynamic data whwn pulling from external API

Trying to build a website with some sliders.for slider i used SLICK slider.Here is my code .
<template>
<div class="homePopularVenue">
<div class="container">
<h2 class="text-center sub-headwords">POPULAR VENUE</h2>
<!--slider start-->
<div class="home-slider-popular-venue">
<div>
<div class="well">
<span class="half-image-temp">
<img class="img-rsponsive" src=" http://placehold.it/250x150" alt="">
</span>
<span class="half-content-temp">
<h3 class="title">HELLOW</h3>
<h5 class="small">Welcome to Hellow World</h5>
BOOK NOW
</span>
</div>
</div>
</div>
<div class="text-center">
VIEW ALL
</div>
</div>
</div>
</template>
<script>
export default {
name: 'homePopularVenue',
data () {
return {
posts: []
}
},
mounted() {
this.create();
this.$http.get('https://newsapi.org/v1/sources?language=en')
.then(response => {
console.log(response.data);
this.posts = response.data.source;
})
},
methods:{
create (){
$('.home-slider-popular-venue').slick({
slidesToShow: 4,
slidesToScroll: 1,
infinite: true,
dots: true,
autoplay: true,
autoplaySpeed: 2000,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
infinite: true,
dots: true
}
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2
}
},
{
breakpoint: 480,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
}
]
});
}
},
created: function(){
}
}
</script>
<style scoped>
.sub-headwords:after{
content:"";
width:200px;
background: #F99A13;
height: 4px;
display: block;
margin: auto;
margin-top: 15px;
margin-bottom: 30px;
}
.home-slider-popular-venue .well{
box-shadow: 2px 4px 8px 0 rgba(46,61,73,.2);
margin: 30px 10px;
transition: .2s ease-in-out;
}
.home-slider-popular-venue .well:hover{
box-shadow: 12px 15px 20px 0 rgba(46,61,73,.15);
}
.half-image-temp{
max-height: 250px;
}
.half-image-temp img{
width: 100%;
display: block;
margin: auto;
}
.half-content-temp{
}
</style>
Everything was good before i put the data dynamicaly in slider, after putting the data dynamically in slider its not working.
<template>
<div class="homePopularVenue">
<div class="container">
<h2 class="text-center sub-headwords">POPULAR VENUE</h2>
<!--slider start-->
<div class="home-slider-popular-venue">
<div v-for="post in posts">
<div class="well">
<span class="half-image-temp">
<img class="img-rsponsive" src=" http://placehold.it/250x150" alt="">
</span>
<span class="half-content-temp">
<h3 class="title">HELLOW</h3>
<h5 class="small">Welcome to Hellow World</h5>
<p> {{post.id}} </p>
BOOK NOW
</span>
</div>
</div>
</div>
<div class="text-center">
VIEW ALL
</div>
</div>
</div>
</template>
Also the same problem is happening with OWl.Carousel.