I have JSON Array with following structure
items: [
{
ID: 11,
UserID: "test.com",
UserRole: "user",
timeStamp: "2021-03-23T15:54:02.125578",
dialogs: [
{
"Bot": "Why is data missing?",
"test.com": "not available",
"Bot": "please enter ID",
"test.com": "1234"
}
]
}
]
I have to display elements inside dialogs as list. i am using v-for but dialogs is displaying as array with commas. how can i show this with index? Following is v-for loop i am using
<ul v-for="item in items" :key="item">
<li v-for="(dialog, index) in dialogs" :key="index">{{key}}: {{dialogs}}</li>
</ul>
<ul v-for="item in items" :key="item">
<li v-for="(dialog, index) in item.dialogs" :key="index">{{index}}: {{dialog}}</li>
</ul>
There are 2 changes required.
In your dialogs you have duplicate keys, so they need to separated out into two different objects.
In your HTML part you need to loop as items.dialogs
Here is the full code.
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
items: [
{
ID: 11,
UserID: "test.com",
UserRole: "user",
timeStamp: "2021-03-23T15:54:02.125578",
dialogs: [
{
"Bot": "Why is data missing?",
"test.com": "not available",
},
{"Bot": "please enter ID",
"test.com": "1234"
}
]
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul v-for="(item, index) in items" :key="item">
<li v-for = "(data, index) in item.dialogs">
{{data}} {{index}}</li>
</ul>
</div>
Related
I want to display nested list. The structure of the list:
[
{
name: "Level 1A",
children: [
{
name: "Level 2A",
children: [
]
},
{
name: "Level 2B",
children: [
{
name: "Level 3A",
children: [...]
}
]
}
]
},
{
name: "Level 1B",
children: [
{
name: "Level 2A"
children: [...]
}
]
}
]
As you can see we have items with 2 properties: name and children. It could be nestem many many levels down.
The HTML output should be something like this:
<list>
<list-grup name="Level 1A">
<list-item name="Level 2A"></list-item>
<list-item name="Level 2B"></list-item>
</list-grup>
<list-grup name="Level 1B">
<list-item name="Level 2A"></list-item>
</list-grup>
</list>
The only way i found is to display it like this:
<list>
<ng-container *ngFor="let item of list">
<list-group *ngIf="item.children" [item]="item.name">
<ng-container *ngFor="let item1 of item.children">
<list-group [item]="item1.name">
<list-group *ngIf="item1.children" [item]="item1.name">
<ng-container *ngFor="let item2 of item1.children">
...
</ng-container>
</list-group>
</list-group>
</ng-container>
</list-group>
</ng-container>
</list>
But this way is incorrect because I dont want it to be hardcoded because this data will be dynamic.
Can you help me find better solution to display this data? It could be done in template or component.
One possible way is to create a component which represents a single Node (name, children)
first the interface:
export interface Node {
name: string;
children: Node[];
}
component with one #Input() binding
export class NodeComponent implements OnInit {
#Input() node: Node;
html
<li>
<p>{{node.name}}</p>
<ul *ngFor="let item of node.children">
<app-node [node]="item"></app-node>
</ul>
</li>
begin the whole process from:
<ul>
<ng-container *ngFor="let item of list">
<app-node [node]="item"></app-node>
</ng-container>
</ul>
Working Stackblitz
Version with Expand/Collapse support
I am trying to create a web in vuejs that is multilanguage, so far the only idea that has occurred to me is to insert in an array the translations that will then be referenced in the html document using JSX. If someone has a more profitable idea and helps me implement it, I will be grateful.
HTML:
<template>
<div id="app">
<header>
<nav>
<div class="superior-nav">
<div class="langs">
<select name="language-selector" id="language-selector">
<option v-for="lang in langs" :value="lang.value">{{lang.name}}</option>
</select>
</div>
<div class="contacts">
<ul>
<li><i class="fab fa-facebook-f"></i></li>
<li><i class="fab fa-twitter"></i></li>
<li><i class="fab fa-instagram"></i></li>
<li><i class="fab fa-linkedin-in"></i></li>
</ul>
</div>
</div>
<div class="inferior-nav">
<nav class="nav">
<ul class="menu">
<li>Home</li>
<li>About</li>
<li>Services</li>
<li>Team</li>
<li>Careers</li>
</ul>
</nav>
</div>
</nav>
</header>
</div>
</template>
Script:
<script>
export default {
name: 'app',
data() {
return {
langs: [
{
id: 1,
name: "English",
value: "English"
},
{
id: 2,
name: "Español",
value: "Spanish",
},
{
id: 3,
name: "Français",
value: "French"
}
],
navItems: [
{
id: "en",
home: "Home",
about: "About",
services: "Services",
team: "Team",
careers: "Careers"
},
{
id: "es",
home: "Inicio",
about: "Sobre Nosotros",
services: "Servicios",
team: "Equipo",
careers: "Trabajos"
},
{
id: "fr",
home: "Accueil",
about: "À propos",
services: "Service",
team: "Équipe",
careers: "Carrières"
}
],
selectedLang: []
}
},
components: {
},
methods: {
changeLang(){
var id = this.selectedLang;
var option = document.getElementById("language-selector")[0].value;
if(option.value === "English"){
this.selectedLang[0] == navItems[0]
}
}
}
}
</script>
As you can see, I have a Select element with their respective values and names. So I need that when the value of the select is English, the content of the page is in English and so on with all languages.
As you can see, I have an array called navItems that stores in an object each element of the navigation list respectively.
What I try to do with the changeLang method is to save them all in a new array called selectedLang and then be called with JSX as mentioned above. Any idea how to do it?
Add v-model inside your select tag and whatever data will be selected it will automatically save to v-model. Remove this code
var option = document.getElementById("language-selector")[0].value; if(option.value === "English"){
this.selectedLang[0] == navItems[0]
}
and change it to this.
this.selectedLang = []
navItems.forEach(lang=>{
if(lang.id == this.languageSelected){
this.selectedLang.push(lang)
}
})
Add languageSelected = 'es' after the selectedLang:[] //so that english will be the default language that will be selected
Add languageSelected as v-model in select. <select v-model="languageSelected" name="language-selector" id="language-selector">
Change value of lang object same as the id of navItems
So I am using a JSON object that looks something like this:
data: [
{
title: "Post Title One",
categories: {
data: [
{
id: 1,
name: "Category Name 1"
}
]
}
},
{
title: "Post Title Two",
categories: {
data: [
{
id: 2,
name: "Category Name 1"
},
{
id: 3,
name: "Category Name 2"
}
]
}
}
]
and I want to grab all the categories for each post and display them using Vue. So what I have currently is:
<div v-for="post in posts">
<div>{{ post.categories.data }}</div>
</div>
In that {{ post.categories.data }} I am trying to display the category name from the JSON object. When I use what I have above the whole array is displayed in the div. When I try to do something like
{{ post.categories.data.name }}
or
{{ post.categories.data[0].name }}
I don't display the name of the category. I would really like to display the name of every category a post has, but can't seem to get it to display correctly.
EDIT: Also posts is the data property I am using in VueJS and am setting the JSON object to become that property.
You should use map method in conbination with destructuring.
<div v-for="post in posts">
<div>{{ post.categories.data.map(({name}) => name).join(' ') }}</div>
</div>
I am quite new to Vue and am attempting to retrieve a JSON response from an API and then print this on my page.
This is what I have so far:
<body>
<div id="mystats" class="container">
<h1>My Top Tracks</h1>
<ol>
<li v-for="track in tracks">#{{ track.name }}</li>
</ol>
<pre>#{{ tracks|json }}</pre>
<button v-on:click="fetchStats">Fetch stats</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.0.3/vue-resource.min.js"></script>
<script type="text/javascript">
$vue = new Vue({
el: '#mystats',
data: {
tracks: [],
},
methods: {
fetchStats: function()
{
this.$http.get('/mystatsdata', {params: {type: 'tracks'}}).then((response) => {
this.tracks.push(response.body);
console.log(this.tracks.name);
}, (response) => {
// error callback
});
}
}
})
</script>
</body>
Below is the response I am getting back:
[
[
{
"name": "Falling Away - Acoustic (Bonus Track)",
"track_number": 8,
"type": "track",
}
]
]
The issue is that the:
<ol>
<li v-for="track in tracks">#{{ track.name }}</li>
</ol>
is not printing out the track name.
There's no error in my console, and so being a little new to Javascript and Vue.js I'm not really sure where I am going wrong.
How do I get the name to display?
Edit
Here is the response with more than one entry (limited to 2 currently):
[
[
{
"name": "Falling Away - Acoustic (Bonus Track)",
"track_number": 8,
"type": "track",
},
{
"name": "Perfect Strangers",
"track_number": 1,
"type": "track",
}
]
]
The response that you are getting back is an array containing another array - which in turn contains the actual objects representing your tracks.
So inside: <li v-for="track in tracks">#{{ track.name }}</li> , the track refers to the inside array and not to each object.
For quick-fix, you can change your code to:
<li v-for="track in tracks[0]">#{{ track.name }}</li>
and try.
But the proper fix would be to fix the backend, to return the result as a single array of objects.
As #craig_h suggested it looks like you're receiving an array of array of objects instead of an array of objects.
I would recommand you to send a better formatted json like this:
[
{
"name": "Falling Away - Acoustic (Bonus Track)",
"track_number": 8,
"type": "track",
},
{
"name": "Falling Away2 - Acoustic (Bonus Track)",
"track_number": 9
"type": "track",
}
]
If you don't have access to the backend, using this.tracks.push(response.body[0]) in your fetchStats method should do the trick.
I'm trying to conditionally show and hide columns based on the data returned, if the data set contains any objects meeting conditions.
Here is a sample of the data returned from my search results
[
{
"id": "typeahead-241-1091-option-0",
"label": "Android Home Page",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-1",
"label": "Google",
"model": {
"type": "link",
}
},
{
"id": "typeahead-241-1091-option-2",
"label": "Forgotten Google Play Password",
"model": {
"type": "kb",
}
}
]
Now I'm presenting the data in columns, based on the type.
<div class="flexitem">
<h4>External Links</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'link'">{{match.label}}</div>
</div>
<div class="flexitem">
<h4>Knowledge Base</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'kb'">{{match.label}}</div>
</div>
<!-- the below has no results. I want it hidden altogether
currently it shows the <h4>Products</h4> with nothing below it-->
<div class="flexitem">
<h4>Products</h4>
<div ng-repeat="match in matches" ng-if="match.model.type == 'product'">{{match.label}}</div>
</div>
What I need to accomplish is putting conditions on the flexitem divs altogether to only show if there are results for that type. So if there are no results with the type == 'product', then don't even show that div. A ng-if on that row would work, but what will be the best way to cycle through all of the children of match to determine if there is a result? indexOf doesn't work through children arrays.
Put the logic on the angular side using Array.filter to separate arrays;
Angular controller:
$scope.linkMathches = $scope.matches.filter(function(m){
return m.model.type === 'link'
});
$scope.kbMathches = $scope.matches.filter(function(m){
return m.model.type === 'kb'
});
HTML:
<div class="flexitem" ng-if="linkMathches.length">
<h4>External Links</h4>
<div ng-repeat="match in linkMathches">
{{match.label}}
</div>
</div>
<div class="flexitem" ng-if="kbMathches.length">
<h4>Knowledge Base</h4>
<div ng-repeat="match in kbMathches">
{{match.label}}
</div>
</div>
Going further for dynamic values in model.type:
Angular controller:
$scope.typeMatches = {
link: {title: 'External Links', matches: []},
kb: {title: 'Knowledge Base', matches: []},
product: {title: 'Products', matches: []}
};
$scope.matches.forEach(function(match){
$scope.typeMatches[match.model.type].matches.push(match);
});
HTML:
<div class="flexitem"
ng-if="value.matches.length"
ng-repeat="(key,value) in typeMatches">
<h4>{{value.title}}</h4>
<div ng-repeat="match in value.matches">
{{match.label}}
</div>
</div>