Why isn't the value of the object properties inserted here? - vue.js

I started learning vue yesterday and I'm now fiddling around on the CLI3.
Currently I'm trying out the different approaches to inserting data into my markup.
Here, I basically want to make a "list of Lists".
This here is list1:
<template>
<div>
<ul v-for="item in items">
<li :text="item"></li>
</ul>
</div>
</template>
<script>
export default{
name:"list1",
data() {
return {
items: {
item1 : "itemA",
item2 : "itemB",
item3 : "itemC"
}
}
}
}
</script>
This is the list of lists:
<template>
<div>
<h1>All my stuff in a biiig list!</h1>
<listOfLists />
</div>
</template>
<script>
import listOfLists from '#/components/listOfLists.vue'
export default {
name: 'myComplexView.vue',
components: {
listOfLists
}
}
And this is inserted into myComplexView.vue inside views (im working with routing as well, though it doesnt work perfectly yet as you will see on the screenshot), which you can see here:
<template>
<div>
<h1>All my stuff in a biiig list!</h1>
<listOfLists />
</div>
</template>
<script>
import listOfLists from '#/components/listOfLists.vue'
export default {
name: 'myComplexView.vue',
components: {
listOfLists
}
}
</script>
This is the result Im getting:
https://imgur.com/H8BaR2X
Since routing doesnt work correctly yet, I had to enter the url into the browser manually. Fortunately, the site at least loaded that way as well, so I can tackle these problems bit by bit ^^
As you can see, the data was iterated over correctly by the v-for.
However, the data wasn't inserted in the text attribute of the li elements.
I'm a bit clueless about the cause though.
Maybe I'm not binding to the correct attribute? Vue is using its own naming conventions, based off standard html and jquery as far as I understood.

You've got this in your template:
<li :text="item"></li>
This will bind the text attribute to the value, outputting, e.g.:
<li text="itemA"></li>
You should be able to see this in the developer tools. In the picture you posted you hadn't expanded the relevant elements so the attributes can't be seen.
I assume what you want is to set the content. For that you'd either use v-text:
<li v-text="item"></li>
or more likely:
<li>{{ item }}</li>
Either of these will output:
<li>itemA</li>
On an unrelated note, I would add that this line will create multiple lists:
<ul v-for="item in items">
It's unclear if that's what you want. You're going to create 3 <ul> elements, each with a single <li> child. If you want to create a single <ul> then move the v-for onto the <li>.

Related

How to have a scoped toggle variable in VueJS

I'm coming from an AngularJS background where the ng-repeat has a scoped variables and I'm trying to figure out how to achieve a similar result without the need to create a new component which seems overkill for a lot of situations.
For example:
<div class="item" v-for="item in items">
<div class="title">{{item.title}}</div>
<a #click="showMore = !showMore">Show more</a>
<div class="more" v-if="showMore">
More stuff here
</div>
</div>
In AngularJS that code would work great, but in VueJS if you click on show more it causes the variable to update for every item in the items list, is there anyway to create a local scoped variable inside of the v-for without the need to make a new component?
I was able to get it to work by having the showMore variable be something like #click="showMore = item.id" and then v-if="showMore.id = item.id" but that also seems like too much extra complexity for something that should be much simpler? The other problem with that approach is you can only get one item to show more rather than allow for multiple items to be toggled shown at once.
I also tried changing the items model to include item.showMore but once again that adds more complexity and it causes a problem if you need to update an individual item since the model is changed.
Are there any simpler approaches to this?
What do you think about this: CODEPEN
<template>
<div>
<h1>Items</h1>
<div v-for="item in items"
:key="item.id"
class="item"
>
{{item.name}}
<button #click="show=item.id">
Show More
</button>
<div v-if="item.id == show">
{{item.desc}}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{id:1, name:"One", desc: "Details of One"},
{id:2, name:"Two", desc: "Details of Two"},
{id:3, name:"Three", desc: "Details of Three"}
],
show: null
};
}
};
</script>
<style>
.item{
padding: 5px;
}
</style>

Using plain JS in Vue.js Component

So, I want to create a navbar and rather than re-invent the wheel, I am using some public code to speed up my MVP dev.
Essentially, I am using this nav-bar code - https://codepen.io/PaulVanO/pen/GgGeyE.
But I am not sure of how I can implement jquery part within my Vue code (I have made a component, copied over html and css, now just need to integrate the jquery functionality within it.)
Here is the Jquery code I need to integrate.
$('#toggle').click(function() {
$(this).toggleClass('active');
$('#overlay').toggleClass('open');
});
It would be really thankful if anyone could help me accomplish with this.
Assuming you have your markup (html and css) as part of one component, getting the toggle to add/remove a class would be really simple, you just need to have a method toggle the active state and a data property to keep the data. An example would be better, so here it goes.
In your component object:
{
data() {
return {
isActive: false
}
},
methods: {
toggleMenu(){
this.isActive = !this.isActive
}
}
}
In your markup you need this
<div class="button_container" id="toggle" :class="{'active': isActive}" #click="toggleMenu">
<span class="top"></span>
<span class="middle"></span>
<span class="bottom"></span>
</div>
------------------------------------
<div class="overlay" id="overlay" :class="{'open': isActive}">
<nav class="overlay-menu">
<ul>
<li >Home</li>
<li>About</li>
<li>Work</li>
<li>Contact</li>
</ul>
</nav>
That should get you going, just note i used the shorthand form for v-on and for v-bind
EDIT:
Here's also a link to an updated pen with the whole example

Images in Vue not showing up

I am having trouble displaying images in my Vue CLI project.
Here is what I have going on. This vue file accesses a json file with a few references to the individual Eyewear objects, all that works. I have references to the image I am trying to access in the json file. And with the current code, I can see the correct image reference in the browser, but it does not load the image. Is it something to do with webpack or another loader needing to load the image file?
<template>
<div>
<h1 id='callout'>Select Your Eyewear</h1>
<div id='item' v-for='item in items' :key=item.id>
<img :src='`..${item.images.frontal}`' alt='eyeware' />
<ul id='itemLIist'>
<li >
{{ item.brand }}
</li>
<li>
{{ item.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
import items from "../assets/eyewear.json";
export default {
name: "ItemList",
data: function() {
return {
items: items.eyewear
};
}
};
</script>
<style scoped>
</style>
I don't know this works for you or not. But in my case providing the full path of the image works for me. in your screenshot reference starting from "../assets" instead of that try something "src/assets" (Full path with out dots)
and for make this simple, first just try to hard code full path src to a image tag and see whether it's working or not.
and let me know if this works for you. =)

x-template has trouble displaying value on the v-for

I had this issue while trying to render html into a vue component.
I am trying to insert component html through x-template. The issue is when I was trying to display the value {{i.value}} like this it was throwing error on console.
<script type="text/x-template" id="first-template">
<div>
<ul>
<li v-for="i in dataCollection">{{ i.id }}</li>
</ul>
</div>
</script>
Vue.component('menu', {
template: '#first-template',
data() {
return {
dataCollection: [{"id":"01"}, {"id":"02"}, {"id":"03"}],
}
}
});
The error on console was:
But when I was giving value as attribute like:
<script type="text/x-template" id="first-template">
<div>
<ul>
<li v-for="i in dataCollection" :id="i.id"></li>
</ul>
</div>
</script>
it works perfect.
Anyone know any fix ?
You should not put script/x-template tages inside of the element that you mount to the main instance to. Vue 2.0 will read all of its content and try to use it as a template for the main instance, and Vue's virtualDOM treats script/x-template's like normal DOM, which screws everthing up,
Simply moving the template out of the main element solved the problem.
Source
This is a suggestion, not a answer.
As #DmitriyPanov mentioned, you'd better bind unique key when using v-for.
Another issue is you'd better to use non built-in/resevered html elements.
so change component id from menu to v-menu or else you like.
Then simulate similar codes below which are working fine.
I doubt the error is caused by some elements of dataCollection doesn't have key=id (probably you didn't post out all elements). You can try {{ 'id' in i ? i.id : 'None' }}.
Vue.component('v-menu', { //
template: '#first-template',
data() {
return {
newDataCollection: [{"id":"01"}, {"id":"02"}, {"id":"03"}, {'xx':0}],
dataCollection: [{"id":"01"}, {"id":"02"}, {"id":"03"}]
}
}
});
new Vue({
el: '#app',
data() {
return {testProperty: {
'test': '1'
}}
},
methods:{
test: function() {
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<v-menu></v-menu>
</div>
<script type="text/x-template" id="first-template">
<div>
<div style="float:left;margin-right:100px;">
<p>Old:</p>
<ul>
<li v-for="(i, index) in dataCollection" :key="index">{{ i.id }}</li>
</ul>
</div>
<div>
<p>Adjusted:</p>
<ul>
<li v-for="(i, index) in newDataCollection" :key="index">{{ 'id' in i ? i.id : 'None' }}</li>
</ul>
</div>
</div>
</script>
I think the problem here lies in the placement of the X-Template code (I had the same issue). According to the documentation:
Your x-template needs to be defined outside the DOM element to which Vue is attached.
If you are using some kind of CMS, you might end up doing just that.
What helped me in that case was (based on your example):
Placing the X-template script outside the #app
passing the collection as a prop to the v-menu component:
<v-menu v-bind:data-collection="dataCollection"></v-menu>
list dataCollection as a prop inside the v-menu component:
Vue.component('v-menu', { //
template: '#first-template',
props: [ "dataCollection" ],
...
});
I hope that helps anyone.
In 2.2.0+, when using v-for with a component, a key is now required.
You can read about it here https://v2.vuejs.org/v2/guide/list.html#v-for-with-a-Component

Providing the model for a component as a slot

Consider the following two custom elements in Aurelia (list & row):
row.html
<template>
<span>${name}</span>
</template>
row.js
export class Row
{
name = "Marry";
}
list.html
<template>
The List
<ol>
<li repeat.for="r of rows">
<slot name="rowItem" model.bind="r"></slot>
</li>
</ol>
</template>
list.js
import { bindable } from 'aurelia-framework';
export class List
{
#bindable
rows = [{name: "John"}];
}
The app will tie them together:
app.html
<template>
<require from="./list"></require>
<require from="./row"></require>
<list rows.bind="users">
<row slot="rowItem"></row>
</list>
</template>
app.js
export class App
{
users = [{name: "Joe"}, {name: "Jack"}, {name: "Jill"}];
}
The problem is that the model for the row is not set correctly. All I get as the output is the following:
The List
1.
2.
3.
So the question is; how can I provide the model for a slot in Aurelia?
Here's a Gist to demonstrate the problem in action.
Slots aren't going to work for what you want to do. It's a known limitation of slots in Aurelia. Slots can't be dynamically generated (such as inside a repeater).
Luckily, there's another option to accomplish what you want: template parts.
Template parts aren't well documented (my fault, I should have written the docs for them). But we have some docs in our cheat sheet. I've modified your gist to show how to use them: https://gist.run/?id=1c4c93f0d472729490e2934b06e14b50
Basically, you'll have a template element in your custom element's HTML that has the replaceable attribute on it along with a part="something" attribute (where something is replaced with the template part's name. Then, when you use the custom element, you'll have another template element that has the replace-part="something" attribute (again, where something is replaced with the template part's name). It looks like this:
list.html
<template>
The List
<ol>
<li repeat.for="row of rows">
<template replaceable part="row-template">
${row}
</template>
</li>
</ol>
</template>
app.html
<template>
<require from="./list"></require>
<require from="./row"></require>
<list rows.bind="users">
<template replace-part="row-template">
<row name.bind="row.name"></row>
</template>
</list>
</template>