2d array in Vue.js - javascript

I'm fairly new to Vue and js and I'm trying to create a Todo App with firebase integration.
What i need it to look like is the following: there should be an option to create a new list of tasks and an option to create new tasks within this list.
So i need a list of lists.
My firebase database structure looks like this:
users (collection) -> tasks(collection) -> and inside the followin structure:
I understand that there should be a nested v-for element right?
Something like this:
<div v-for="task in tasks" :key="task.id">
<ul v-for="todo in task(?)">
</ul>
</div>
But i don't understand how to approach it.
Any advice will be GREATLY appreciated!

<template>
<ul>
<li v-for="task in tasks" :key="task.id">
{{task.name}}
<ul>
<li v-for="td in task.todo" :key="td.id">
{{ td.completed }}
<br>
{{ td.date }}
<br>
{{ td.title }}
<br>
{{ tdurgent }}
</li>
</ul>
</li>
</ul>
</template>
<script>
import {db} from './firebase';
export default {
data() {
return {
users: {}
}
},
firebase: {
tasks: {
source: db.ref('tasks'),
// Optional, allows you to handle any errors.
cancelCallback(err) {
console.error(err);
}
}
}
}
</script>
firebase.js
import Firebase from 'firebase'
const firebaseApp = Firebase.initializeApp({
// Populate your firebase configuration data here.
...
});
// Export the database for components to use.
// If you want to get fancy, use mixins or provide / inject to avoid redundant imports.
export const db = firebaseApp.database();

You can write like this
<div v-for="task in tasks" :key="task.id">
<ul v-for="todo in task.keyOfArrayType" :key="todo.id" >
{{todo.name}}
</ul>
</div>

In the json no key id display for both outer and inner if you interested to put key:="task.id" then you have to change the structure like
otherwise remove :key = "task.id" and :key="td.id"
<ul>
<li v-for="task in tasks" :key="task.id">
{{name}}
<ul>
<li v-for="td in task.todo" :key="td.id">
{{ completed }}
<br>
{{ date }}
<br>
{{ title }}
<br>
{{ urgent }}
</li>
</ul>
</li>
</ul>

Related

Angular ngFor cannot render entire data

I fetch data from api by resolver before loading component, also can see whole data in console and {{ data.length }} prints correct 100 number as well, but ngFor renders random amount of data about 20
// data.component.ts
data: BooksData[];
ngOnInit(): void{
this.route.data.subscribe(
data => {
console.log(data) // prints entire data correctly, data: Array(100)
this.data = data;
}
)
}
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ d.title }}</li>
</ul>
i also tried slice pipe *ngFor="let d of data | slice:0:(data.length-1)" but same result
You have syntax problem in the interpolation of data.title
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ data.title }}</li>
</ul>
Should be
{{ data.length }} <!-- 100 -->
<ul>
<li *ngFor="let d of data">{{ d.title }}</li>
</ul>
Syntax issue data.title should be d.title
.html:
<ul>
<li *ngFor="let d of data | async">{{ d.title }}</li>
</ul>
You already know now what is the problem from above comments.
i.e data.tile need to changed to d.title
If you want you can use below more readable code
books$: BooksData[];
ngOnInit(): void{
this.books$ = this.route.data;
}
In html
<ul *ngIf="books$ | async as books">
<li *ngFor="let book of books">
{{ book.title }}
</li>
</ul>

How to detect which property is selected/clicked

I'm trying to detect which property is selected/clicked out of ngFor , which comes from a REST API.
I want to get which property(broker.username) is selected out of others
<div class="list-group">
<ul *ngFor="let broker of brokers">
<li class="broker_list"> {{broker.username}}</li>
</ul>
</div>
this is the REST call
[
{ id: 1, username: "PersonA"},
{ id: 2, username: "PersonB"}
]
You have to use event handler on anchor tag like this:
<div class="list-group">
<ul *ngFor="let broker of brokers">
<li class="broker_list">
<a (click)="onSelect(broker)" href="#" class="list-group-item list-group-item-action" style="text-align: center;"> {{ broker.username }}</a>
</li>
</ul>
</div>
Within your component add method:
#Component({ })
class XYZ {
// ... some code
public onSelect(broker) {
// Do what you need with broker?
}
}
Pass the broker directly in the method, like this
<div class="list-group">
<ul *ngFor="let broker of brokers">
<li class="broker_list"> {{broker.username}}</li>
</ul>
</div>
There are several ways, one of those would be to do something like this.
1) Add click handler on a tag:
<div class="list-group">
<ul *ngFor="let broker of brokers">
<li class="broker_list"> {{broker.username}}</li>
</ul>
</div>
2) Add method to component:
selected(brokerName: string) {
console.log(brokerName);
}
You could add a (click) property that calls a function, which takes a broker as a parameter. You can then access the username of that broker.
{{broker.username}}
The a tag should be able to know what the current broker is, since it is inside the *ngFor.

How to render a list of static content with Vue named slot?

I have trouble figuring out how to get the following to work:
My parent template
<comp>
link 1
link 2
</comp>
and my component comp template looks like the following:
<ul class="comp">
<li class="comp-item"><slot name="links"></slot></li>
</ul>
currently all my anchors goes to that single li tag (which is expected)
but I would like to be able to produce multiple li for every named slot I inserted like the following:
<ul class="comp">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
Is there any way to achieve what I need without using scoped slot? Because my content is pure HTML so I feel it is unnecessary to put static content inside prop in order to render them.
From what I have seen, most vue UI framework requires you to use another custom component for the list item, which I feel is over killed for the problem. Is there any other way to do this?
This is easily accomplished with a render function.
Vue.component("comp", {
render(h){
let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
return h('ul', {class: 'comp'}, links)
}
})
Here is a working example.
console.clear()
Vue.component("comp", {
render(h){
let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
return h('ul', {class: 'comp'}, links)
}
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp>
link 1
link 2
</comp>
</div>
Or with the help of a small utility component for rendering vNodes you could do it like this with a template.
Vue.component("vnode", {
functional: true,
render(h, context){
return context.props.node
}
})
Vue.component("comp", {
template: `
<ul class="comp">
<li class="comp-item" v-for="link in $slots.links"><vnode :node="link" /></li>
</ul>
`
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp>
link 1
link 2
</comp>
</div>
You can make use of scoped slots instead of slots
Your comp component receives a prop links which is an array of links(since static initialized as a custom option). Iterate over the links and pass link as data to the slot just like passing props to a component
Vue.component("comp", {
template: `
<ul class="comp">
<li class="comp-item" v-for="link in links">
<slot v-bind="link"></slot>
</li>
</ul>
`,
props: ["links"]
})
new Vue({
el: "#app",
// custom static option , accessed using vm.$options.links
links: [
{text: "link1"},
{text: "link2"},
{text: "lin3"}
]
})
In the parent where the comp component is used make use of a <template> element with a special attribute slot-scope , indicating that it is a template for a scoped slot.
The value of slot-scope will be used as the name of a temporary variable that holds the props object passed from the child:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp :links="$options.links">
<template slot-scope="link">
{{link.text}}
</template>
</comp>
</div>
Here is the working fiddle
If you don't like to put your data in array, and render list with v-for
You can put all of them in the component, no slot:
<ul class="comp">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
or with slot:
<comp>
<ul class="comp" slot="links">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
</comp>

How to access item in <slot> inside v-for (vue.js)

How to send item from v-for to slot? In vue.js.
ListComponent:
<ul>
<li v-for="item in list">
<slot></slot>
</li>
</ul>
Page view:
<list-component :list="list">
<span v-text="item.value"></span>
</list-component>
Code <span v-text="item.value"></span> can't access item (from component's scope). Is it a way to send an item from component to code in tag?
P.S. I know, that as a workaround I can send $index from component to parent view, but it's a little bit hacky
UPD: Example of my current workaround (somebody may find this useful):
Declare index in view's data:
data () {
return {
index: 0,
list: [ ... ]
}
Add to index param to the view's template:
<list-component :list="list" :index="index">
<span v-text="list[index].value"></span>
</list-component>
Declare index in component's props:
props: {
index: {
type: Number
}
}
Add index to v-for's element:
<ul>
<li v-for="item in list" index="$index">
<slot></slot>
</li>
</ul>
the bind expression is compiled in the context who define them,so:
v-text="item.value"
can not be compiled because in Page view there is no "item" defined.
maybe you can try to change your code structure like below:
ListComponent:
//content in component
<span>i am text in component,item value is:{{item.value}}</span>
<slot></slot>
Page view:
<ul>
<li v-for="item in list">
<list-component :item="item"></list-component>
</li>
</ul>

Vue.js v-repeat not working

I'm trying to follow a tutorial on Vue.js, but the code for the first lesson isn't working for v-repeat. I'm trying to display the data in the tasks object:
<div id="tasks">
<div>
<h1>Tasks</h1>
<ul class="list-group">
<li v-repeat="task: tasks">
{{ task.body }}
</li>
</ul>
</div>
</div>
<script>
new Vue ({
el: '#tasks',
data: {
tasks: [
{ body: 'Go to store', completed: false }
]
}
})
</script>
<li v-for="task in tasks">
v-repeat was deprecated in 1.0:
https://github.com/vuejs/vue/issues/1200

Categories