Classic scenario: I want to display a list, but when it's empty I want to display "No data".
The fact that it is somewhat complicated to do something I would expect to be simple makes me think I'm probably doing it wrong.
Here is my current solution.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>
<div id="element">
<div v-if="empty">No item in inventory</div>
<div v-for="(index, item) in inventory">
{{item.key}}<button onclick="remove('{{index}}')">remove</button>
</div>
</div>
<script type="text/javascript">
"use strict";
var vm;
$(function() {
vm = new Vue({
el: '#element',
data: {
inventory: {"id1" : {"key" : "val1"}, "id2" : {"key" : "val2"}},
empty: false
},
watch: {
inventory: function() {
vm.empty = $.isEmptyObject(vm.inventory);
}
}
});
});
function remove(key) {
Vue.delete(vm.inventory, key);
}
</script>
Is there a better solution than this?
You can just use length of inventory in v-if, like following:
<div id="element">
<div v-if="!inventory.length">No item in inventory</div>
<div v-for="(index, item) in inventory">
{{item.key}}
<button v-on:click="remove(index)">remove</button>
</div>
</div>
Given that inventory variable is a hash and not an array, you can use any of the following to find it is empty and use that in v-if:
ECMA 5+:
Object.keys(inventory).length === 0
Pre-ECMA 5:
function isEmpty(obj) {
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
return false;
}
return JSON.stringify(obj) === JSON.stringify({});
}
As you are already using jquery, you can also do:
jQuery.isEmptyObject({}); // true
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdn.jsdelivr.net/vue/1.0.16/vue.js"></script>
<div id="element">
<div v-if="isEmpty">No item in inventory</div>
<div v-for="(index, item) in inventory">
{{item.key}}<button #click="remove(index)">remove</button>
</div>
</div>
<script type="text/javascript">
"use strict";
var vm;
$(function() {
vm = new Vue({
el: '#element',
data: {
inventory: {"id1" : {"key" : "val1"}, "id2" : {"key" : "val2"}},
empty: false
},
methods: {
remove: function(index) {
Vue.delete(this.inventory, index);
}
},
computed: {
isEmpty: function () {
return jQuery.isEmptyObject(this.inventory)
}
}
});
});
</script>
After searching for a few minutes, I come up with a better solution to check whether the object is empty or not.
Object.keys( YOUR_OBJECT ).length == 0 // Check if it's empty.
It will return 0 if it's empty. If you want to check whether the array is empty or not you can definitely go for this solution below,
YOUR_ARRAY.length == 0 // Check if it's empty.
In my case it's an object, not array. So, it may also help. Happy coding :)
If it's an array, you can use
v-if="!array.length"
Worked Great for me...
v-if="array.length == 0"
<div v-if="Object.length > 0 ">
//Write your logic here
</div>
<div v-else>
No Records found
</div>
You can just use this
v-if="(YOUR_OBJECT).total == 0"
Related
I have a sidebar that you can see below:
<template>
<section>
<div class="sidebar">
<router-link v-for="(element, index) in sidebar" :key="index" :to="{ name: routes[index] }" :class='{active : (index==currentIndex) }'>{{ element }}</router-link>
</div>
<div class="sidebar-content">
<div v-if="currentIndex === 0">
Profile
</div>
<div v-if="currentIndex === 1">
Meine Tickets
</div>
</div>
</section>
</template>
<script>
export default {
mounted() {
EventBus.$on(GENERAL_APP_CONSTANTS.Events.CheckAuthentication, () => {
this.authenticated = authHelper.validAuthentication();
});
console.log()
this.checkRouter();
},
data(){
return {
currentIndex:0,
isActive: false,
sidebar: ["Profile", "Meine Tickets"],
routes: ["profile", "my-tickets"],
authenticated: authHelper.validAuthentication(),
}
},
computed: {
getUser() {
return this.$store.state.user;
},
},
methods: {
changeSidebar(index) {
this.object = this.sidebar[index].products;
this.currentIndex=index;
},
checkRouter() {
let router = this.$router.currentRoute.name;
console.log(router);
if(router == 'profile') {
this.currentIndex = 0;
} else if(router == 'my-tickets') {
this.currentIndex = 1;
}
},
},
}
</script>
So when the link is clicked in the sidebar, the route is being changed to 'http://.../my-account/profile' or 'http://.../my-account/my-tickets'. But the problem is currentIndex doesn't change therefore, the content doesn't change and also I cannot add active class into the links. So how do you think I can change the currentIndex, according to the routes. Should I fire an event, could you help me with this also because I dont know how to do it in Vue. I tried to write a function like checkRouter() but it didn't work out. Why do you think it is happening? All solutions will be appreciated.
So if I understand correctly, you want currentIndex to be a value that's based on the current active route? You could create it as a computed property:
currentIndex: function(){
let route = this.$router.currentRoute.name;
if(router == 'profile') {
return 0;
} else if(router == 'my-tickets') {
return 1;
}
}
I think you could leverage Vue's reactivity a lot more than you are doing now, there's no need for multiple copies of the same element, you can just have the properties be reactive.
<div class="sidebar-content">
{{ sidebar[currentIndex] }}
</div>
Also, you might consider having object be a computed property, something like this:
computed: {
getUser() {
return this.$store.state.user;
},
object() {
return this.sidebar[currentIndex].products;
}
},
Just use this.$route inside of any component template. Docs .You can do it simple without your custom logic checkRouter() currentIndex. See simple example:
<div class="sidebar-content">
<div v-if="$route.name === 'profile'">
Profile
</div>
<div v-if="$route.name === 'my-tickets'">
Meine Tickets
</div>
</div>
This is the JSON response we are getting. Missing some very simple VUEJS logic to meet our requirements.
If the JSON object is empty we need to show the DIV accordingly. But, when I try with length function it's not working. Can anyone help to solve this issue?
{
"moduleInfo": {
"moduleType": "LONG"
},
"FlightElements": {
"modulenames": {
"Ele1": "Flight Parts",
"Ele2": "Flight Wings"
}
}
}
<!-- If moduleType is LONG and "Modulesnames" are available -->
<div class="display-container" v-if='moduleType=="LONG" && !FlightElements.modulenames.length'>
<p>Display Modules</p>
<div>
<!-- If moduleType is LONG and "Modulesnames" is empty -->
<div class="display-container" v-if='moduleType=="LONG" && FlightElements.modulenames.length'>
<p>Display Empty Modules</p>
<div>
Try to check if object property(object) is empty:
new Vue({
el: "#demo",
data() {
return {
mod:{
"moduleInfo": {"moduleType": "LONG"},
"FlightElements": {
"modulenames": {"Ele1": "Flight Parts","Ele2": "Flight Wings"}
}
},
mod1:{
"moduleInfo": {"moduleType": "LONG"},
"FlightElements": {
"modulenames": {}
}
}
}
}
})
Object.entries(objectToCheck).length === 0
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo" style="display: flex; gap: 1em;">
<div style="background: green;">
<div class="display-container" v-if='mod.moduleInfo.moduleType=="LONG" && Object.entries(mod.FlightElements.modulenames).length !== 0'>
<p>Display Modules</p>
</div>
<div class="display-container" v-if='mod.moduleInfo.moduleType=="LONG" && Object.entries(mod.FlightElements.modulenames).length === 0 '>
<p>Display Empty Modules</p>
</div>
</div>
<div style="background: red;">
<div class="display-container" v-if='mod1.moduleInfo.moduleType=="LONG" && Object.entries(mod1.FlightElements.modulenames).length !== 0'>
<p>Display Modules</p>
</div>
<div class="display-container" v-if='mod1.moduleInfo.moduleType=="LONG" && Object.entries(mod1.FlightElements.modulenames).length === 0 '>
<p>Display Empty Modules</p>
</div>
</div>
</div>
Try to use lodash _.isEmpty(value)
<!-- If moduleType is LONG and "Modulesnames" is empty -->
<div class="display-container" v-if='moduleType=="LONG" && _.isEmpty(FlightElements.modulenames)'>
<p>Display Empty Modules</p>
<div>
A few notes.
JSONs in Javascript don't have a length property. Calling json.length will always return undefined. If you had an array of JSONs, however, then you would be able to call .length on it.
const json = { "key": "example" }
const array = [ { "key": "example1" }, { "key": "example2" } ]
console.log(json.length)
console.log(array.length)
// #=> undefined
// #=> 2
If you wanted the length of a JSON via it's keys, you'd have to count how many keys it has. Check this answer for more details on that.
Second, you shouldn't necessarily need lodash as makbeth's comment indicates, you should be able to simply call the modulenames key. It will return false if it has no contents.
Take a JSON like below:
const json = {
"user": { }
}
If you call json in an if, it will return true. Calling json.user, however, will return false.
if (json.user) {
console.log("Hello!")
} else {
console.log("Goodbye!")
}
// #=> Goodbye!
It seems to me, assuming that the code you posted is what's actually being used, that you're simply not calling the correct JSON keys here.
You first need to save the JSON you're getting from the API into a variable, and then you can access those keys properly.
Something like this:
<template>
<div v-if="data.moduleType === 'LONG' && data.FlightElements.moduleNames">
<p>Display Modules</p>
</div>
<div v-if="data.moduleType === 'LONG' && !data.FlightElements.moduleNames">
<p>Display Empty Modules</p>
</div>
</template>
<script>
export default {
data() {
return {
data = {}
}
},
methods: {
async fetchData() {
this.data = callApi();
}
}
}
</script>
I've been searching for the answer 2nd day. But still couldn't find solution.
I have the modal window template. And the main page template from where I need to update modal window size by clicking on the button (span). Shortly it's like this for HTML:
<template id="modal">
<div>
<div :class="'modal-' + size">
...
</div>
</div>
</template>
<template id="list">
<div>
<span #click="onDetails">
Show Details
</span>
</div>
<modal size="md" #showdetails="showdetails();" ref="modal">
...
</modal>
</template>
And for JS:
Vue.component("modal", {
template: "#modal",
props: {
size: {
type: String,
default: ""
}
},
methods: {
onDetails() {
this.$emit("showdetails")
}
}
})
var List = Vue.extend({
template: "#list",
methods: {
showDetails() {
if(this.$refs.modal.size == "md") {
this.$refs.modal.size = "lg"
}
<additional code here>
}
}
})
When I'm accessing this.$refs.modal.size for read - it's OK. When I'm just changing it from showDetails - OK if only this action in the function. When I'm put something else instead of - size is not updating.
For example:
this.$refs.modal.size = "lg" - will work
this.$refs.modal.theme = "danger"; this.$refs.modal.size = "lg" - neither of them are updating
What am I doing wrong?
You need to assign the attribute value of Size by the javascript method setAttribute . Example : this.$refs.modal.setAttribute('size', 'lg')
There is a working demo below:
new Vue({
el: '#app',
methods: {
showdetails() {
console.log(this.$refs.modal.getAttribute('size'));
this.$refs.modal.setAttribute('size', 'lg')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>
<div id='app'>
<button size="md" #click="showdetails" ref="modal">Click</button>
</div>
I am trying to do a very simple vue example and it won't display. I've done similar things before, but this won't work.
It is an extremely simple task list. It is an input with a submit button that adds an item to a list. For some reason the component does not render at all. I am very lost am supposed to give a presentation on vue. I was hoping to use this as an example.
I'm really not sure what else to say about this, but stack overflow won't let me submit this without typing more information about the issue.
<div id="app">
<task-list></task-list>
</div>
Vue.component('task-list-item', {
props: ["task"],
template: '#task-list-item-template'
})
Vue.component('task-list', {
data: function () {
return {
taskList: [],
newTask: ''
}
},
methods: {
addTask: function () {
var self = this;
if (self.newTask !== ""
&& self.newTask !== null
&& typeof self.newTask !== "undefined") {
this.taskList.push(self.newTask);
this.newTask = "";
}
}
},
template: '#task-list-template'
})
new Vue({
el: '#app',
data: function () {
return {
}
}
})
<script id="task-list-template" type="text/x-template">
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList"
v-bind:task="taskItem">
</task-list-item>
</ul>
</script>
<script id="task-list-item-template" type="text/x-template">
<li>{{task}}</li>
</script>
I am getting no error messages of any kind.
I think the problem is there should be only 1 child under <script id="task-list-template" type="text/x-template"></script>. In task-list-template, you have multiple children. Try to wrap them in 1 div
<script id="task-list-template" type="text/x-template">
<div>
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList"
v-bind:task="taskItem">
</task-list-item>
</ul>
</div>
</script>
Demo on codepen
According to A Single Root Element
Every component must have a single root element
To fix you can do some thing like:
<script id="task-list-template" type="text/x-template">
<div>
<input v-model="newTask" />
<button v-on:click="addTask()">Add Task</button>
<ul>
<task-list-item v-for="taskItem in taskList" v-bind:task="taskItem">
</task-list-item>
</ul>
</div>
</script>
I have got Vue-JS app. After use click variable rasters_previews_list get new data. I would like to generate list with them. I can't understand which directive I should use to handle this even.
Here is my code:
var userContent = Vue.extend({
template: `
<div class="LayersMenuSectionContent" v-if="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li> // generate list here
<ul>
</div>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function()
{
},
methods:
{
}
});
Should I use v-on or v-if?
When rasters_previews_list is changed, list is autorendered in v-for.
new Vue({
el: '#app',
template: `
<div class="LayersMenuSectionContent" v-show="rasters_previews_list.length">
<ul v-for="img in rasters_previews_list">
<li>{{img.id}}</li>
<ul>
</div>
<button #click="add">Add</button>
`,
data: function () {
return {
rasters_previews_list: [] // when come new data I should generate li with then
}
},
ready: function(){ },
methods: {
add(){
this.rasters_previews_list.push({id: 'hello'},{id: 'world'});
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="app"></div>
Extra: You must use v-show instead of v-if for this case