How to populate pie chart by calling a function - html

Application used: angular 2
Plattform: Visual Studio Code.
I want to display a pie chart, having its values fixed from the beginning with the number of entries in 4 tables. The tables are given by the table types: firstlevel, secondlevel, critical, secondlevel100.
Now I don't want to just throw in the pieChartData some numbers, instead, I want to call the function populatePiechart() which populates the pie chart.
Sites I visited:
this is one of the links I visited, but it didn't help
the second link I visited, and also didn't help
cockpit.component.ts
// Pie
public pieChartType: string = 'pie';
public pieChartLabels: string[] = ['Anzahl FirstLevel-Tickets', 'Anzahl SecondLevel-Tickets', 'Anzahl SecondLevel-Tickets 100%', 'Anzahl Kritische-Tickets'];
public pieChartData: number[] = [ ]; //How do I call the function here??
private pieChartColors: any[] = [{ backgroundColor: ["rgba(35, 35, 255, 1)", "rgba(0, 0, 155, 1)", "rgb(138,43,226)", "rgba(199, 19, 62, 1)"] }];
populatePiechart(ticketType:string,number: number):number[]{
this.pieChartData[ticketType]=number;
let num:number[] = this.pieChartData;
this.pieChartData=num;
return this.pieChartData;
}
changeFirstLevel(number: number) { //EventListener-anzahl tickets tabelle
// console.log(this.pieChartData[0], number );
this.pieChartData[0] = number;
let num:number[] = this.pieChartData;
this.pieChartData=num;
}
changeSecondLevel(number: number) {
this.pieChartData[1] = number;
let num:number[] = this.pieChartData;
this.pieChartData=num;
}
changeSecondLevel100(number: number){
// this.pieChartData[2] = number;
this.pieChartData[2] = number;
let num:number[] = this.pieChartData;
this.pieChartData=num;
}
changeCritical(number: number) {
this.pieChartData[3] = number;
let num:number[] = this.pieChartData;
this.pieChartData=num;
}
cockpit.component.html:
<div class="row">
<div class="col-md-6 noPaddingRight"> <!-- TABELLEN TICKETS -->
<ticket-table ticketType="critical" (ticketChanger)="changeCritical($event)"></ticket-table> <!-- Wenn sich Anzahl Tickets im System ändert (Tabellen) ändert sich PieChart -->
<ticket-table ticketType="firstlevel" (ticketChanger)="changeFirstLevel($event)"></ticket-table>
</div>
<div class="col-md-6 noPaddingLeft">
<ticket-table ticketType="secondlevel" (ticketChanger)="changeSecondLevel($event)"></ticket-table>
<ticket-table ticketType="secondlevel100" (ticketChanger)="changeSecondLevel100($event)"></ticket-table> <!-- NICHT ÄNDERN, SLA in TABELLE nicht gewünscht -->
<!--populating piechart-->
<ticket-table ticketType="firstlevel" (ticketChanger)="populatePiechart(firstlevel,$event)"></ticket-table>
<ticket-table ticketType="secondlevel" (ticketChanger)="populatePiechart(secondlevel,$event)"></ticket-table>
<ticket-table ticketType="secondlevel100" (ticketChanger)="populatePiechart(secondlevel100,$event)"></ticket-table>
<ticket-table ticketType="critical" (ticketChanger)="populatePiechart(critical,$event)"></ticket-table>
</div>
ticket-table.component.ts:
cockpitList: ICockpit[];
collapsed: boolean = true;
progress: number;
cockpitUpdate: Date;
#Output() ticketChanger: EventEmitter<number> = new EventEmitter<number>(); //
panelColor: string;
#Input() ticketType: string; //
constructor(private _cockpitService: CockpitService,
private _toasterService: ToasterService) { moment.locale('de'); }
ngOnInit() {
this.refreshCockpitList();
setInterval(() => { this.refreshCockpitList(); }, 1000 * 60);
}
refreshCockpitList() {
this._cockpitService.getCockpits(this.ticketType).subscribe(data => { //BACKEND
this.cockpitList = data;
console.log(this.ticketType, this.cockpitList.length);
this.ticketChanger.emit(this.cockpitList.length);
console.log(this.ticketType, this.cockpitList.length);
this.cockpitUpdate = new Date();
});
}
By the way, I am new to angular and I am unsure of where do I get the number(since I am just doing adjustments to the app, I am not the developer) and where to call the function populatePiechart(...)

Related

Knockout Foreach creating duplicate items

On our UI, we have classrooms that are eligible for assessments. After creating and adding in eligibleclassrooms, I am getting duplicates of each classroom type. The expected output is one of each classroom.
Relavant HTML:
<div class="eligible-classrooms">
<h5 class="semi-bold btm-gap-sm">Eligible Classrooms</h5>
<div class="classrooms">
<!-- ko foreach: model.sortedEligibleClassrooms -->
<div class="classroom">
<span data-bind="text: $data.ageRangeTypeName"></span><span class="count" data-bind="text: $data.numClassrooms"></span>
</div>
<!-- /ko -->
</div>
</div>
Relevant Typescript:
Model:
numberOfEligibleClassrooms: KnockoutObservableArray<{ ageRangeTypeId: number, ageRangeTypeName: string, numClassrooms: number }>,
sortedEligibleClassrooms: KnockoutComputed<Array<{ ageRangeTypeId: number, ageRangeTypeName: string, numClassrooms: number }>>
self.model:
numberOfEligibleClassrooms: ko.observableArray([]),
sortedEligibleClassrooms: null,
constructor(orgCaseId: number, observationType: ObservationTypeModel, orgObservationSetTypeId: number) {
var self = this;
self.model.sortedEligibleClassrooms = ko.computed(function () {
return self.model.numberOfEligibleClassrooms().sort((left: { ageRangeTypeId: number, ageRangeTypeName: string, numClassrooms: number }, right: { ageRangeTypeId: number, ageRangeTypeName: string, numClassrooms: number }): number => {
return left.ageRangeTypeId > right.ageRangeTypeId ? 1 : -1;
});
}, self.model.numberOfEligibleClassrooms);
self.load = (): void => {
CommonFactory.AppSettings.get('OrgClassroomCollectMajorityAgeRange', function (setting: IApplicationSetting) {
const majorityAgeRangeEnabled = setting ? setting.value.toString().toLowerCase() === 'true' : false;
OrgFactory.ObservationTypeAgeRangeTypes.search({ "observationTypeId": self.model.observationType.id(), isCount: true }, function (ageRangeTypes) {
for (var j = 0; j < ageRangeTypes.length; j++) {
// The following function preserves the scope of the variables
(function (ageRangeTypeId, ageRangeTypeName) {
var minimumAgeRangeTypeId = self.settings.isERSObservation() ? ageRangeTypeId : null;
var search = {
minimumAgeRangeTypeId: minimumAgeRangeTypeId,
includesAgeRangeTypeId: majorityAgeRangeEnabled ? null : ageRangeTypeId,
majorityAgeRangeTypeId: majorityAgeRangeEnabled ? ageRangeTypeId : null,
isCount: true
};
OrgFactory.OrgCase.getEligibleObservationClassrooms(orgCaseId, search, function (data) {
self.model.numberOfEligibleClassrooms.push({ ageRangeTypeId: ageRangeTypeId, ageRangeTypeName: ageRangeTypeName, numClassrooms: data.length });
});
})(ageRangeTypes[j].ageRangeTypeId, ageRangeTypes[j].ageRangeTypeName);
}
});
});
}
Output:
What I did to fix this is create a distinctEligibleClassrooms method that distinctly sorts through the list of eligible classrooms:
//creates a distinct array of eligible classrooms.
self.model.distinctEligibleClassrooms = ko.computed(function () {
const classrooms = self.model.numberOfEligibleClassrooms();
const seen = {};
const distinctClassrooms = classrooms.filter(classroom => {
if (!seen[classroom.ageRangeTypeId]) {
seen[classroom.ageRangeTypeId] = true;
return true;
}
return false;
});
return distinctClassrooms;
}, self.model.numberOfEligibleClassrooms);
I added this directly under the current sortedEligibleClassrooms method and removed that because it will no longer be in use.

I'm trying to create a memory game where an expanding list of numbers is shown in ionic and angular and the user has to type in the answer

The way that I am doing it is that I want each of the numbers to appear then disappear. I have tried a lot of options but only the last number ends up showing when there are two or more numbers in the array. I suspect it has something to do with the for loop, but there does not seem to be a way around it.
Here is my typescript code for the generate numbers function:
generateNumbers() {
let numbersArray = new Promise<number[]>((resolve, reject) => {
let numberArray: number[] = []
for (let i = 0; i < this.level; i++) {
this.animationCtrl.create()
.addElement(this.currentNum.nativeElement)
.duration(500)
.iterations(1)
.fromTo('opacity', '1', '0.05').play()
.then(func => {
let randomnum = Math.floor(Math.random() * 9)
numberArray.push(randomnum)
this.currentIndex = i
this.currentNumber = randomnum
this.parsedCurrentNumber = JSON.parse(JSON.stringify(this.currentNumber))
}).then(func => {
this.animationCtrl.create()
.addElement(this.currentNum.nativeElement)
.duration(500)
.iterations(1)
.fromTo('opacity', '0.05', '1').play()
}).then(func => {
if (i === this.level - 1) {
resolve(numberArray)
}
})
}
})
return numbersArray
}
Here are my variable declarations and injections:
#ViewChild('currentNumber', { read: ElementRef, static: true}) currentNum: ElementRef;
level: number = 1;
levelExp: number = 1;
gameHasBegun = false;
paused = false;
numbersArray: number[] = [];
answer: string;
wrongcount: number = 0;
wrong = false;
lost = false;
currentIndex: number = 0
currentNumber: number;
parsedCurrentNumber: string;
constructor(
private router: Router,
private menu: MenuController,
private animationCtrl: AnimationController ) { }
Here is how I call my generate function:
this.generateNumbers().then(
(val) => this.numbersArray = val
)
Here is my HTML Code for the part where the numbers should be shown, but instead only one number is shown when I have two or more numbers in my array:
<ion-content #currentNumber>
<ion-label class="ion-text-center" >
<h1>{{ parsedCurrentNumber }}</h1>
</ion-label>
</ion-content>
Look at the following stackblitz.
https://stackblitz.com/edit/ionic-79e1rn
You basically need to loop through your array with a timeout.
ionViewDidEnter(){
this.runSeries(0);
}
runSeries(i){
if(i < this.nums.length){
setTimeout(() => {
this.lastNum = this.nums[i];
i++;
this.runSeries(i);
}, 1000)
}
}
and bind lastNum in your template.

HTML error when Passing data from Parent component to Child Component in Angular

In here i am passing data from parent to child and trying to draw a graph by using those data. This is my graph drawing method which is in child component createGraph(divName, chartDataInfo).In here i am trying to draw 2 charts.
export class ViewComponent implements OnInit{
lineChart = ['line_chart1', 'line_chart2', 'line_chart3'];
value = ['33.5M', '67.9M', '90.9M', '09.9M'];
names = ['Bookings', 'Modifications','cancellations', 'Revenue' ];
bookingInfo = [];
mdfInfo = [];
ngOnInit() {
this.getInfo();
this.getBookingInfo();
}
getBookingInfo() {
const params = [];
params.push({code: 'dateType', name: 'BOOKING'});
params.push({code: 'fromDate', name: '2019-01-01'});
params.push({code: 'toDate', name: '2019-12-31'});
this.ServiceHandler.getTxnInfo([], params).subscribe(
bookings => {
this.bookingInfo = bookings.responseObj.txnValues;
console.log(this.bookingInfo);
});
}
getInfo(){
const params = [];
params.push({code: 'fromDate', name: '2019-01-01'});
params.push({code: 'toDate', name: '2019-12-31'});
this.ServiceHandler.getMdfInfo([], params).subscribe(
modifications => {
this.mdfInfo = modifications.responseObj.txnValues;
this.modificationTtcSum = modifications.responseObj.ttcSum;
});
}
}
This is my dashboard.component.html
<app-chips [lineChart]="lineChart[0]" [value] = "value[0]" [name] = "names[0]" [mdfInfo] = "mdfInfo"></app-summary-chips>
<app-chips [lineChart]="lineChart[1]" [value] = "value[1]" [name] = "names[1]" [bookingInfo] = "bookingInfo"></app-summary-chips>
This my child component. Therefore i have called this.createGraph(this.lineChart, this.mdfInfo); 2 times inside ngOnChanges(changes: SimpleChanges).But when i do like that both charts are not coming.When i call this.createGraph(this.lineChart, this.mdfInfo) only once inside ngOnChanges(changes: SimpleChanges) and at the same time i use only <app-summary-chips> selector only once then one chart is drawing. What is the reason for it?
export class ChipsComponent implements OnInit {
#Input('lineChart') lineChart: string;
#Input('value') value: string;
#Input('name') name: string;
#Input() bookingInfo = [];
#Input() mdfInfo = [];
ngOnChanges(changes: SimpleChanges) {
console.log(this.bookingInfo);
console.log(this.mdfInfo );
this.createGraph(this.lineChart, this.mdfInfo);
this.createGraph(this.lineChart, this.bookingInfo);
}
createGraph(divName, chartDataInfo) {
am4core.useTheme(am4themesAnimated);
const chartNameChartTTV = am4core.create(divName, am4charts.XYChart);
chartNameChartTTV.width = am4core.percent(100);
chartNameChartTTV.height = am4core.percent(100);
console.log(this.bookingInfo);
chartNameChartTTV.padding(0, 0, 0, 0);
chartNameChartTTV.data = [];
for (let i = 0; i < chartDataInfo.length; i++) {
const booking = chartDataInfo[i];
console.log(booking);
chartNameChartTTV.data.push({date: booking.time, value: booking.ttc});
}
chartNameChartTTV.colors.list = [
am4core.color('rgba(4, 69, 142, 1)'),
];
// Create axes
const dateAxis = chartNameChartTTV.xAxes.push(new am4charts.DateAxis());
const valueAxis = chartNameChartTTV.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.grid.template.disabled = true;
valueAxis.renderer.labels.template.disabled = true;
dateAxis.renderer.grid.template.disabled = true;
dateAxis.renderer.labels.template.disabled = true;
// Create series
const series = chartNameChartTTV.series.push(new am4charts.LineSeries());
series.dataFields.valueY = 'value';
series.dataFields.dateX = 'date';
series.tooltipText = '{value';
series.fillOpacity = 1;
series.strokeWidth = 2;
series.minBulletDistance = 15;
}
}
This is my chips.component.html
<div class="l-content-wrapper c-summary-chip oh" >
<div class="c-summary-chip__value">{{value}}</div>
<div class="c-summary-chip__txt">{{name}}</div>
<div id= "{{lineChart}}" class="c-summary-chip__graph ">
</div>
</div>
Try wrapping your code inside an if check
createGraph(divName, chartDataInfo) {
if (divName && chartDataInfo.length) {}
}
As ngOnChanges is an async event there is no guarantee that when you call the function inside changes all parameters will be present.
Also for debugging give console.log like this.
createGraph(divName, chartDataInfo) {
console.log(divName, chartDataInfo);
if (divName && chartDataInfo) {}
}
That way you can confirm all required data is there when you call the function.
Inside ngOnChanges hook use SimpleChanges to track your input parameters.
If params present, then call your function.
ngOnChanges(changes: SimpleChanges): void {
if (changes['divName'] && changes['chartDataInfo']) {
this.createGraph(changes['divName'].currentValue, changes['chartDataInfo'].currentValue);
}
}
Take a look please https://dev.to/nickraphael/ngonchanges-best-practice-always-use-simplechanges-always-1feg

Random number is not refreshed on submit

I have a random number generator (for voucher numbers), but when I click the button, a new random number is not shown. Can anyone help please?
This is my controller that generates the random number:
static Random random = new Random();
public List<string> RandomVouchers()
{
int vouchersToGenerate = 1;
int lengthOfVoucher = 10;
List<string> generatedVouchers = new List<string>();
char[] keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890".ToCharArray();
while (generatedVouchers.Count < vouchersToGenerate)
{
string voucher = GenerateVoucher(keys, lengthOfVoucher);
if (!generatedVouchers.Contains(voucher))
{
generatedVouchers.Add(voucher);
return generatedVouchers;
}
}
return generatedVouchers;
}
private static string GenerateVoucher(char[] keys, int lengthOfVoucher)
{
return Enumerable
.Range(1, lengthOfVoucher) // for(i.. )
.Select(k => keys[random.Next(0, keys.Length - 1)]) // generate a new random char
.Aggregate("", (e, c) => e + c); // join into a string
}
This is the orders page :
<div id="vouchercode" style="display:none">
<ul>
#foreach (string strVouchers in ViewBag.Vouchers)
{
<li>#strVouchers</li>
}
</ul></div>
<button id="getvoucher">GenerateVoucher</button>
This is javascript code:
<script type="text/javascript">
$(function () {
$("#getvoucher").click(function () {
$("#vouchercode").dialog({
width: 460,
height: 200,
modal: true,
});
});
});

how to hide json panel on certain dates

Hi I'm beginner in ASP NET, I was asked to hide the "Registration Wizard" panel on 2 weeks before and after certain date. I believe we are using JSon to display panels. I'm not sure how can I achieving this as was unable to find anything.
module PrestigeWorldWide.Scripts.ViewModels {
export class IndexViewModel extends BaseViewModels.BaseViewModel {
public panels: KnockoutObservableArray<IPanelObject> = ko.observableArray<IPanelObject>();
public events: KnockoutObservableArray<FullCalendar.EventObject> = ko.observableArray<any>();
constructor() {
super();
this.panels.push({
Name: "My Transcript",
Desc: "View your unofficial QUB transcript",
Icon: "fa-file-text",
Link: "/PrestigeWorldwide/Grade/ViewTranscript"
});
this.panels.push({
Name: "Module Info",
Desc: "View the information on all modules including pre-requisites and course content",
Icon: "fa-folder-open",
Link: "/PrestigeWorldwide/Module/ModuleInfo"
});
this.panels.push({
Name: "Enrollment Wizard",
Desc: "Enroll for modules and enter further information about yourself - emergency contacts etc.",
Icon: "fa-magic",
Link: "/PrestigeWorldwide/Registration/Index"
});
this.getEvents();
}
getEvents() {
var url = "/PrestigeWorldwide/Class/GetStudentClasses";
this.loading(true);
$.ajax(url).done((events: FullCalendar.EventObject[]) => {
this.loading(false);
_.each(events, (event) => {
this.events.push(event);
});
});
}
}
export interface IPanelObject {
Name: string;
Desc: string;
Icon: string;
Link?: string;
}
}
Simply add a date check before adding the panel:
DateTime cutOffDateStart = new DateTime() // Insert 2 weeks before here
DateTime cutOffDateEnd = new DateTime() // Insert 2 weeks after here
if (DateTime.Now >= cutOffDateStart && DateTime.Now < cutOffDateEnd)
{
panels.Add(new Panel()
{
Name = "Registration Wizard",
Desc = "Use this tool to enrol for the new semester.",
Icon = "fa-pencil"
});
}