Condition erros in vue.js - javascript

I am trying to check my variable is empty. I think my code looks fine.
But it is not working..
Current my vue.js version is 2.5.13
Below is my code
<template>
<div v-if="Object.keys(this.myValues).length === 0">
is empty
</div>
<div v-else>
good
</div>
</template>
<script>
export default {
data: function() {
return {
myValues: new Object()
};
}
};
</script>

This is the working example data refers to current template so remove this
var app = new Vue({
el: '#el',
data: function() {
return {
myValues: new Object(),
another: {some:'value'}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="el">
<div v-if="Object.keys(myValues).length === 0">
myValues is empty
</div>
<div v-else>
myValues have some element
</div>
<div v-if="Object.keys(another).length === 0">
Another is empty
</div>
<div v-else>
Anoter have some element
</div>
</div>

Related

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>

Vue emit ref of another element on click

Hello how i can get the element by className or something else. So i need to get element by className actually but i can't figure out how to do that in this case:
here is my fiddle: https://jsfiddle.net/cihanzengin/aq9Laaew/294154/
Simply i wanna do that: When click to menu in method i try to get element which have classname nav. I tried to make with ref but i can't
here is my code :
<div id="app">
<some-component #get-element="getElement"></some-component>
</div>
<script>
var someComponent = Vue.component("some-component", {
template: `
<div class="columns mobile-navigation">
<div class="column drawer">
<a class="is" #click="$emit('get-element')">MENU</a>
</div>
<div ref="nav" class="column mobile-nav-wrapper">
<p> Some Text </p>
</div>
</div>
`
});
var app = new Vue({
el: '#app',
data: {
},
components: {
"mobile-nav": mobileNav
},
methods: {
getElement() {
console.log(this.$refs.nav);
}
}
});
</script>
You can try something like this.
var classToCheck = 'myclass';
if( this.$refs.nav.classList.includes(classToCheck) ){
// includes above class
}
OR
myclickevent(event){
event.target.classList // this will get you classList of of clicked element then you can compare
}
This contains all the classes for your element
this.$refs.nav.classList
i found the solution:
here is need to add **<some-component>** to ref attribute for accessing to ref inside jsx.
Then will possible to access to nav ref with: this.$refs.someRef.$refs.nav
<div id="app">
<some-component #get-element="getElement" ref="someRef"></some-component>
</div>
<script>
var someComponent = Vue.component("some-component", {
template: `
<div class="columns mobile-navigation">
<div class="column drawer">
<a class="is" #click="$emit('get-element')">MENU</a>
</div>
<div ref="nav" class="column mobile-nav-wrapper">
<p> Some Text </p>
</div>
</div>
`
});
var app = new Vue({
el: '#app',
data: {
},
components: {
"mobile-nav": mobileNav
},
methods: {
getElement() {
console.log(this.$refs.someRef.$refs.nav);
}
}
});
</script>

How to Add or Remove Vue.js component dynamically (programmatically or on the fly)

Here is my code, this is just a example code, if the below works then this will help me to build something else that I am working on.
<template>
<div id="wrapper">
<div id="divOne">
<!-- Add or remove component here dynamically -->
</div>
<div id="divTwo">
<!-- Add or remove component here dynamically -->
</div>
<!-- There will be more divs like #divOne #divTwo above -->
<div>
<input type="radio" id="one" value="divOne" v-model="pickedDiv">
<label for="one">One</label>
</div>
<div>
<input type="radio" id="two" value="divTwo" v-model="pickedDiv">
<label for="two">Two</label>
</div>
<button #click="addComponent">Add Component</button>
</div>
</template>
<script>
import SomeComponent from './SomeComponent'
export default {
data() {
return {
pickedDiv: '',
pickedDivPreviously: ''
propItems: ['item1', 'item2']
}
}
methods: {
addComponent () {
//-- This is not working code but I need something like this --//
this.pickedDivPreviously = this.pickedDiv // event not sure how to get previously selected div
const divThatIsPicked = document.getElementById(this.pickedDiv)
const divThatWasPickedPreviously = document.getElementById(this.pickedDivPreviously)
// code here to remove/empty/destroy old component from 'divThatWasPickedPreviously'
divThatWasPickedPreviously.innerHTML = ""
// code here to add new component in 'divThatIsPicked'
divThatIsPicked.appendChild('<some-component :someProp="propItems" #someEvent="someFn">')
}
}
}
</script>
I don't want to distract you from answering actual question but If you are curious about what I am working then check this :) Here I am trying to add new child DIV at the end of the row when any row item is clicked.
I will be more than happy if this is converted to vue than the actual question asked above, as said please don't get distracted from actual question if you find it hard :)
I got help from JamesThomson in forum.vuejs.org, though the solution did not fix my issue but I got to understand the limitation or possibilities of using Vue.js.
JamesThomson says:
Yeah, your example code definitely won’t work. When working with Vue
you need to think in a data oriented way, not DOM oriented (like
jQuery)
Taken from your SO post:
Here I am trying to add new child DIV at the end of the row when any
row item is clicked.
I assume this is your end goal for this topic. A simple example of
this can be achieved like so:
https://codepen.io/getreworked/pen/XZOgbm?editors=1010
let Welcome = {
template: `
<p #click="toggleMsg()">Welcome {{ msg }}!</p>
`,
data () {
return {
msg: 'home'
}
},
methods: {
toggleMsg () {
return this.msg = this.msg === 'home' ? 'back' : 'home';
}
}
}
const App = new Vue({
el: '#app',
data: {
children: [
Welcome
]
},
methods: {
add () {
this.children.push(Welcome);
},
}
});
<link rel="stylesheet" href="//cdn.rawgit.com/milligram/milligram/master/dist/milligram.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<template v-for="(child, index) in children">
<component :is="child" :key="child.name"></component>
</template>
<button #click="add()">Add Another</button>
</div>
or you can use a render function for more flexibility
https://jsfiddle.net/jamesbrndwgn/ku7m1dp0/9/
const Reusable = {
template: '<div>{{ name }} {{ bar }}</div>',
props: {
name: {
type: String
}
},
data () {
return {
bar: 'Bar'
}
}
}
const App = new Vue({
el: '#app',
data: {
items: []
},
methods: {
addComponent () {
const renderComponent = {
render (h) {
return h(Reusable, {
class: ['foo'],
props: {
name: 'Foo'
}
})
}
}
this.items.push(renderComponent)
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<link rel="stylesheet" href="//cdn.rawgit.com/milligram/milligram/master/dist/milligram.min.css">
<div id="app">
<component v-for="item in items" ref="itemRefs" :is="item" :key="item.name"></component>
<button #click="addComponent">Add Component</button>
</div>
I found one of the other ways that does kinda same as above but work only with old vue.js-1 not with vue.js-2:
var createNewBox = function() {
var MyPartial = Vue.extend({});
window.partial = new MyPartial({
template: '#partial',
data: function() {
return {
txt: 'This is partial'
}
},
methods: {
print: function() {
console.log('this.txt : ' + this.txt)
console.log('main.txt : ' + main.txt)
},
},
})
window.partial.$mount().$appendTo('body')
}
window.main = new Vue({
el: '#main',
data: function() {
return {
txt: 'This is main'
}
},
methods: {
show: function() {
createNewBox()
}
},
})
<script src="https://cdn.bootcss.com/vue/1.0.17/vue.min.js"></script>
<div #click="show" style="width:200px;height:200px;background:#000" id="main">
<template id="partial">
<div style="width:100px;height:100px;background:#ff0" #click.stop="print"></div>
</template>
</div>
this converted to Vue.
https://codepen.io/jacobgoh101/pen/Kojpve
<div id="app">
<div class="parent">
<div class="child" #click="handleChildClick" data-new-child-id="1">1234</div>
<div class="child" #click="handleChildClick" data-new-child-id="2">12341234 </div>
<div class="child" #click="handleChildClick" data-new-child-id="3">123412341234</div>
<div class="child" #click="handleChildClick" data-new-child-id="4">1234</div>
<div class="new-child" v-if="[1,2,3,4].indexOf(showNewChild) > -1">boom</div>
<div class="child" #click="handleChildClick" data-new-child-id="5">12341234</div>
<div class="child" #click="handleChildClick" data-new-child-id="6">123412341234</div>
<div class="child" #click="handleChildClick" data-new-child-id="7">1234</div>
<div class="child" #click="handleChildClick" data-new-child-id="8">12341234</div>
<div class="new-child" v-if="[5,6,7,8].indexOf(showNewChild) > -1">boom</div>
<div class="child" #click="handleChildClick" data-new-child-id="9">123412341234</div>
<div class="new-child" v-if="[9].indexOf(showNewChild) > -1">boom</div>
</div>
</div>
Javascript
new Vue({
el: '#app',
data: {
showNewChild:null
},
methods: {
handleChildClick(e) {
let id = e.target.dataset.newChildId;
id = Number(id);
this.showNewChild = id;
}
}
})

Declare reactive data properties in vue.js?

I have a very basic vue.js app:
var app = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
messages: [
'Hello from Vue!',
'Other line...'
]
}
})
The following html works fine:
<div class="container" id="app">
<div class="row" style="">
<div class="col-md-8 offset-md-2">
<span v-for="msg in messages">${msg}</span>
</div>
</div>
</div>
However very similar html block does not:
<div class="container" id="app">
<div class="row" style="">
<div class="col-md-8 offset-md-2">
<textarea id="chat_area" readonly="" rows="20">
<span v-for="msg in messages">${msg}</span>
</textarea>
</div>
</div>
</div>
[Vue warn]: Property or method "msg" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
I'm using Vue v2.3.3. What could be the problem?
As documentation says, interpolation in textareas won't work, so you need to use v-model.
If the only thing you want to do is to display html inside textarea, you could in theory use an ugly workaround by wrapping your array fields inside a function and set that function as textarea v-model:
var app = new Vue({
el: '#app',
delimiters: ['${', '}'],
data: {
messages: [
'Hello from Vue!',
'Other line...'
]
},
computed:{
multiLineMessages: function(){
var result = "";
for(var message of this.messages){
result += '<span>' + message + '</span>'
}
return result;
}
}
});
template part:
<div class="container" id="app">
<div class="row" style="">
<div class="col-md-8 offset-md-2">
<textarea v-model="multiLineMessages" placeholder="add multiple lines">
</textarea>
</div>
</div>
</div>
It's more like a proof that it's doable but I highly don't recommend using it anywhere, as html shouldn't be generated this way (especially larger chunks of it).
jsFiddle preview

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