v-if not working on template - javascript

So I am relatively new to learning Vue.js. I have gotten to understand most of it so far but I still have trouble with v-if never working. For example...
I would expect these to not show because showProgress is false!
<template v-if="showProgress">
<div id="progressCols" class="md-layout">
<div class="md-layout-item" :class="[{ activeStep: currentStep(1) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(2) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(3) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(4) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(5) }, '.md-elevation-1']"></div>
{{ showProgress }}
</div>
</template>
<script>
export default {
name: 'ProgressCols',
data: function(){
return {
showProgress: false
}
},
methods: {
currentStep(i){
let n = 0;
if (this.$route.params.name == "Ailments") {
n = 1;
} else if (this.$route.params.name == "Effects") {
n = 2;
}
i < n ? true : false
}
}
}
</script>

The v-if should be on the outermost div, not template.
<template>
<div id="progressCols" class="md-layout" v-if="showProgress">
<div class="md-layout-item" :class="[{ activeStep: currentStep(1) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(2) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(3) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(4) }, '.md-elevation-1']"></div>
<div class="md-layout-item" :class="[{ activeStep: currentStep(5) }, '.md-elevation-1']"></div>
{{ showProgress }}
</div>
</template>
<script>
export default {
name: 'ProgressCols',
data: function(){
return {
showProgress: false
}
},
methods: {
currentStep(i){
let n = 0;
if (this.$route.params.name == "Ailments") {
n = 1;
} else if (this.$route.params.name == "Effects") {
n = 2;
}
i < n ? true : false
}
}
}
</script>
Without a v-else on the template, it doesn't know what to render when false.

Related

How can I automaticaly switch through VueJS tabs on an Interval

This is my very first VueJS Applicationa and it is more of a POC than a serious project.
Nevertheless I really nead a solution to my problem.
The Application resembles a dashboard for several "Groups" and each group has a certain amount of data that I can visualize. For each kind of data I have one tab and in every tab there is this kind of data visualized for each group.
So. Now the problem that im facing is that as a dashboard it should be able to display all the information without a user interaction. To realise that, I need the tabs to change on a timeinterval. so for example every 5 Minutes another Tab is shown. I hope that makes sense.
I googled some solutions already, but for them to work I would need to rewrite almost all of my current work. So I am looking for a solution that I can implement into my current project.
Here is my code so far:
Dashboard.vue
<template>
<div style="margin-left:220px" class="text-center m-3">
<tabs>
<tab title="Robots">
<div v-if="responseAvailable == true">
<div v-for="customer in result" class="customerCard">
<span class="card-content">
{{ customer.CustomerName }}
<hr />
<div v-for="robot in customer.ListOfRobots" :class="robot.State">
{{ robot.Name }}
</div>
</span>
</div>
</div>
</tab>
<tab title="Jobs" :selected="true">
<div v-if="responseAvailable == true">
<div v-for="customer in result" class="customerCard">
<span class="card-content">
{{ customer.CustomerName }}
<hr />
<apexchart width="500" type="bar"
:options="customer.options" :series="customer.ListForFrontend">
</apexchart>
</span>
</div>
</div>
</tab>
<tab title="Queues">
<div v-if="responseAvailable == true">
<div v-for="customer in result" class="customerCard">
<span class="card-content">
{{ customer.CustomerName }}
<hr />
<div v-for="queue in customer.ListOfQueues" id="chart">
{{ queue.Name }}
<apexchart type="line" height="200" :options="lineChartOptions" :series="queue.FrontedListQueues"></apexchart>
</div>
</span>
</div>
</div>
</tab>
<tab title="Triggers">
<div v-if="responseAvailable == true">
<div v-for="customer in result" class="customerCardPie">
<span class="card-content">
{{ customer.CustomerName }}
<hr />
<apexchart type="pie" width="280" :options="piechartOptions" :series="customer.TriggersFE"></apexchart>
</span>
</div>
</div>
</tab>
</tabs>
</div>
</template>
<script>
import M from 'materialize-css'
import ApexCharts from 'apexcharts'
import Tab from './Tabs/Tab.vue'
import Tabs from './Tabs/Tabs.vue'
export default {
name: 'Dashboard',
components: {
Tab,
Tabs
},
/*data() {
return {
result: null,
responseAvailable: null,
timer: ""
}
},*/
data: () => ({
result: null,
responseAvailable: null,
timer: "",
pieSeries: [34,345,123,6,75],
piechartOptions: {
chart: {
width: 280,
type: 'pie',
},
labels: ['Enabled', 'Disabled'],
colors: ['#11FF00', '#FF0000',],
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
},
legend: {
position: 'bottom'
}
}
}]
},
lineChartOptions: {
chart: {
height: 200,
type: 'line',
zoom: {
enabled: false
}
},
dataLabels: {
enabled: false
},
colors: ['#11FF00', '#FFA200', '#FF0000', ],
stroke: {
curve: 'smooth'
},
grid: {
row: {
colors: ['#f3f3f3', 'transparent'], // takes an array which will be repeated on columns
opacity: 0.5
},
},
xaxis: {
//categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'],
categories: ['01:00', '02:00', '03:00', '04:00', '05:00', '06:00', '07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00', '21:00', '22:00', '23:00', '00:00',],
}
},
}),
created() {
this.fetchAPIData();
this.timer = setInterval(this.fetchAPIData, 900000)
},
mounted() {
M.AutoInit(); // That way, it is only initialized when the component is mounted
},
methods: {
fetchAPIData() {
this.responseAvailable = false;
fetch("https://localhost:44378/api/values", {
"method": "GET",
})
.then(response => {
if (response.ok) {
return response.json()
} else {
alert("Server returned " + response.status + " : " + response.statusText);
}
})
.then(response => {
this.result = response;
console.log(this.result[0].ListOfQueues[1].FrontedListQueues[0].data);
this.responseAvailable = true;
})
.catch(err => {
alert(err);
});
},
cancelAutoUpdate() {
clearInterval(this.timer)
}
},
beforeDestroy() {
clearInterval(this.timer)
}
};
</script>
Tab.vue
<template lang="html">
<div class='tab' v-show='isActive'>
<slot></slot>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: 'Tab'
},
name: { requred: true },
selected: { default: false }
},
data() {
return {
isActive: true
}
},
mounted() {
this.isActive = this.selected;
},
computed: {
href() {
return "#" + this.name.toLowerCase().replace(/ /g, '-');
}
}
}
</script>
Tabs.vue
<template lang="html">
<div>
<ul class='tabs__header'>
<li v-for='tab in tabs'
:key='tab.title'
#click='selectTab(index)'
:class='{"tab__selected": (index == selectedIndex)}'>
<a :href="tab.href" #click="selectNewTab(tab)">{{ tab.name }}</a>
</li>
</ul>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
selectedIndex: 0, // the index of the selected tab,
tabs: [] // all of the tabs
}
},
created() {
this.tabs = this.$children
},
mounted() {
//this.selectTab(0);
let tabsVue = this;
setInterval(function () {
tabsVue.changeToNextTab();
}, 1000);
},
methods: {
changeToNextTab() {
if (!this.tabs.length) {
return;
}
let activeIndex = this.tabs.findIndex(tab => tab.isActive);
if (activeIndex === -1) {
activeIndex = 0;
}
// add one to the index for the next tab
activeIndex++;
if (activeIndex >= this.tabs.length) {
// Reset to first tab if on the last tab
activeIndex = 0;
}
this.selectNewTab(this.tabs[activeIndex]);
},
selectNewTab(slectedTab) {
this.tabs.forEach(tab => {
tab.isActive = (tab.name == slectedTab.name)
})
}
}
}
</script>
Any help is much appreciated. And how I said, this is my first VueJS project so I am aware some of the things are not best practice.
Codesandbox: https://codesandbox.io/s/priceless-mountain-m9fl9?file=/src/main.js

Vue.js: How to do validation in dynamic v-for

I get a JSON with 60 questions that are displayed every 10 out of 10. But I need to check that all of them have been answered before moving on to the next 10 questions.
My component:
<div class="test-questions comp" id="scrollb">
<div class="question" v-for="(q, index) in currentPageItems" :key="q.id">
<div class="statement">
{{q.id}}. {{q.text}}
</div>
<div class="options yes-no">
<div :class="{'active':relato.quest['q'+q.id] === 1}" class="caption option yes" #click="handleYes('q'+q.id, q.ck)">Sim</div>
<div :class="{'active':relato.quest['q'+q.id] === 0}" class="caption option no" #click="handleNo('q'+q.id, q.ck)">Não</div>
</div>
</div>
</div>
<div class="action-row">
<button v-if="pageNumber <= 4" class="btn btn-green" #click="next()"><span>Próximo</span></button>
<button v-if="pageNumber == 5" class="btn btn-green" #click="salvarRelato()"><span>Publicar</span></button>
</div>
My Script:
<script>
export default {
props: ['grupoid','getperguntas','perguntas'],
data(){
return {
perpage: 10,
pageNumber: 0,
relato: {
loading: false,
errors: '',
titulo: '',
sonho: '',
resumo: '0',
ck: {
c1: '',
c2: '',
c3: '',
c4: '',
c5: '',
c6: '',
c7: '',
exist: '',
},
quest: {
q1: '',q2: '',q3: '',q4: '',q5: '',q6: '',q7: '',q8: '',q9: '',q10: '',
q11: '',q12: '',q13: '',q14: '',q15: '',q16: '',q17: '',q18: '',q19: '',q20: '',
q21: '',q22: '',q23: '',q24: '',q25: '',q26: '',q27: '',q28: '',q29: '',q30: '',
q31: '',q32: '',q33: '',q34: '',q35: '',q36: '',q37: '',q38: '',q39: '',q40: '',
q41: '',q42: '',q43: '',q44: '',q45: '',q46: '',q47: '',q48: '',q49: '',q50: '',
q51: '',q52: '',q53: '',q54: '',q55: '',q56: '',q57: '',q58: '',q59: '',q60: '',
},
ckQuestAssociations: {
c1: [],
c2: [],
c3: [],
c4: [],
c5: [],
c6: [],
c7: [],
exist: [],
} ,
},
}
},
computed:{
currentPageItems(){
return this.perguntas['questions'].slice(this.pageNumber*this.perpage,this.pageNumber*this.perpage+this.perpage)
}
},
methods: {
next(){
this.pageNumber++;
document.getElementById("scrollb").scrollIntoView({behavior: "smooth"});
},
previous(){
this.pageNumber--;
},
handleYes(quest, ck) {
this.relato.quest[quest] = 1;
ck.forEach(c => {
if (this.relato.ckQuestAssociations[c].indexOf(quest) === -1) {
this.relato.ckQuestAssociations[c].push(quest);
++this.relato.ck[c];
}
});
},
handleNo(quest, ck) {
this.relato.quest[quest] = 0;
console.log(this.relato.quest);
console.log(this.relato.ck);
ck.forEach(c => {
let index = this.relato.ckQuestAssociations[c].indexOf(quest);
if (index !== -1) {
this.relato.ckQuestAssociations[c].splice(index, 1);
--this.relato.ck[c];
}
});
}
}
}
</script>
What would be the suggestion to resolve this?
                                                                                                                                                                                       
In next method check if every qi (0<i=<60) has value equals to 1 or 0 until the current page :
next(){
let valid=Object.values(this.relato.quest).slice(0,(pageNumber+1)*perpage).every(q=>q==0 || q==1)
if(valid){
this.pageNumber++;
document.getElementById("scrollb").scrollIntoView({behavior: "smooth"});
}
},

Vuejs add and remove classes with v-for

i'm making a list of items with vuejs v-for loop. I have some API data from server.
items: [
{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
Template
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: ????}" #click="toggleActive">
{{ item.foo }}
{{ item.number }}
</div>
</div>
JS
methods: {
toggleActive() {
//
}
}
I need following: When i'm clicking on div add class active, if i have already active class - remove active class.( toggle ). Also i can select multiple items.
How can i do this? I don't have boolean variable in items array, and i shouldn't move item in a separate component
Here you go.
new Vue({
el: "#app",
data: {
items: [{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
},
methods: {
toggleActive(index) {
let item = this.items[index];
item.active = !item.active;
this.$set(this.items, index, item);
}
}
})
.active {
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: item.active}" #click="toggleActive(index)">
{{ item.foo }} {{ item.number }}
</div>
</div>
</div>
Here's a JS Fiddle:
https://jsfiddle.net/eywraw8t/250008/
App.vue
<template>
<div>
<div
v-for="(item, i ) in items"
:key="i"
:class="{ active: i === activeItem}"
>
// some looped items from data here
// button for active toggle
<button #click="selectItem(i)"> make item active </button>
</div>
</div>
</template>
Data and Methods
<script>
export default {
data() {
return {
activeItem: null,
};
},
methods: {
selectItem(i) {
this.activeItem = i;
},
},
};
</script>

VueJS - Dynamic repeating component

I have a <filter> component in a .vue file that has some properties to control the filter of a query.
This <filter> can be added / removed on-the-fly as the user needs. It's behavior is very similar to the Google Analytics segmentation filter, or Advanced Custom Fields from WordPress.
The only solution I see is instantiating this component dynamically and iterate over an array of these components inside my main app, but I don't exactly know how to do it.
Vue.component("my-filter", {
template: "#filterTemplate",
data: function() {
return {
field: null,
value: null
}
},
mounted: function() {
this.$emit("filter-created", this);
},
methods: {
removeFilter: function() {
console.log("Remove this filter");
}
}
});
var app = new Vue({
el: "#app",
data: {
filtersCount: 5,
filters: [] // PROBLEM! I can't decrement on my filtersCount and remove the correct filter. Iteration should be over my "filtersCount" property.
},
methods: {
filterCreated: function(filterObj) {
this.filters.push(filterObj);
},
addFilter: function() {
this.filtersCount += 1;
}
}
});
* {
font-family: "Helvetica", "mono";
font-size: 16px;
}
.filterContainer + .filterContainer {
margin-top: 10px;
}
.filterContainer {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<!-- I shouldn't iterate over an integer value, but over an array of objects to remove the right ones -->
<my-filter v-on:filter-created="filterCreated" v-for="(index, filter) in filtersCount" :key="index"></my-filter>
<br>
<button #click="addFilter">Add filter</button>
</div>
<script type="text/x-template" id="filterTemplate">
<div class="filterContainer">
<input type="text" :value="field" placeholder="Field" />
<input type="text" :value="value" placeholder="Value" />
<button #click="removeFilter">Remove filter</button>
</div>
</script>
A few things can be changed to get it working (I'm just assuming what you are looking for!)
First, you don't need a data property for counting filters (filtersCount), you can loop through the filters property.
Second, adding this to the filters property can cause unexpected behaviour because this references the entire Vue component. I would recommend adding plain objects that represent the filter data and pass the data as props. Note: that the index is also passed as a prop which can be referenced and allow the filter to be removed through emitting
And lastly, your v-for seems to be reversed. It should be (filter, index) instead of (index, filter).
Vue.component("my-filter", {
template: "#filterTemplate",
props: [
'field',
'value', // filter data
'id',
'index' // index that allows this filter to be removed
],
data: function() {
return {
field: this.field,
value: this.value
}
},
methods: {
removeFilter: function() {
this.$emit('remove-filter', this.index);
},
handleInput: function(prop, e) {
this.$emit('update-filter', { index: this.index, prop, value: e.target.value });
}
}
});
window.vm = new Vue({
el: "#app",
data: {
filters: [
{ id: 1, field: null, value: null },
{ id: 2, field: null, value: null },
{ id: 3, field: null, value: null },
{ id: 4, field: null, value: null },
{ id: 5, field: null, value: null }
]
},
methods: {
addFilter: function() {
var id = Math.max.apply(Math,this.filters.map(function(o){return o.id;})) + 1;
this.filters.push({ id, field: null, value: null });
},
removeFilter: function(index) {
this.filters.splice(index, 1);
},
updateFilter: function(payload) {
this.filters[payload.index][payload.prop] = payload.value;
}
}
});
* {
font-family: "Helvetica", "mono";
font-size: 16px;
}
.filterContainer + .filterContainer {
margin-top: 10px;
}
.filterContainer {
display: block;
border: 1px solid black;
padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<button #click="addFilter">Add Filter</button>
<br><br>
<my-filter v-for="(filter, index) in filters" :key="index" :field="filter.field" :value="filter.value" :id="filter.id" :index="index" #remove-filter="removeFilter" #update-filter="updateFilter"></my-filter>
</div>
<script type="text/x-template" id="filterTemplate">
<div class="filterContainer">
<div>Index: {{ index }}, ID: {{ id }}</div>
<input type="text" :value="field" placeholder="Field" #input="handleInput('field', $event)" />
<input type="text" :value="value" placeholder="Value" #input="handleInput('value', $event)" />
<button #click="removeFilter">Remove filter</button>
</div>
</script>

Nested Check all and UnCheck all models should be reflected in JSON using angularjs

I have to implement nested Check all and Uncheck all in my web application using angular Js. I am struggling to implement those things and its models(checkall,unCheckall,sub Checks)should be updated inside the json. How to achieve it. Thanks In advance.
angular.module("app", []).controller("ctrl", function($scope) {
$scope.options = [{
value: 'Check All 1',
selected: false,
subList: [{
subSelect: false,
id: 1,
value: "check_1"
}, {
subSelect: false,
id: 2,
value: "check_2"
}]
}, {
value: 'Check All 2',
selected: false,
subList: [{
subSelect: false,
id: 3,
value: "check_1"
}, {
subSelect: false,
id: 4,
value: "check_2"
}]
}];
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="app" ng-controller="ctrl">
<form id="selectionForm">
<div ng-repeat="option in options" ng-model="options">
<input type="checkbox" ng-click="toggleAll()" ng-model="option.selected">Check all
<br>
<div ng-repeat="sub in option.subList" ng-model="option.subList" style="margin:0px 15px">
<input type="checkbox" ng-model="sub.subSelect" ng-change="optionToggled()">{{sub.value}}
<div>
</div>
</form>
</div>
{{options}}
</body>
</html>
Implement toggleAll() something like this :
$scope.toggleAll = function(option) {
angular.forEach(option.subList, function(value, key) {
value.subSelect = option.selected;
});
};
And implement optionToggled() like this :
$scope.optionToggled = function(option) {
var flag = true;
angular.forEach(option.subList, function(value, key) {
flag = flag && value.subSelect;
});
option.selected = flag;
};
And notice that :
toggleAll() is now called on ngChange.
current option is passed to toggleAll() and optionToggled() as input param.
angular.module("app", []).controller("ctrl", function($scope) {
$scope.options = [{
value: 'Check All 1',
selected: false,
subList: [{
subSelect: false,
id: 1,
value: "check_1"
}, {
subSelect: false,
id: 2,
value: "check_2"
}]
}, {
value: 'Check All 2',
selected: false,
subList: [{
subSelect: false,
id: 3,
value: "check_1"
}, {
subSelect: false,
id: 4,
value: "check_2"
}]
}];
$scope.toggleAll = function(option) {
angular.forEach(option.subList, function(value, key) {
value.subSelect = option.selected;
});
};
$scope.optionToggled = function(option) {
var flag = true;
angular.forEach(option.subList, function(value, key) {
flag = flag && value.subSelect;
});
option.selected = flag;
};
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<body>
<div ng-app="app" ng-controller="ctrl">
<form id="selectionForm">
<div ng-repeat="option in options"
ng-model="options">
<input type="checkbox"
ng-change="toggleAll(option)"
ng-model="option.selected">Check all
<br>
<div ng-repeat="sub in option.subList"
ng-model="option.subList"
style="margin:0px 15px">
<input type="checkbox"
ng-model="sub.subSelect"
ng-change="optionToggled(option)">{{sub.value}}
</div>
</div>
</form>
{{options}}
</div>
</body>
</html>
working link attached.
And here the code goes
$scope.toggleAll = function(index, torf){
$scope.options[index].subList.forEach(function(val){
val.subSelect = torf;
});
};
$scope.optionToggled = function(id){
$scope.options.forEach(function(val) {
if(val.id == id){var isTrue = true;
var isFalse = false;
val.subList.forEach(function(val1) {
if(!val1.subSelect||!isTrue)
isTrue = false;
if(val1.subSelect||isFalse)
isFalse = true;
});
if(isTrue){
val.selected = true;
}else{
val.selected = false;
}
}
});
};
Try this:
<div class="pull-left">
<a ng-click='checkAll()'>All</a> |
<a ng-click='uncheckAll()'>None</a>
</div>
<input type="checkbox" ng-model="data.selectedRecord" />
$scope.checkAll = function () {
$scope.checkList = [];
angular.forEach($scope.checkList, function (data){
data.selectedRecord = true;
$scope.checkList.push(data.id);
});
}
$scope.uncheckAll = function () {
angular.forEach($scope.checkList, function (data) {
$scope.checkList = [];
data.selectedRecord = false;
});
}
I am also using this.It is working for me.

Categories

Resources