Vue component not displaying data in HTML page - javascript

index.html:
<body>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
index.js:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
const Counter = {
data() {
return {
counter: 0
}
}
}
Vue.createApp(Counter).mount('#counter')
and the output is:
Hello Vue!
{{ counter }}
Why is my code for counter not working?

You're using the syntax for two separate versions of Vue.
new Vue is v2, Vue.createApp is v3.
For your code to work with v2:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
const Counter = new Vue({
el: '#counter',
data() {
return {
counter: 0
}
}
})
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>
For your code to work with v3:
var app = Vue.createApp({
data() {
return {
message: 'Hello Vue!'
}
}
})
const Counter = Vue.createApp({
data() {
return {
counter: 0
}
}
})
app.mount('#app');
Counter.mount('#counter');
<script src="https://unpkg.com/vue#next"></script>
<div id="app">
{{ message }}
</div>
<div id="counter">
{{ counter }}
</div>

Related

How to interpret html in an attribute with Vue

I need to convert some code to Vue, I have a rendering difference in the alt attribute of an image, because I can't find a way to interpret the html in the attributes, I haven't found any topics that talk about this do you have an idea please?
In the examples I made on purpose not to put src to see the alternative texts.
Vue.component('first-image', {
inheritAttrs: false,
template: '<div class="container-image"><img v-bind="$attrs"></div>'
});
Vue.component('second-image', {
template: '<img>',
});
new Vue({
el: '#app',
data() {
return {
alternativeText: '1 000€',
};
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- Without VueJS -->
<img alt="1 000€">
<br>
<br>
<!-- With VueJS -->
<div id="app">
<first-image :alt="alternativeText"></first-image>
<second-image alt="1 000€"></second-image>
</div>
You can try like following snippet:
Vue.component('first-image', {
inheritAttrs: false,
template: '<div class="container-image"><img v-bind="$attrs"></div>'
});
Vue.component('second-image', {
template: '<img>',
});
new Vue({
el: '#app',
data() {
return {
alternativeText: '1 000€',
};
},
methods: {
decodeHtml(html) {
const txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- Without VueJS -->
<img alt="1 000€">
<br>
<br>
<!-- With VueJS -->
<div id="app">
<first-image :alt="decodeHtml(alternativeText)"></first-image>
<second-image alt="1 000€"></second-image>
</div>

appending vuejs data to a div

I have something I have been trying to do which is challenging. I have a simple div that gets appended to the top level on the click of a button. The issue is I want vuejs data appended inside of this div. I am not quite sure how to bind this data, I have tried using a simple expression, but no luck. Can someone please let me know how this can be solved--and with a div, not a bootstrap modal
new Vue({
el: "#app",
data: {
chocs:[{"title":'a man tale'},{"title":'a boy tale'}]
},
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(`<div id="popover-dialog"> data here {{this.chocs[0].title}}
</div>`);
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">
Click Me
</button>
<div id="fox">
</div>
</div>
Without JQuery, the Vue-way:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}],
titleToBeAppended: ''
}),
methods: {
handleTileClick: function(){
this.titleToBeAppended = this.chocs[0].title
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="popover-dialog">
<p>Data here: {{ titleToBeAppended }}</p>
<button v-on:click="handleTileClick()">Click Me</button>
</div>
</div>
Using template literals:
new Vue({
el: "#app",
data: () => ({
chocs:[{"title":'a man tale'}, {"title":'a boy tale'}]
}),
methods: {
handleTileClick: function(){
alert(this.chocs[0].title);
$("#fox").append(
`<div id="popover-dialog">data here: ${this.chocs[0].title}</div>`
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div id="app">
<h2>Todos:</h2>
<button v-on:click="handleTileClick()">Click Me</button>
<div id="fox"></div>
</div>

Vue.js remove element from list

I am trying to create a simple webpage where I can add or remove textboxes using vue.js.
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push({});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list":key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
</div>
<script src="index.js"></script>
</body>
</html>
I added a snippet to the page (I think you need to expand or make it full screen to see the result properly), my problem is that on Delete button it doesn't remove the corresponding row, but the last one.
Has anyone any idea about how can I do this work fine?
Thank you very much :)
It is actually removing the correct item out of the array, but you're not seeing it because you're not changing the value of the model only the textarea which is not tied to the value instead its just cached to :key="index", below is an example which should show that, simply by adding a counter you can see it's deleting the correct object.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: [],
counter: 0,
};
},
methods: {
deleteFromList(index) {
this.list.splice(index, 1);
},
addItem() {
this.list.push(this.counter++);
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30">{{item}}</textarea>
<button #click="deleteFromList(index)">Delete</button>
</li>
</ul>
<pre>{{ list }}</pre>
</div>
To fix the issue and have dynamic changing values/model you should use v-model on the value and indexOf when removing.
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data() {
return {
list: []
};
},
methods: {
deleteFromList(item) {
this.list.splice(this.list.indexOf(item), 1);
},
addItem() {
this.list.push('');
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<button #click="addItem()">Add 1</button>
<ul>
<li v-for="(item, index) in list" :key="index">
<textarea rows="1" cols="30" v-model="list[index]"></textarea>
<button #click="deleteFromList(item)">Delete</button>
</li>
</ul>
</div>

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;
}
}
})

Passing props to VueJS component thru v-repeat turns up empty

I'm a bit new to VueJS. I have this Blade template, which is passed the variable $plans which contains [{id:1,name:'1st Plan'},{id:2,name:'2nd Plan'}]:
#extends('layouts.backend')
#section('content')
#if(Auth::user()->can('edit-plans'))
<edit-plans
:workouts="{!! json_encode($plans) !!}"
></edit-plans>
#endif
#endsection
Within edit.vue:
<template>
<workout
v-repeat="workouts"
></workout>
</template>
<script>
export default {
props: [
'workouts'
]
}
</script>
Within workouts.vue:
<template>
<div>{{ id }} :: {{ name }}</div>
</template>
<script>
export default {
props: [
]
}
</script>
I have these templates registered globally:
Vue.component('edit-plans', require('./components/plans/edit.vue'));
Vue.component('workout', require('./components/plans/workout.vue'));
When I compile with yarn, I simply get one line with :: in it but noid or name values showing up on two lines as expected.
when I check the Chrome Vue JS developer extension, I see this in the EditPlans component...
...but nothing in the Workouts component.
In edit.vue declare the v-for (instead of v-repeat) and pass the props. In workout.vue, declare the props so they are available in the template.
edit.vue:
<template>
<workout
v-for="workout in workouts" :id="workout.id" :name="workout.name" :key="workout.id"
></workout>
</template>
<script>
export default {
props: ['workouts']
}
</script>
workout.vue:
<template>
<div>{{ id }} :: {{ name }}</div>
</template>
<script>
export default {
props: ['id', 'name']
}
</script>
Demo:
Vue.component('edit-plans', {
template: "#edit-plans-tpl",
props: ['workouts']
});
Vue.component('workout', {
template: "#workout-tpl",
props: ['id', 'name']
});
new Vue({
el: '#app',
data: {
message: [1,2]
}
})
<script src="https://unpkg.com/vue#latest/dist/vue.min.js"></script>
<template id="edit-plans-tpl">
<div>
<workout
v-for="workout in workouts" :id="workout.id" :name="workout.name" :key="workout.id"
></workout>
</div>
</template>
<template id="workout-tpl">
<div>{{ id }} :: {{ name }}</div>
</template>
<div id="app">
<edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
</edit-plans>
</div>
Update, per comment: What if I just want to pass each full workout into the child instead of each part of the object? In other words, I'd be able to do {{ workout.id }} :: {{ workout.name }}
You can use v-bind for that. Just change the edit.vue, keep workout.vue the same as above.
edit.vue:
<template>
<workout
v-for="workout in workouts" v-bind="workout" :key="workout.id"
></workout>
</template>
<script>
export default {
props: ['workouts']
}
</script>
workout.vue: same as above.
Demo for this:
Vue.component('edit-plans', {
template: "#edit-plans-tpl",
props: ['workouts']
});
Vue.component('workout', {
template: "#workout-tpl",
props: ['id', 'name']
});
new Vue({
el: '#app',
data: {
message: [1,2]
}
})
<script src="https://unpkg.com/vue#latest/dist/vue.min.js"></script>
<template id="edit-plans-tpl">
<div>
<workout
v-for="workout in workouts" v-bind="workout" :id="workout.id"
></workout>
</div>
</template>
<template id="workout-tpl">
<div>{{ id }} :: {{ name }}</div>
</template>
<div id="app">
<edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
</edit-plans>
</div>
Update, per comment: So no matter what, I have to declare every property within the workout object? I can't just do props: ['workout'] within the workout.vue so I can do {{ workout.id }} :: {{ workout.name }}?
You can declare the workout prop in the child and pass it in the parent like :workout="workout":
edit.vue:
<template>
<workout
v-for="workout in workouts" :workout="workout" :key="workout.id"
></workout>
</template>
<script>
export default {
props: ['workouts']
}
</script>
workout.vue:
<template>
<div>{{ workout.id }} :: {{ workout.name }}</div>
</template>
<script>
export default {
props: ['workout']
}
</script>
Demo for this:
Vue.component('edit-plans', {
template: "#edit-plans-tpl",
props: ['workouts']
});
Vue.component('workout', {
template: "#workout-tpl",
props: ['workout']
});
new Vue({
el: '#app',
data: {
message: [1,2]
}
})
<script src="https://unpkg.com/vue#latest/dist/vue.min.js"></script>
<template id="edit-plans-tpl">
<div>
<workout
v-for="workout in workouts" :workout="workout" :key="workout.id"
></workout>
</div>
</template>
<template id="workout-tpl">
<div>{{ workout.id }} :: {{ workout.name }}</div>
</template>
<div id="app">
<edit-plans :workouts='[{"id":1,"name":"1st Plan"}, {"id":2,"name":"2nd Plan"}]'>
</edit-plans>
</div>
Note: :key="workout.id" added to the loop: This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state. (thanks #channasmcs).

Categories