Proper way to show array inside an array with v-for - arrays

I am trying to display the values of the text array/object but I am getting an output trying to show me paragraphs for every name inside the array/object.
Link to current result: current result
I am fairly new to vue.js so any tips are welcome!
<template>
<div class="education center">
<div v-if="object.timelines != null">
<template v-for="(time,index) in object.timelines">
<p :key="index">{{ time.schoolyear }}</p>
<div :key="index" v-bind="time" v-for="(text,index) in time.text">
<p :key="text">Degree: {{ text.degree }}</p>
<p>Institution: {{ text.institution }}</p>
<p>Where: {{text.where}}</p>
</div>
</template>
</div>
</div>
</template>
<script>
export default {
el: ".education",
data: function() {
return {
object: {
timelines: [
{
schoolyear: "2016 - 2017",
text: [
{ degree: "Applied Computer Science" },
{ institution: "Thomas More University of Applied Science" },
{ where: "Belgium, Geel" }
]
},
{
schoolyear: "2018 - 2019",
text: [
{ degree: "Business IT" },
{ institution: "HAMK University of Applied Science" },
{ where: "Finland, Hämeenlinna" }
]
}
]
}
};
}
};
</script>
I only want to show text.degree once for schoolyear="2016 - 2017"

It's not completely clear to me what you want, but maybe is it that you want to iterate through the .text array and, for each entry in the array, display both its key and its content. If so, you might try something like:
<p v-for="(entry, index) in time.text" :key="index">
{{Object.keys(entry)[0]}}: {{Object.values(entry)[0]}}
</p>
If you need to worry about title case for the keys, you could either use a computed property to convert the array, or define a method to convert each string.

First of all thanks to Boussadjra Brahim for providing the codepen wich resolved my issue.
I will first rephrase the question and then copy the solution.
The question: I want to print out values from an array inside a javascript object. In my <div>tag is is currently printing trying to print out text.institution for each element in the text array.
resulting in vue.js trying to show <p>Institution: {{ text.institution }}</p>
for degree, institution and where. Giving a browser output of:
<p>Degree:</p>
<p>Institution: Thomas More University of Applied Science"</p>
<p>Where:</p>
for text.where this would change to
<p>Degree:</p>
<p>Institution:</p>
<p>Where: Belgium, Geel</p>
The answer: Yet again a huge thanks to Boussadjra Brahim for showing the solution.
/* eslint-disable vue/require-v-for-key */
<template>
<div class="education center">
<div v-if="object.timelines != null">
<template v-for="(time,index) in object.timelines">
<p :key="index">{{ time.schoolyear }}</p>
<div :key="index" :set="text = time.text">
<p>Degree: {{ text.degree }}</p>
<p>Institution: {{ text.institution }}</p>
<p>Where: {{text.where}}</p>
</div>
</template>
</div>
</div>
</template>
<script>
export default {
el: ".education",
data(){
return {
object: {
timelines: [
{
schoolyear: "2016 - 2017",
text: {
degree: "Applied Computer Science",
institution: "Thomas More University of Applied Science",
where: "Belgium, Geel"
}
},
{
schoolyear: "2018 - 2019",
text: {
degree: "Business IT",
institution: "HAMK University of Applied Science",
where: "Finland, Hämeenlinna"
}
}
]
}
};
}
};
</script>
I changed the text array from square brackets to curly brackets and instead of using a v-for= I changed to a :set=.

Related

Trying to iterate an array of objects in angular

Problem: Trying to iterate an array of objects in angular but only appears the first one. The service works, I'm getting the full response.
The angular service where I execute a get for all the assets:
getAsset(asset_type):Observable<Asset[]>{
return this.http.get<Asset[]>(`${this.find}/${this.domain_id}/assets?asset_type=${asset_type}`, httpOptions);
}
The model of the Asset
export class Asset{
asset_name: string;
mac_address: string;
floor: number;
location: string;
temperature: number;
battery: number;
timestamp_tlm: string;
timestamp_geo: string;
}
The component.ts where i call the service and send the corresponding parameter.
ngOnInit() {
this.whereisService.getAsset(this.asset_type).subscribe(assets => {
if(Array.isArray(assets)){
this.assets = assets;
}
else if(typeof assets === 'string' ){
this.assets = [];
}
else{
this.assets = [assets];
}
});
}
}
The component.html
<div class="text-center">
<ul id="ticket" class="list-unstyled my-2">
<li class="btn w-100 bg-primary text-center text-white mx-0 my-2 display-block" *ngFor="let asset of rows_transformed let i = index">
<p class="h5"> Name: {{ asset?.asset_name }}</p>
<p class="h5"> Tipo: {{ asset?.asset_type }}</p>
<p class="h5"> Mac adress: {{ asset?.mac_address }} </p>
<p class="h5"> Piso: {{ asset?.floor }} </p>
<p class="h5"> Localização: {{ asset?.location }} </p>
<p class="h5"> Hora: {{ asset?.timestamp_tlm }} </p>
</li>
</ul>
</div>
Response JSON from API
{
"code": 200,
"data": [
{
"mac_address": "AC233F52BD17",
"floor": -3,
"asset_name": "Tripés microfone 1",
"asset_type": "Carro trasnporte",
"location": "Armazem 2",
"temperature": 22.0,
"battery": 74.0,
"timestamp_tlm": "2019-11-22 10:17:49.563121+00:00",
"timestamp_geo": "2019-11-22 10:17:49.563266+00:00"
},{...}
]
}
The JSON response doesn't match with what you expect. Start by simplifying your component. The service is supposed to return an Observable<Asset[]>. So the component shouldn't test to see if the emitted event is an array or a string. It's supposed to be an array of assets. If it's not, then the service should be fixed:
this.whereisService.getAsset(this.asset_type).subscribe(assets => this.assets = assets);
Then, you need to fix the service. What the server returns is not an array. It's an object with a data property, which is an array of assets. So the service should be
getAsset(asset_type): Observable<Asset[]>{
return this.http.get<{ data; Asset[]; }>(`${this.find}/${this.domain_id}/assets?asset_type=${asset_type}`, httpOptions).pipe(
map(object => object.data)
);
}
Since the methods allows getting an arra of assets, it should also be named getAssets(), not getAsset(). When one sees a method getAsset(), one expects to get back one asset, not an array of assets.
And finally, since the array is stred in the property assets and not rows_transformed, the template should iterate through that array:
*ngFor="let asset of assets; index as i"
Use
*ngFor="let asset of assets"
in your Html instead of rows_transformed. Also you can scrap i as you are not using it.

ng repeat in object with dynamic keys

I have a problem writing proper ng-repeat for this object. I would like to display all object properties. There is a main array of apps, each app can have a multiple versions and each version can have multiple users.
Here is object json.
"Awesome App 1": {
"1.16": {
"Steve": [
"steve#example.com",
null
],
"Mike": [
"mike#example.com",
null
]
}
},
"Awesome App 2": {
"1.7.0": {
"steve": [
"steve#example.com",
null
]
}
},
...
Problem is that keys are dynamic and I don`t know how to map it in ng-repeat. Thanks for a help.
You can try something like this:
https://plnkr.co/edit/3wMdzrtkpShLgl8mu9sN
$scope.data.json = {"Awesome App 1":
......
};
<ul>
<li ng-repeat="(key, val) in data.json">
App Name: {{key}} <br/>
<span ng-repeat="(key2, val2) in val">
Version: {{key2}} <br/>
<span ng-repeat="(key3, val3) in val2">
User: {{key3}} - {{val3[0]}} <br/>
</span>
</span>
</li>
</ul>

Angular using ng-repeat variable in nested ng-repeat

I have an ng-repeat which iterates over an array of values:
var englishList = ["abo", "ser", "vol", "con", "giv", "blo"];
$scope.englishList = englishList;
Is there a way to loop over these values in an ng-repeat and use the returned value as part of a nested ng-repeat?
<div ng-repeat="api in englishList">
<div ng-repeat="result in searchData.abo | filter:searchText">
<li>{{result.title}} {{result.shortname}}</li>
</div>
</div>
Ideally, I'd like this line to interpolate the each ng-repeat value from $scope.englishList:
<div ng-repeat="result in searchData.{{api}} | filter:searchText">
Is there a way to do this in angular?
You should be able to do something like this, surely:
<div ng-repeat='api in englishList'>
<div ng-repeat='item in searchData[api]'>
<!-- uses the value of 'api' as a key in 'searchData' -->
<!-- you do not need to use interpolation here as these are already expressions -->
</div>
</div>
I can't really give a complete example as your code is not exactly obvious in how you would want to use the nested type, but the above snippet should give you an idea of HOW to use nested repeats.
I would advise you use an object model like so
{ "api": {
"foo": [ "bar", "baz", "qux" ]
}}
Rather than having two different arrays. This should make it less brittle. Remember that your view's logic should ideally be as simple as possible and it shouldn't have to do much manipulation on the data given to it to work. I would say that iterating one array and then iterating another using the values of array 1 as keys of array 2 is maybe a bit too much for the view to do.
Just use the bracket notation to dynamically access a property :
<div ng-repeat="api in englishList">
<div ng-repeat="result in searchData[api] | filter: searchText" >
<li>{{result.title}}, {{result.shortname}}</li>
</div>
</div>
Snippet :
angular.module('demoApp', []).controller('DemoController', function ($scope) {
$scope.englishList = ["abo", "ser", "vol", "con"];;
$scope.searchData = {
abo: [{
title: 'title abo',
shortname: 'shortname abo'
}],
ser: [{
title: 'title ser 1',
shortname: 'shortname ser 1'
}, {
title: 'title ser 2',
shortname: 'shortname ser 2'
}],
vol: [{
title: 'title vol',
shortname: 'shortname vol'
}],
con: [{
title: 'title con',
shortname: 'shortname con'
}]
};
});
p {
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="DemoController">
<div>Search <input type="text" ng-model="searchText"/></div>
<div ng-repeat="api in englishList">
<p>{{api}}</p>
<div ng-repeat="result in searchData[api] | filter: searchText" >
<li>{{result.title}}, {{result.shortname}}</li>
</div>
</div>
</div>

How to iterate over inner object's properties in an AngularJS template?

I'm in the process of learning AngularJS. I would like to print out a list of objects and iterate over one of the object's inner object's properties. This looked like a standard procedure of using nested loops, however, it doesn't appear to be so simple.
My Controller is setup below. Essentially, it is a list of random vehicles.
var vehicleApp = angular.module("vehicleApp", []);
vehicleApp.controller('VehicleController', function ($scope) {
$scope.vehicles = [{
id: 0,
name: "car",
parts: {
wheels: 4,
doors: 4
}
}, {
id: 1,
name: "plane",
parts: {
wings: 2,
doors: 2
}
}, {
id: 2,
name: "boat",
parts: {
doors: 1
}
}];
});
I'd like to output the vehicles as such:
car
- wheels (4)
- doors (2)
plane
- wings (2)
- doors (2)
boat
- doors (1)
My template that I used was setup as such:
<div ng-app="vehicleApp" ng-controller="VehicleController">
<p ng-repeat="vehicle in vehicles">
{{ vehicle.name }}
</p>
<ul>
<li ng-repeat="(attribute, value) in vehicle.parts">
{{attribute}} ({{value}})
</li>
</ul>
</div>
This produces a list of the vehicles, but not the sub lists of the parts inner object.
Interestingly, enough, when I use {{ vehicle.parts }} it returns a JSON string of the parts inner object. Does AngularJS treat it as a string and hence, it is unable to print out the properties of the parts object?
You didn't enclose the second ngRepeat in the first one:
<div ng-app="vehicleApp" ng-controller="VehicleController">
<p ng-repeat="vehicle in vehicles">
{{ vehicle.name }}
<ul>
<li ng-repeat="(attribute, value) in vehicle.parts">
{{attribute}} ({{value}})
</li>
</ul>
</p>
</div>

Dependant ng-repeat in AngularJS

I have a following data structure coming from REST:
scope.taglist =
[ { name: "mylist", tags: ["tag1", "tag2", "tag3", ...]}, { name:
"mylist2", tags: ["tag2.1", "tag2.2", "tag2.3", ...]} ]
In order to present the names of the objects I have the following html:
<div>
<select ng-model="tagNameSelection">
<option ng-repeat="tagObj in taglist" value="{{tagObj}}">{{tagObj.name}}</option>
</select>
</div>
<div class="tagdetails">
<!-- present the list of tags from tagNameSelection -->
</div>
Now I am a little bit of a loss on how to present the tags list of
individual object. I am able to present the array in raw format (by
sticking {{tagNameSelection}} inside the tagdetails div) but when I
try to iterate through those with ng-repeat angular gives a error
message.
Oddly enough when I hard-code one of the tag lists to the scope in controller the ng-repeat works flawlessly.
Maybe you interesting something like this:
HTML
<div ng-controller="fessCntrl">
<div>
<select ng-model="tagNameSelection"
ng-options="tagObj as tagObj.name for tagObj in taglist"
ng-change="change(tagNameSelection)"></select>
</div>
<pre>{{tagNameSelection.tags|json}}</pre>
<div class="tagdetails">
<ul ng-repeat="tag in tagNameSelection.tags">
<li>{{tag}}</li>
</ul>
</div>
</div>
Controller
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.change = function (value) {
};
$scope.taglist = [{
name: "mylist",
tags: ["tag1", "tag2", "tag3"]
}, {
name: "mylist2",
tags: ["tag2.1", "tag2.2", "tag2.3"]
}]
});
fessmodule.$inject = ['$scope'];
See Fiddle

Resources