How to collect nested data in Vue.js without duplicates? - arrays

A second question about my project "Avatar database". I want to collect all tags from all avatars into one array. Of course the list should not contain duplicates.
For example, I have 3 avatars with the tag "red" and in the array "allTags" - "red" is displayed only once.
Data structure
data() {
return {
avatars: [
{
name: "Butterfly Blue",
tags: ["animal", "butterfly", "blue"]
},
{
name: "Butterfly Green",
tags: ["animal", "butterfly", "green"]
},
{
name: "Deer Shining",
tags: ["animal", "deer"]
}
]
}
}
I'm trying to get those tags using a computed property:
allTags() {
var result = [];
for (var avatar in this.avatars) {
for (var tag in avatar.tags) {
if (!tag in result) {
result += tag
}
}
}
return result
}
But... The only output I can see is: [] - an empty array.
I want the computed property allTags to return an array ([]) of all tags from all avatars.
Using the example data above {{ allTags }} should be:
[ "animal", "butterfly", "blue", "green", "deer" ]

You should use !result.includes(tag) instead of !tag in result, and result.push(tag) instead of result += tag:
allTags() {
var result = [];
for (let avatar of this.avatars) {
for (let tag of avatar.tags) {
if (!result.includes(tag)) {
result.push(tag)
}
}
}
return result
}
Also, I have replaced the use of for..in with for..of, this is the recommended construct.
See demo:
new Vue({
el: '#app',
data() {
return {
avatars: [{
name: "Butterfly Blue",
tags: ["animal", "butterfly", "blue"]
},
{
name: "Butterfly Green",
tags: ["animal", "butterfly", "green"]
},
{
name: "Deer Shining",
tags: ["animal", "deer"]
}
]
}
},
computed: {
allTags() {
var result = [];
for (let avatar of this.avatars) {
for (let tag of avatar.tags) {
if (!result.includes(tag)) {
result.push(tag)
}
}
}
return result
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<div id="app">
<h4>Avatars:</h4>
<p>{{ avatars }}</p>
<hr>
<h4>allTags:</h4>
<p>{{ allTags }}</p>
</div>

Related

Data from 2 arrays

So i have two arrays:
1:
"movies":
{
"id": "123bb",
"category": "3345",
"content": "Sinister"
}
Second:
"categories":
{
"id": "3345",
"code": "Movie",
"name": "Horror"
},
I also have random movie:
TS:
loadData() {
this.PagesService.loadData().subscribe(response => {
console.log(response)
this.movies = response
this.movies[Math.floor(Math.random() * this.movies.length)];
this.randomValue = this.movies[Math.floor(Math.random() * this.movies.length)];
return this.randomValue
})
console.log(this.randomValue)
};
HTML:
<p>{{ this.randomValue.content }}</p>
So if I have something like this:
<p>{{ this.randomValue.category }}</p>
There is "3345" as category but I would like to have "name" from this second array but I am not sure how to do that
My recommendation:
store the data as observable
map the data in observable pipe (maybe use combineLatest to combine movies and categories data)
use the async pipe in template
use an own structural directive to pick the datas random element
Here is how it could look like...
The directive
import { Directive, Input, TemplateRef, ViewContainerRef } from '#angular/core';
interface RandomContext<T> {
appRandom: T[];
$implicit?: T;
}
#Directive({
standalone: true,
selector: '[appRandom]',
})
export class RandomDirective<T> {
private context: RandomContext<T> = {
appRandom: [],
$implicit: undefined,
};
#Input()
set appRandom(elements: T[]) {
this.context.appRandom = elements;
this.pickNewElement();
}
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {
this.viewContainer.createEmbeddedView(this.templateRef, this.context);
}
private pickNewElement(): void {
this.context.$implicit =
this.context.appRandom[
Math.floor(Math.random() * this.context.appRandom.length)
];
}
}
And your template:
<p *appRandom="movies$ | async; let randomMovie">
{{ randomMovie.category }}
</p>
And your component:
movies$: Observable<ExtendedMovie[]>;
ngOnInit() {
this.movies$ = combineLatest([
this.PagesService.loadData(),
this.CategoriesService.loadCategories(),
]).pipe(
map(([movies, categories]) => {
return /*map movies array to extend it with your required data from categories array*/;
}),
);
}

ES6 : Create objects in a given format from array of key values

var result = {445: "L005.0", 455: "L006.0", 456: "L007.0", 457: "L008.0", 458: "L009.0", 459: "L027.0", 467: "L005.7", 580: "L001.0", 581: "L002.0", 587: "L003.0"};
From this "result", I want to output an object like this
{
"445": {
name: result[445],
icon: "fa-search"
},
"455": {
name: result[455],
icon: "fa-search"
},
"456": { ... },
"457": { ... },
...
...
}
So you need to iterate over keys to construct new object o;
let res={}; //initializing
for(let i of Object.keys(result))
{
res[i]={
"name": result[i],
"icon":"fa-seach"
}
}
console.log(res) //to test

How to mapping variable data for pie chart (react.js)

I want make pie chart using state value in react with '#toast-ui/react-chart'.
I tried this and that after looking at the examples, but it's hard to me.
This is a example.
//chart data
var data = {
categories: ['June, 2015'],
series: [
{
name: 'Budget',
data: [5000]
},
{
name: 'Income',
data: [8000]
},
{
name: 'Expenses',
data: [4000]
},
{
name: 'Debt',
data: [6000]
}
]
};
var options = {
chart: {
width: 660,
height: 560,
title: 'Today's Channel & Value.'
}
tooltip: {
suffix: 'value'
}
},
};
var theme = {
series: {
colors: [
'#83b14e', '#458a3f', '#295ba0', '#2a4175', '#289399',
'#289399', '#617178', '#8a9a9a', '#516f7d', '#dddddd'
]
}
};
//render part
render()
{
return(
<div>
<PieChart
data={data}
options={options}
/>
</div>
}
and document is here.
https://github.com/nhn/toast-ui.react-chart#props
https://nhn.github.io/tui.chart/latest/tutorial-example07-01-pie-chart-basic
What's in the document is how to make a chart with a fixed number, but I want to change it using the state.
So, How can I mapping series data like this and how to add data length flexible?
I have list of object like ...
this.state.list =[{"channel_name":"A","channel_number":17,"VALUE":3,"num":1},
{"channel_name":"B","channel_number":23,"VALUE":1,"num":2},
{"channel_name":"C","channel_number":20,"VALUE":1,"num":3},
{"channel_name":"D","channel_number":1,"VALUE":1,"num":4}]
The length of the list is between 1 and 7 depending on the results of the query.
I want to do like this.
series:[
{
name: this.state.list[0].channel_name+this.state.list[0].channel_num
data: this.state.list[0].VALUE
},
{
name: this.state.list[1].channel_name+this.state.list[1].channel_num
data: this.state.list[1].VALUE
},
{
name: this.state.list[2].channel_name+this.state.list[2].channel_num
data: this.state.list[2].VALUE
},
{
name: this.state.list[3].channel_name+this.state.list[3].channel_num
data: this.state.list[3].VALUE
}
]
How can I implement it however I want?
Since this.state.list is a list of objects, so you can simply use map method to loop through each object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map. Then create new object with custom value.
let new_series = [];
this.state.list.map((obj) => {
let info = {
name: obj.channel_name + obj.channel_number, //from your code
data: obj.VALUE //from your code
}
new_series.push(info)
});
Then assign new list to your chart.
//chart data
var data = {
categories: ['June, 2015'],
series: new_series
]
};

Extracting some values from JSON objects in AngularJS

I have a JSON text (posted below) and I want to extract name and channel_remote_number from each of its object inside its item array. Can someone please guide how can I do that?
JSON Text:
{
"xml":{
"version":"3.0.0",
"item_startidx":"0",
"total_items":"471",
"items_link":"https://example_url/",
"items":{
"item":[
{
"id":"36438",
"name":"A plus",
"type":"liveWMV",
"link":"https://example_url/",
"duration":"35000",
"channel_logo":{
"#cdata":"http://example_url/"
},
"channel_remote_number":"180",
"description":"A plus",
"response_link":"https://example_url/",
"restrict_link":"https://example_url/",
"play_time":"https://example_url/",
"protected":"no",
"program_listing":"https://example_url/",
"program_guide":"https://example_url/",
"electronic_program_guide":"https://example_url/",
"catchup_tv":"7",
"popup":{
"type":"blocking",
"message":"Temporary Down",
"buttons":{
"button":{
"type":"cancel",
"text":"OK"
}
}
},
"category_id":"12797",
"path":"Smart TV App>Live TV>Pakistani>Entertainment"
},
{
"id":"37669",
"name":"A plus",
"type":"liveWMV",
"link":"https://example_url/",
"duration":"35000",
"channel_logo":{
"#cdata":"http://example_url/"
},
"channel_remote_number":"180",
"description":"A plus",
"response_link":"https://example_url/",
"restrict_link":"https://example_url/",
"play_time":"https://example_url/",
"protected":"no",
"program_listing":"https://example_url/",
"program_guide":"https://example_url/",
"electronic_program_guide":"https://example_url/",
"catchup_tv":"7",
"popup":{
"type":"blocking",
"message":"Temporary Down",
"buttons":{
"button":{
"type":"cancel",
"text":"OK"
}
}
},
"category_id":"12797",
"path":"Smart TV App>Live TV>Pakistani>Entertainment"
}
]
}
}
}
var data = {
"xml": {....
var answer = data.xml.items.item
.map(x => ({ name: x.name, channel_remote_number: x.channel_remote_number }));

Group by on a complex object in AngularJS

I've an array that contains assignments of employees on tasks, it looks like something like this:
$scope.assignments = [
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Kill everyone", project:"Destruction"
},
date: {
day:"01/01", year:"1985"
}
},
{
employee: {
id:"2", firstname:"Luke", lastname:"Skywalker"
},
task: {
name:"Find daddy", project:"Star Wars"
},
date: {
day:"65/45", year:"1000000"
}
},
{
employee: {
id:"1", firstname:"John", lastname:"Rambo"
},
task: {
name:"Save the world", project:"Destruction"
},
date: {
day:"02/01", year:"1985"
}
}
];
I would like to group by employee, for having something like this:
$scope.assignmentsByEmployee = [
{ //First item
id:"1",
firstname:"John",
lastname:"Rambo",
missions: [
{
name:"Kill everyone",
date:"01/01",
year:"1985"
},
{
name:"Save the world",
date:"02/01",
year:"1985"
}
]
},
{ //Second item
id="2",
firstname:"Luke",
lastname:"Skywalker",
missions: [
name:"Find daddy",
date:"65/45",
year:"1000000"
]
}
];
Is their a simple way to do this ? I tried something with a double forEach, but it leads me nowhere.
Hope I'm understandable :)
Thanks !
You should just be able to loop through the assignments array and create a 'keyed array' (which just means using an object in JavaScript) on employee ID. Then you just fill up the missions array as required.
Something like
// initialise a holding object
var assignmentsByEmployee = {};
// loop through all assignemnts
for(var i = 0; i < $scope.assignments.length; i++) {
// grab current assignment
var currentAssignment = $scope.assignments[i];
// grab current id
var currentId = currentAssignment.employee.id;
// check if we have seen this employee before
if(assignmentsByEmployee[currentId] === undefined) {
// we haven't, so add a new object to the array
assignmentsByEmployee[currentId] = {
id: currentId,
firstname: currentAssignment.employee.firstname,
lastname: currentAssignment.employee.lastname,
missions: []
};
}
// we know the employee exists at this point, so simply add the mission details
assignmentsByEmployee[currentId].missions.push({
name: currentAssignment.task.name,
date: currentAssignment.date.day,
year: currentAssignment.date.year
});
}
These leaves assignmentsByEmployee as an object, but you can simply foreach through it and convert it back to an array if required. E.g:
$scope.assignmentsByEmployee = [];
for(var employeeId in assignmentsByEmployee) {
$scope.assignmentsByEmployee.push(assignmentsByEmployee[employeeId]);
}

Resources