typescript - 在 Angular 中将搜索栏的数据调用到 chart.js 图表
我想在 Angular 9 中创建一个 chart.js 的条形图。用户应该在搜索栏中输入一个字符串,这会在一个 .json 文件中查找相应的条目,并将其属性显示在条形图中。例如,你可以输入“甜椒”,它会显示一个图表,其中一个条形名为“甜”,高度为 3,另一个条形名为“酸”,高度为 1。搜索组件可以工作,我可以输入名字并以文本形式返回值。然而,我无法让它返回一个正确的图表。
如果这个问题对你们来说很基础,我很抱歉,我只是一个正在学习编程的业余爱好者。我到处查找这个问题,但找不到这个问题或者任何解决方法。
这是 home-page.component.ts:
import { Component, OnInit } from '@angular/core';
import { DataService } from '../../data.service';
import { Post } from '../../post';
import { Chart } from 'chart.js';
@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
post: Post[]
constructor(
public dataService: DataService
) { }
ngOnInit() {
this.dataService.getPosts().subscribe(posts => {
this.post = posts
this.dataService.postsData = posts
});
}
onSelectedFilter(e) {
this.getFilteredExpenseList();
let postname = this.post.name;
let postsour = this.post.sour;
let postsweet = this.post.sweet;
this.chart = new Chart('canvas', {
type: 'bar',
data: {
labels: postname,
datasets: [
{
data: postsour,
borderColor: "#3cba9f",
fill: false
},
{
data: postsweet,
borderColor: "#ffcc00",
fill: false
},
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}],
}
}
});
}
getFilteredExpenseList() {
if (this.dataService.searchOption.length > 0)
this.post = this.dataService.filteredListOptions();
else {
this.post = this.dataService.filteredListOptions();
}
}
}
这是 search-bar.component.ts:
import { Component, OnInit, ViewChild, ElementRef, EventEmitter, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { DataService } from '../../data.service';
import { Post } from '../../post';
@Component({
selector: 'app-search-bar',
templateUrl: './search-bar.component.html',
styleUrls: ['./search-bar.component.css']
})
export class SearchBarComponent implements OnInit {
myControl = new FormControl();
filteredOptions: Observable<string[]>;
allPosts: Post[];
autoCompleteList: any[]
@ViewChild('autocompleteInput') autocompleteInput: ElementRef;
@Output() onSelectedOption = new EventEmitter();
constructor(
public dataService: DataService
) { }
ngOnInit() {
// get all the post
this.dataService.getPosts().subscribe(posts => {
this.allPosts = posts
});
// when user types something in input, the value changes will come through this
this.myControl.valueChanges.subscribe(userInput => {
this.autoCompleteExpenseList(userInput);
})
}
private autoCompleteExpenseList(input) {
let categoryList = this.filterCategoryList(input)
this.autoCompleteList = categoryList;
}
// this is where filtering the data happens according to you typed value
filterCategoryList(val) {
var categoryList = []
if (typeof val != "string") {
return [];
}
if (val === '' || val === null) {
return [];
}
return val ? this.allPosts.filter(s => s.name.toLowerCase().indexOf(val.toLowerCase()) != -1)
: this.allPosts;
}
// after you clicked an autosuggest option, this function will show the field you want to show in input
displayFn(post: Post) {
let k = post ? post.name : post;
return k;
}
filterPostList(event) {
var posts = event.source.value;
if (!posts) {
this.dataService.searchOption = []
}
else {
this.dataService.searchOption.push(posts);
this.onSelectedOption.emit(this.dataService.searchOption)
}
this.focusOnPlaceInput();
}
removeOption(option) {
let index = this.dataService.searchOption.indexOf(option);
if (index >= 0)
this.dataService.searchOption.splice(index, 1);
this.focusOnPlaceInput();
this.onSelectedOption.emit(this.dataService.searchOption)
}
// focus the input field and remove any unwanted text.
focusOnPlaceInput() {
this.autocompleteInput.nativeElement.focus();
this.autocompleteInput.nativeElement.value = '';
}
}
这是所引用的 post.ts:
export interface Post {
name: string,
type: string,
sweet: number,
sour: number,
salty: number,
bitter: number,
fatty: number,
umami: number,
spicy: number,
}
这是 .json 文件的一个示例:
[
{
"name": "bell pepper",
"type": "vegetable",
"sweet": 3,
"sour": 1,
"salty": 1,
"bitter": 2,
"fatty": 0,
"umami": 0,
"spicy": 2
},
{
"name": "salt",
"type": "spice",
"sweet": 0,
"sour": 0,
"salty": 10,
"bitter": 0,
"fatty": 0,
"umami": 0,
"spicy": 0
},
{
"name": "beef",
"type": "meat",
"sweet": 1,
"sour": 0,
"salty": 2,
"bitter": 0,
"fatty": 4,
"umami": 5,
"spicy": 0
},
{
"name": "Apple",
"type": "fruit",
"sweet": 6,
"sour": 3,
"salty": 0,
"bitter": 0,
"fatty": 0,
"umami": 0,
"spicy": 0
}
]
这里是数据服务:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Post } from './post';
@Injectable({
providedIn: 'root'
})
export class DataService {
searchOption = []
public postsData: Post[]
postUrl: string = "../assets/posts.json";
constructor(
private http: HttpClient
) { }
getPosts(): Observable<Post[]> {
return this.http.get<Post[]>("../assets/flavors.json");
}
filteredListOptions() {
let posts = this.postsData;
let filteredPostsList = [];
for (let post of posts) {
for (let options of this.searchOption) {
if (options.name === post.name) {
filteredPostsList.push(post);
}
}
}
console.log(filteredPostsList);
return filteredPostsList;
}
}
再次感谢你在这里的帮助。这是我第一次使用 Angular,我真的已经快要绝望了。谢谢你!
答案#1
在主页组件中,this.post指的是一个对象数组。要从对象数组生成新数组,请使用map()。尝试以下方法
home-page.component.ts:
let postname = this.post.map(p => p.name);
let postsour = this.post.map(p => p.sour);
let postsweet = this.post.map(p => p.sweet);
工作示例:游乐场
我在这里为你的代码创建了一个简陋的 Stackblitz。当然,由于我无法访问组件模板,我已将图表生成绑定到一个按钮元素上。你可以随意根据你的需求修改它。
