How does parse Int subtraction work in JS (Ionic 5 + Angular)? - javascript

I am working on a point-based question game within Ionic 5 using Angular. I asked previously on how to make the addition button work as intended, and it worked great, but now when trying to use the same methods for point subtraction, I get a "Nan" box.
I have tried to rework my GUI to see if the problem is on that side, but nothing changed.
I am a super beginner at Ionic and HTML in general so my code will probably be pretty garbage. Any help would be great!
Below is the code before any of my modifications.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Point Game</title>
<script type="module" src="https://cdn.jsdelivr.net/npm/#ionic/core#4.7.4/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/#ionic/core#4.7.4/dist/ionic/ionic.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#ionic/core#4.7.4/css/ionic.bundle.css"/>
<style>
:root {
--ion-safe-area-top: 20px;
--ion-safe-area-bottom: 22px;
}
</style>
<script>
function openMenu() {
document.querySelector('ion-menu-controller').open();
}
function p1point(){
var p1pp = document.getElementById("p1p").innerText; //getting text inside element
p1pp = parseInt(p1pp) + 1; //Increment
document.getElementById("p1p").innerHTML = p1pp; // Writing values
}
function p2point(){
var p2pp = document.getElementById("p2p").innerText; //getting text inside element
p2pp = parseInt(p2pp) + 1; //Increment
document.getElementById("p2p").innerHTML = p2pp; // Writing values
}
function p1minus(){
var p1mm = document.getElementById("p1min").innerText; //getting text inside element
p1mm = parseInt(p1mm) - 1; //Increment
document.getElementById("p1min").innerHTML = p1mm; // Writing values
}
function p2minus(){
var p2mm = document.getElementById("p2min").innerText; //getting text inside element
p2mm = parseInt(p2mm) - 1; //Increment
document.getElementById("p2min").innerHTML = p2mm; // Writing values
}
</script>
</head>
<body>
<ion-app>
<ion-menu side="start">
<ion-header>
<ion-toolbar translucent>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<ion-icon name="home" slot="start"></ion-icon>
<ion-label>Home</ion-label>
</ion-item>
<ion-item>
<ion-icon name="person" slot="start"></ion-icon>
<ion-label>Profile</ion-label>
</ion-item>
<ion-item>
<ion-icon name="chatbubbles" slot="start"></ion-icon>
<ion-label>Messages</ion-label>
</ion-item>
<ion-item>
<ion-icon name="settings" slot="start"></ion-icon>
<ion-label>Settings</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ion-menu>
<div class="ion-page" main>
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Point Game</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-grid>
<ion-row>
<ion-col>
<ion-card>
<!--Player 1 score-->
<ion-card-header>
<ion-card-subtitle class = "ion-text-center">Player 1</ion-card-subtitle>
<ion-card-title class = "ion-text-center" id = "p1p">0</ion-card-title>
</ion-card-header>
</ion-card>
</ion-col>
<ion-col size = -1>
<!-- fake inner thing psuedo-col-->
</ion-col>
<ion-col>
<ion-card>
<!--Player 2 score-->
<ion-card-header>
<ion-card-subtitle class = "ion-text-center">Player 2</ion-card-subtitle>
<ion-card-title class = "ion-text-center" id = "p2p">0</ion-card-title>
</ion-card-header>
</ion-card>
</ion-col>
</ion-row>
<ion-row>
<ion-col width-50 style = "text-align: right">
<ion-button id = "p1plus" onclick="p1point()" > + </ion-button>
</ion-col>
<ion-col size = .15>
<!-- fake inner thing psuedo-col-->
</ion-col>
<ion-col width-50 style = "text-align: right">
<ion-button id = "p2plus" onclick="p2point()"> + </ion-button>
</ion-col>
<ion-col size = -3>
<!-- fake inner thing psuedo-col-->
</ion-col>
</ion-row>
</ion-row>
<ion-row>
<ion-col width-50 style = "text-align: right">
<ion-button id = "p1min" onclick="p1minus()" > - </ion-button>
</ion-col>
<ion-col size = .15>
<!-- fake inner thing psuedo-col-->
</ion-col>
<ion-col width-50 style = "text-align: right">
<ion-button id = "p2min" onclick="p2minus()"> - </ion-button>
</ion-col>
<ion-col size = -3>
<!-- fake inner thing psuedo-col-->
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
</div>
</ion-app>
<ion-menu-controller></ion-menu-controller>
</body>
</html>

I think the problem of your minus functions is that you are getting the innerText of the buttons. You are using p1min and p2min ids, and those texts are not numbers. That is why you are getting NaN.

Related

How to disable a button depending on the length of a list

I want that the user can choose only one tag. So the button should be disabled after the user has pushed one tag to the list. So I made up the idea that if the list.length is bigger than 0, the button should be disabled. But somehow it doesn't work in my approach.
page.html
<ion-item>
<ion-input mode="md" formControlName="category" clearInput="true" placeholder="Tag" name="tagValue"></ion-input>
<ion-button [disabled]="!categoryForm.valid" [disabled]="tagList?.length > 1" item-right type="submit" icon-only>
<ion-icon name="checkmark"></ion-icon>
</ion-button>
</ion-item>
page.ts
public tagInput: string = '';
public tagList: any[] = [];
constructor() {}
...
addTag() { // properly access and reset reactive form values
const tagCtrl = this.categoryForm.get('category');
if (tagCtrl.value) {
this.tagList.push(tagCtrl.value);
this.tagInput = ''; // in order to have an empty input
}
}
You're using disable attribute twice:
<ion-item>
<ion-input mode="md" formControlName="category" clearInput="true" placeholder="Tag" name="tagValue"></ion-input>
<ion-button [disabled]="!categoryForm.valid || tagList?.length > 0" item-right type="submit" icon-only>
<ion-icon name="checkmark"></ion-icon>
</ion-button>
</ion-item>

Store input value in array with ionic angular 5

I have this in my html side :
<ion-grid style="margin-bottom: 25px;">
<ion-row padding>
<ion-col col-11>
<label class="bold">Title</label>
<ion-input type="text" class="bordered" placeholder="Enter Title" [(ngModel)]="data.title"></ion-input>
</ion-col>
</ion-row>
<ion-row padding>
<ion-col col-11 class="pharagraph margin-bottom">
<label class="bold">Pharagraph</label>
<ion-textarea rows="10" class="bordered" placeholder="Enter Content Paragraph" [(ngModel)]="data.paragraph"></ion-textarea>
</ion-col>
</ion-row>
<ion-row padding *ngFor="let input of inputs; let i=index">
<ion-col col-11 class="pharagraph margin-bottom">
<ion-textarea rows="10" class="bordered" placeholder="Enter Content Paragraph" [(ngModel)]="data.paragraph[i]"></ion-textarea>
</ion-col>
<ion-col col-1>
<button ion-button clear icon-start icon-right (click)="delParagraph(i)"><ion-icon name="trash" color="danger"></ion-icon></button>
</ion-col>
</ion-row>
<ion-row padding>
<ion-col col-11>
<button ion-button block color="danger" id="addPharagraph" (click)="addParagraph()"><ion-icon name="add-circle"></ion-icon> add pharagraph</button>
</ion-col>
</ion-row>
</ion-grid>
<div class="tab" style="position: fixed; bottom: 0;">
<a class="tab-item" (click)="save()">Save Draft</a>
</div>
As you can see here, there is an input for a paragraph by default and user can choose to add another paragraph as many as they want.
Here is my TypeScript :
data:any = {};
constructor(public navCtrl: NavController, public navParams: NavParams, public http: Http) {
this.data.title = '';
this.data.paragraph = '';
}
addParagraph(){
this.inputs.splice(0,0,this.inputs.length+1);
}
delParagraph(paragraphID){
this.inputs.splice(this.inputs.indexOf(paragraphID), 1);
}
save(){
var testData = JSON.stringify(this.data);
console.log(testData);
}
With those code, I can only display the data in 1 dimension like this :
{
"title":"testing title",
"paragraph":"testing paragraph 1"
}
But I wanted it to be displayed in this form :
{
"title":"testing title",
"paragraph":[
{"paragraph": "testing paragraph 1"},
{"paragraph": "testing paragraph 2"},
{"paragraph": "testing paragraph 3"}
]
}
I suggest the following:
Class:
data = {
"title": "testing title",
"paragraphs": [
{ "paragraph": "testing paragraph 1" },
{ "paragraph": "testing paragraph 2" },
{ "paragraph": "testing paragraph 3" }
]
}
...
addParagraph(){
this.data.paragraphs.push( { "paragraph": "" });
}
delParagraph(paragraphID){
this.data.paragraphs.splice(paragraphID,1);
}
HTML
<ion-row padding *ngFor="let paragraph of data.paragraphs; let i=index">
<ion-col col-11 class="pharagraph margin-bottom">
<ion-textarea rows="10" class="bordered" placeholder="Enter Content Paragraph" [(ngModel)]="paragraph.paragraph"></ion-textarea>
</ion-col>
<ion-col col-1>
<button ion-button clear icon-start icon-right (click)="delParagraph(i)"><ion-icon name="trash" color="danger"></ion-icon></button>
</ion-col>
</ion-row>
<ion-row padding>
<ion-col col-11>
<button ion-button block color="danger" id="addPharagraph" (click)="addParagraph()"><ion-icon name="add-circle"></ion-icon> add pharagraph</button>
</ion-col>
</ion-row>
Demo
Hello I think you wanted to define an array of paragraph instead of string
this.data.title = '';
this.data.paragraph = [{}] instead of '';
And push your paragraphs in this.data.paragraph ;)
this.data.paragraph.push({paragraph: 'My text content'});

Ionic ngElse equal

I want to do a simple if else in Angular template. I'm using Ionic framework. What I want to do is something like
if (val != null){
document.write("No value");
}
else{
document.write("Has value");
}
What I have now is
<ion-grid *ngIf="devices">
<!-- Show if devices exist -->
<ion-row>
<ion-col>
<ion-list>
<ion-item>
device 1
</ion-item>
</ion-list>
</ion-col>
</ion-row>
</ion-grid>
<ion-grid>
<!-- Show if devices DO NOT exist -->
<ion-row>
<ion-col>
<button text-center ion-button round col-6 offset-3> Odśwież urządznia </button>
</ion-col>
</ion-row>
</ion-grid>
I wanted to do something like *ngIf!=null or *ngElse but these two do not work.
So my question is how do I do that?
You have to use in following way -
<div *ngIf="condition; else elseBlock">
Truthy condition
</div>
<ng-template #elseBlock>
False condition
</ng-template>
hope this will help you, let me know in case any issue?

Expand/collapse fields that are generated in an ngFor using a toggle function?

I have a div that repeats using an *ngFor. So there are multiple div's on my page. Within each of these div's, there several more element's that also toggle. So we have collapsible fields within other collapsible fields. Each item allows the parent to collapse all children, but also the children to expand/collapse individually.
The problem is that when multiple item are generated using the *ngFor, the toggle function to expand/collapse the fields applies to all the items on the page. I want the toggle to work for only that specific item.
Here is a snippet of the HTML/AngularJS code:
<div padding>
<div *ngFor="let item of ItemsList">
<div>
<ion-grid>
<ion-row>
<ion-col>
{{item.information}}
</ion-col>
<ion-col>
{{item.information}}
</ion-col>
<ion-col>
{{item.information}}
</ion-col>
<ion-col>
{{item.information}}
</ion-col>
<ion-col>
<a *ngIf="!expandItem" (click)="toggleItem('down')">
<ion-icon class="fa fa-angle-double-down fa-2x"></ion-icon>
</a>
<a *ngIf="expandItem" (click)="toggleItem('up')">
<ion-icon class="fa fa-angle-double-up fa-2x"></ion-icon>
</a>
</ion-col>
</ion-row>
<div>
...
...
...
<ion-col>
<a *ngIf="!expandField1" (click)="toggleField1('down')">
<ion-icon class="fa fa-angle-double-down fa-2x"></ion-icon>
</a>
<a *ngIf="expandField1" (click)="toggleField1('up')">
<ion-icon class="fa fa-angle-double-up fa-2x"></ion-icon>
</a>
</ion-col>
<ion-grid *ngIf ="expandField1 || (expandItem && expandField1)">
<ion-row *ngFor="let subItem of item.subItem">
<ion-col>
{{subItem.name}}
</ion-col>
<ion-col>
{{subItem.name}}
</ion-col>
<ion-col>
{{subItem.name}}
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>
Here is a snippet of the toggle functions
toggleItem(type: any) {
if (type == 'up') {
this.expandItem = false;
this.expandField1 = false;
} else {
this.expandItem = true;
this.expandField1 = true;
}
toggleField1(type: any) {
if (type == 'up') {
this.expandField1 = false;
} else {
this.expandField1 = true;
this.expandItem = true;
}
Any questions please ask.
you will have to use an array of expandItem and expandField1 to track opening and closing of each collapsible. For this you can use $index and then set array for it like expandItem[$index] = true for a particular collabsible on click.

Iterate in a JSON array and style its elements

I am fetching data from a REST API, and I am receive a JSON that has the following format:
[Object]
0:Object
createdAt:"2016-05-04T16:32"
list:Array[4]
0:"Mango"
1:"Apple"
2:"Banana"
3:"Kiwi"
Currently, the following is printed when calling that JSON in the HTML file:
Mango,Apple,Banana,Kiwi
Here is the JS code used to retrieve data from the REST API:
this.http.get('https://example.com/api').subscribe(data => {
this.categories = data.json().results;
});
The current HTML/Angular code:
<div *ngFor="#fruit of categories">
<ion-row>
<ion-col>
<div class="txt">{{fruit.list}}</div>
</ion-col>
</ion-row>
</div>
The final Result of what I want to achieve is the following:
<div>
<ion-row>
<ion-col>
<div class="txt">Mango</div>
</ion-col>
<ion-col>
<div class="txt">Apple</div>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<div class="txt">Banana</div>
</ion-col>
<ion-col>
<div class="txt">Kiwi</div>
</ion-col>
</ion-row>
</div>
Can you please tell me how to achieve that? Do I need to change something on the JSON itself? Or it can be done simply by tweaking the *ngFor?
I would create a new object to gather elements:
this.service.getFruits().subscribe(categories => {
let fruits = categories.list;
let fruitsByGroup = [];
fruits.forEach((fruit, index) => {
let groupIndex = Math.floor(index/2);
if (index%2 === 0) {
fruitsByGroup[groupIndex] = [];
}
fruitsByGroup[groupIndex].push(fruit);
});
this.fruitsByGroup = fruitsByGroup;
});
Then I would iterate this way:
<div *ngFor="#fruitGroup of fruitsByGroup">
<ion-row *ngFor="#fruit of fruitGroup">
<ion-col>
<div class="txt">{{fruit.list}}</div>
</ion-col>
</ion-row>
</div>
You could do something like this using an ng-repeat:
<div>
<ion-row ng-repeat="fruit in categories.list">
<ion-col>
<div class="txt">{{fruit}}</div>
</ion-col>
</ion-row>
</div>
The main complication that will come out of this, is separating them out into different rows. If there aren't too many items you're dealing with, you could try something like this:
<div>
<ion-row ng-repeat="fruit in categories.list.slice(0,1)">
<ion-col>
<div class="txt">{{fruit}}</div>
</ion-col>
</ion-row>
<ion-row ng-repeat="fruit in categories.list.slice(2,3)">
<ion-col>
<div class="txt">{{fruit}}</div>
</ion-col>
</ion-row>
</div>
Does this answer your question?
You can do this using nested ngFor
<div *ngFor="#fruit of categories">
<ion-row>
<ion-col *ngFor="#item of fruit.list">
<div class="txt">
{{item}}
</div>
</ion-col>
</ion-row>
</div>
In you rest calling code
this.http.get('https://example.com/api').subscribe(data => {
this.categories = data.json().results[0].list;
});
In your HTML code
<div *ngFor="#fruit of categories">
<ion-row>
<ion-col>
<div class="txt">{{fruit[0]}}</div>
</ion-col>
</ion-row>
</div>

Categories

Resources